Fabricjs pan and zoom

前端 未结 5 985
陌清茗
陌清茗 2020-12-08 01:40

How can I pan and zoom using fabricjs? I\'ve tried using the methods zoomToPoint and setZoom but they do not work for panning. Once I start using different zoom points I sta

相关标签:
5条回答
  • 2020-12-08 01:58

    Solved it using:

    relativePan() absolutePan()

    [Update]

    $('#goRight').click(function(){
        var units = 10 ;
        var delta = new fabric.Point(units,0) ;
        canvas.relativePan(delta) ;
    }) ;
    
    $('#goLeft').click(function(){
        var units = 10 ;
        var delta = new fabric.Point(-units,0) ;
        canvas.relativePan(delta) ;
    }) ;
    $('#goUp').click(function(){
        var units = 10 ;
        var delta = new fabric.Point(0,-units) ;
        canvas.relativePan(delta) ;
    }) ;
    
    $('#goDown').click(function(){
        var units = 10 ;
        var delta = new fabric.Point(0,units) ;
        canvas.relativePan(delta) ;
    });
    

    http://jsfiddle.net/ux16013L/2/

    0 讨论(0)
  • 2020-12-08 02:05

    I know it is already answered, but I had to do a mouse panning, so I adapted the fiddle of the accepted answer to do so. I post it here for anyone who has to do something like this. This is just the main idea:

    var panning = false;
    canvas.on('mouse:up', function (e) {
        panning = false;
    });
    
    canvas.on('mouse:down', function (e) {
        panning = true;
    });
    canvas.on('mouse:move', function (e) {
        if (panning && e && e.e) {
            var units = 10;
            var delta = new fabric.Point(e.e.movementX, e.e.movementY);
            canvas.relativePan(delta);
        }
    });
    

    Here is the fiddle: http://jsfiddle.net/gncabrera/hkee5L6d/5/

    0 讨论(0)
  • 2020-12-08 02:05

    I have an example on Github using fabric.js Canvas panning and zooming: https://sabatinomasala.github.io/fabric-clipping-demo/

    The code responsible for the panning behaviour is the following: https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js

    It's a simple extension on the fabric.Canvas.prototype, which enables you to toggle 'drag mode' on the canvas as follows:

    canvas.toggleDragMode(true); // Start panning
    canvas.toggleDragMode(false); // Stop panning
    

    Take a look at the following snippet, documentation is available throughout the code.

    const STATE_IDLE = 'idle';
    const STATE_PANNING = 'panning';
    fabric.Canvas.prototype.toggleDragMode = function(dragMode) {
      // Remember the previous X and Y coordinates for delta calculations
      let lastClientX;
      let lastClientY;
      // Keep track of the state
      let state = STATE_IDLE;
      // We're entering dragmode
      if (dragMode) {
        // Discard any active object
        this.discardActiveObject();
        // Set the cursor to 'move'
        this.defaultCursor = 'move';
        // Loop over all objects and disable events / selectable. We remember its value in a temp variable stored on each object
        this.forEachObject(function(object) {
          object.prevEvented = object.evented;
          object.prevSelectable = object.selectable;
          object.evented = false;
          object.selectable = false;
        });
        // Remove selection ability on the canvas
        this.selection = false;
        // When MouseUp fires, we set the state to idle
        this.on('mouse:up', function(e) {
          state = STATE_IDLE;
        });
        // When MouseDown fires, we set the state to panning
        this.on('mouse:down', (e) => {
          state = STATE_PANNING;
          lastClientX = e.e.clientX;
          lastClientY = e.e.clientY;
        });
        // When the mouse moves, and we're panning (mouse down), we continue
        this.on('mouse:move', (e) => {
          if (state === STATE_PANNING && e && e.e) {
            // let delta = new fabric.Point(e.e.movementX, e.e.movementY); // No Safari support for movementX and movementY
            // For cross-browser compatibility, I had to manually keep track of the delta
    
            // Calculate deltas
            let deltaX = 0;
            let deltaY = 0;
            if (lastClientX) {
              deltaX = e.e.clientX - lastClientX;
            }
            if (lastClientY) {
              deltaY = e.e.clientY - lastClientY;
            }
            // Update the last X and Y values
            lastClientX = e.e.clientX;
            lastClientY = e.e.clientY;
    
            let delta = new fabric.Point(deltaX, deltaY);
            this.relativePan(delta);
            this.trigger('moved');
          }
        });
      } else {
        // When we exit dragmode, we restore the previous values on all objects
        this.forEachObject(function(object) {
          object.evented = (object.prevEvented !== undefined) ? object.prevEvented : object.evented;
          object.selectable = (object.prevSelectable !== undefined) ? object.prevSelectable : object.selectable;
        });
        // Reset the cursor
        this.defaultCursor = 'default';
        // Remove the event listeners
        this.off('mouse:up');
        this.off('mouse:down');
        this.off('mouse:move');
        // Restore selection ability on the canvas
        this.selection = true;
      }
    };
    
    // Create the canvas
    
    let canvas = new fabric.Canvas('fabric')
    canvas.backgroundColor = '#f1f1f1';
    
    // Add a couple of rects
    
    let rect = new fabric.Rect({
      width: 100,
      height: 100,
      fill: '#f00'
    });
    canvas.add(rect)
    
    rect = new fabric.Rect({
      width: 200,
      height: 200,
      top: 200,
      left: 200,
      fill: '#f00'
    });
    canvas.add(rect)
    
    // Handle dragmode change
    
    let dragMode = false;
    $('#dragmode').change(_ => {
      dragMode = !dragMode;
      canvas.toggleDragMode(dragMode);
    });
    <div>
      <label for="dragmode">
        Enable panning
        <input type="checkbox" id="dragmode" name="dragmode" />
      </label>
    </div>
    <canvas width="300" height="300" id="fabric"></canvas>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/1.7.15/fabric.min.js"></script>

    0 讨论(0)
  • 2020-12-08 02:09

    Here is my solution for canvas zoom (using mouse wheel) and pan (using left/up/right /down keys or shift key + mouse left down + mouse move).

    https://jsfiddle.net/milanhlinak/7s4w0uLy/8/

    <!DOCTYPE html>
    <html>
    
    <head>
        <script type="text/javascript" src="lib/jquery-3.1.1.min.js"></script>
        <script type="text/javascript" src="lib/fabric.min.js"></script>
    </head>
    
    <body>
    
        <canvas id="canvas" style="border: 1px solid #cccccc"></canvas>
    
        <script>
            var Direction = {
                LEFT: 0,
                UP: 1,
                RIGHT: 2,
                DOWN: 3
            };
    
            var zoomLevel = 0;
            var zoomLevelMin = 0;
            var zoomLevelMax = 3;
    
            var shiftKeyDown = false;
            var mouseDownPoint = null;
    
            var canvas = new fabric.Canvas('canvas', {
                width: 500,
                height: 500,
                selectionKey: 'ctrlKey'
            });
    
            canvas.add(new fabric.Rect({
                left: 100,
                top: 100,
                width: 50,
                height: 50,
                fill: '#faa'
    
            }));
            canvas.add(new fabric.Rect({
                left: 300,
                top: 300,
                width: 50,
                height: 50,
                fill: '#afa'
            }));
    
            canvas.on('mouse:down', function (options) {
                var pointer = canvas.getPointer(options.e, true);
                mouseDownPoint = new fabric.Point(pointer.x, pointer.y);
            });
            canvas.on('mouse:up', function (options) {
                mouseDownPoint = null;
            });
            canvas.on('mouse:move', function (options) {
                if (shiftKeyDown && mouseDownPoint) {
                    var pointer = canvas.getPointer(options.e, true);
                    var mouseMovePoint = new fabric.Point(pointer.x, pointer.y);
                    canvas.relativePan(mouseMovePoint.subtract(mouseDownPoint));
                    mouseDownPoint = mouseMovePoint;
                    keepPositionInBounds(canvas);
                }
            });
            fabric.util.addListener(document.body, 'keydown', function (options) {
                if (options.repeat) {
                    return;
                }
                var key = options.which || options.keyCode; // key detection
                if (key == 16) { // handle Shift key
                    canvas.defaultCursor = 'move';
                    canvas.selection = false;
                    shiftKeyDown = true;
                } else if (key === 37) { // handle Left key
                    move(Direction.LEFT);
                } else if (key === 38) { // handle Up key
                    move(Direction.UP);
                } else if (key === 39) { // handle Right key
                    move(Direction.RIGHT);
                } else if (key === 40) { // handle Down key
                    move(Direction.DOWN);
                }
            });
            fabric.util.addListener(document.body, 'keyup', function (options) {
                var key = options.which || options.keyCode; // key detection
                if (key == 16) { // handle Shift key
                    canvas.defaultCursor = 'default';
                    canvas.selection = true;
                    shiftKeyDown = false;
                }
            });
            jQuery('.canvas-container').on('mousewheel', function (options) {
                var delta = options.originalEvent.wheelDelta;
                if (delta != 0) {
                    var pointer = canvas.getPointer(options.e, true);
                    var point = new fabric.Point(pointer.x, pointer.y);
                    if (delta > 0) {
                        zoomIn(point);
                    } else if (delta < 0) {
                        zoomOut(point);
                    }
                }
            });
    
            function move(direction) {
                switch (direction) {
                case Direction.LEFT:
                    canvas.relativePan(new fabric.Point(-10 * canvas.getZoom(), 0));
                    break;
                case Direction.UP:
                    canvas.relativePan(new fabric.Point(0, -10 * canvas.getZoom()));
                    break;
                case Direction.RIGHT:
                    canvas.relativePan(new fabric.Point(10 * canvas.getZoom(), 0));
                    break;
                case Direction.DOWN:
                    canvas.relativePan(new fabric.Point(0, 10 * canvas.getZoom()));
                    break;
                }
                keepPositionInBounds(canvas);
            }
    
    
            function zoomIn(point) {
                if (zoomLevel < zoomLevelMax) {
                    zoomLevel++;
                    canvas.zoomToPoint(point, Math.pow(2, zoomLevel));
                    keepPositionInBounds(canvas);
                }
            }
    
            function zoomOut(point) {
                if (zoomLevel > zoomLevelMin) {
                    zoomLevel--;
                    canvas.zoomToPoint(point, Math.pow(2, zoomLevel));
                    keepPositionInBounds(canvas);
                }
            }
    
            function keepPositionInBounds() {
                var zoom = canvas.getZoom();
                var xMin = (2 - zoom) * canvas.getWidth() / 2;
                var xMax = zoom * canvas.getWidth() / 2;
                var yMin = (2 - zoom) * canvas.getHeight() / 2;
                var yMax = zoom * canvas.getHeight() / 2;
    
                var point = new fabric.Point(canvas.getWidth() / 2, canvas.getHeight() / 2);
                var center = fabric.util.transformPoint(point, canvas.viewportTransform);
    
                var clampedCenterX = clamp(center.x, xMin, xMax);
                var clampedCenterY = clamp(center.y, yMin, yMax);
    
                var diffX = clampedCenterX - center.x;
                var diffY = clampedCenterY - center.y;
    
                if (diffX != 0 || diffY != 0) {
                    canvas.relativePan(new fabric.Point(diffX, diffY));
                }
            }
    
            function clamp(value, min, max) {
                return Math.max(min, Math.min(value, max));
            }
        </script>
    
    </body>
    
    </html>
    
    0 讨论(0)
  • 2020-12-08 02:10

    If you just want to pan the canvas in the display, and not to change the position of the elements, you can use this solution.

    The idea is to have a fixed size container with css of overflow: hidden that has an expended canvas inside it. the pan will move the canvas inside the container so the user will see different areas of the expended canvas every time.

    0 讨论(0)
提交回复
热议问题