Fabricjs 平移和缩放

Posted

技术标签:

【中文标题】Fabricjs 平移和缩放【英文标题】:Fabricjs pan and zoom 【发布时间】:2015-08-08 14:04:10 【问题描述】:

如何使用 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/

【问题讨论】:

你能详细说明一下吗?我在什么方面进行调整? 【参考方案1】:

使用以下方法解决:

相对平移() 绝对平移()

[更新]

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

【讨论】:

您能提供一些示例代码并更新您的 JSFiddle 吗?谢谢! 请我尝试做同样的事情! 请参阅更新。这就是我所拥有的。 假设如果您放大并向左或向右移动等然后缩小,那么您将以某个不是初始位置的位置结束!可以重置到初始位置吗?? 如何重置为实际画布?【参考方案2】:

我知道它已经被回答了,但我不得不做一个鼠标平移,所以我调整了接受答案的小提琴来这样做。我把它贴在这里给任何必须做这样的事情的人。这只是主要思想:

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

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

【讨论】:

这似乎在 IE 中不起作用。从外观上看,e.e.movementX 和 e.e.movementY 在fabric.js 的IE 版本中不存在。快速环顾四周,发现***.com/questions/40355425/…【参考方案3】:

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

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】:

我在 Github 上有一个使用 fabric.js 画布平移和缩放的示例:https://sabatinomasala.github.io/fabric-clipping-demo/

负责平移行为的代码如下:https://github.com/SabatinoMasala/fabric-clipping-demo/blob/master/src/classes/Panning.js

这是fabric.Canvas.prototype 上的一个简单扩展,可让您在画布上切换“拖动模式”,如下所示:

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

看看下面的 sn-p,整个代码都有文档。

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   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】:

如果你只想在显示中平移画布,而不是改变元素的位置, 你可以使用this solution。

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

【讨论】:

以上是关于Fabricjs 平移和缩放的主要内容,如果未能解决你的问题,请参考以下文章

canvas - 使用fabricjs和angularjs进行捏缩放

fabricjs:缩放后如何显示对象大小

如何修复 FabricJS 中 Inkscape SVG 的缩放和旋转?

FabricJS 缩放图像以适应宽度/大小

Fabricjs 之后的线坐标(移动、缩放、旋转) - canvas.on('object:modified'...

Fabricjs - 在画布边界内缩放画布背景以“包含”