javascript Fabricjs 平移和缩放

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30466322/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 12:14:06  来源:igfitidea点击:

Fabricjs pan and zoom

javascriptcanvasfabricjs

提问by d0001

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.

如何使用fabricjs进行平移和缩放?我试过使用 zoomToPoint 和 setZoom 方法,但它们不适用于平移。一旦我开始使用不同的缩放点,我就开始遇到麻烦。

$('#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/

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

回答by d0001

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/

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

回答by gncabrera

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/

这是小提琴:http: //jsfiddle.net/gncabrera/hkee5L6d/5/

回答by Milan Hlinák

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).

这是我的画布缩放(使用鼠标滚轮)和平移(使用左/上/右/下键或 shift 键 + 鼠标左下 + 鼠标移动)的解决方案。

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

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>

回答by Sabatino

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

我在 Github 上有一个使用 fabric.js 画布平移和缩放的示例: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

负责平移行为的代码如下: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:

这是 上的一个简单扩展fabric.Canvas.prototype,它使您可以按如下方式在画布上切换“拖动模式”:

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>

回答by Dudi

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: hiddenthat 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.

这个想法是有一个固定大小的容器,其中的 cssoverflow: hidden里面有一个扩展的画布。平底锅将在容器内移动画布,因此用户每次都会看到扩展画布的不同区域。