如何使用Fabric.js实现画布平移

DP_*_*DP_ 18 javascript canvas panning fabricjs

我有一个Fabric.js画布,我想实现软件包通常使用"手动"工具进行的全画布平移.当您按下其中一个鼠标按钮,然后在按住鼠标按钮的同时在画布上移动,并且画布的可见部分会相应地更改.

您可以在此视频中看到我想要实现的目标.

为了实现这个功能,我编写了以下代码:

$(canvas.wrapperEl).on('mousemove', function(evt) {
    if (evt.button == 2) { // 2 is the right mouse button
        canvas.absolutePan({
            x: evt.clientX,
            y: evt.clientY
        });
    }
});
Run Code Online (Sandbox Code Playgroud)

但它不起作用.你可以在这个视频中看到会发生什么.

如何按顺序修改代码:

  1. 如果像第一个视频一样平移工作?

  2. 对于事件处理程序来消耗事件?当用户按下或释放鼠标右键时,它应该阻止上下文菜单出现.

Mic*_*zlo 14

平移Fabric画布以响应鼠标移动的简单方法是计算鼠标事件之间的光标位移并将其传递给relativePan.

观察我们如何使用前一个鼠标事件的screenXscreenY属性来计算当前鼠标事件的相对位置:

function startPan(event) {
  if (event.button != 2) {
    return;
  }
  var x0 = event.screenX,
      y0 = event.screenY;
  function continuePan(event) {
    var x = event.screenX,
        y = event.screenY;
    fc.relativePan({ x: x - x0, y: y - y0 });
    x0 = x;
    y0 = y;
  }
  function stopPan(event) {
    $(window).off('mousemove', continuePan);
    $(window).off('mouseup', stopPan);
  };
  $(window).mousemove(continuePan);
  $(window).mouseup(stopPan);
  $(window).contextmenu(cancelMenu);
};
function cancelMenu() {
  $(window).off('contextmenu', cancelMenu);
  return false;
}
$(canvasWrapper).mousedown(startPan);
Run Code Online (Sandbox Code Playgroud)

我们开始进行平移mousedown并继续进行平移mousemove.在mouseup,我们取消平移; 我们也取消了mouseup-cancelling函数本身.

右键单击菜单(也称为上下文菜单)将通过返回取消false.菜单取消功能也会取消.因此,如果随后在画布包装器外单击,则上下文菜单将起作用.

这是一个展示这种方法的页面:

http://michaellaszlo.com/so/fabric-pan/

您将在Fabric画布上看到三个图像(可能需要一两个时间才能加载图像).您将能够使用标准Fabric功能.您可以左键单击图像以移动它们,拉伸它们并旋转它们.但是,当您在画布容器中右键单击时,可以使用鼠标平移整个Fabric画布.


Sab*_*ino 6

我在 Github 上有一个使用 Fabric.js Canvas 平移的示例: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
Run Code Online (Sandbox Code Playgroud)

看一下下面的代码片段,整个代码中都提供了文档。

canvas.toggleDragMode(true); // Start panning
canvas.toggleDragMode(false); // Stop panning
Run Code Online (Sandbox Code Playgroud)
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);
});
Run Code Online (Sandbox Code Playgroud)