Fabricjs pan and zoom

China☆狼群 提交于 2019-11-27 00:30:35

问题


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 start having trouble.

$('#zoomIn').click(function(){
    canvas.setZoom(canvas.getZoom() * 1.1 ) ;
}) ;

$('#zoomOut').click(function(){
    canvas.setZoom(canvas.getZoom() / 1.1 ) ;
}) ;

$('#goRight').click(function(){
    //Need to implement
}) ;

$('#goLeft').click(function(){
    //Need to implement
}) ;

http://jsfiddle.net/hdramos/ux16013L/


回答1:


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/




回答2:


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/




回答3:


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>



回答4:


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>



回答5:


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.



来源:https://stackoverflow.com/questions/30466322/fabricjs-pan-and-zoom

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!