Fabric.js - Move object without holding mouse button

浪子不回头ぞ 提交于 2020-01-04 05:53:53

问题


In Fabric.js an object can be moved in the canvas by left-clicking, holding and moving the mouse. In this condition, the selected object follows the mouse's cursor and object:moving gets fired. Releasing the left mouse button exits this mode.

Is there a way to change this behavior and have an object enter this mode with different events? For example, click once to have the object follow the cursor (and have the object:moving fire correctly) and then click a second time to release the object in it's final position?

I'm hoping to avoid writing this from scratch listening to the "mouse move" event, given that this is already implemented, but just the triggers to enter/exist this mode have to be changed.


回答1:


I implemented this by having a variable called movedObject which is null if no object is moved and contains an object if an object is moved. If you click while an object is being moved then it'll set movedObject to null. If you click while not moving an object then it'll set movedObject to an object if you clicked one.

I added a listener to mouse:move which sets left and top of movedObject to the mouse x and y (minus movedObject width and height / 2) if movedObject is not null.

JSFiddle

Code:

var canvas = new fabric.Canvas('canvas');
canvas.setWidth(300);
canvas.setHeight(300);
var circle = new fabric.Circle({
  radius: 30,
  fill: '#f55',
  top: 100,
  left: 100
});
canvas.add(circle);
circle.hasControls = circle.hasBorders = circle.selectable = false;

var movedObject = null;
canvas.on({
  'mouse:down': function(e) {
    //If an object is selected already it'll be unselected
    if (movedObject !== null) {
        movedObject = null;
    } else {
      //If no object was selected and a click occured on an object it'll now be selected
      if (e.target) {
         movedObject = e.target;
      }
    }
  },
  'mouse:move': function(e) {
    //Moving the object along with mouse cursor
    if (movedObject !== null) {
        movedObject.left = (e.e.clientX - movedObject.width / 2);
        movedObject.top = (e.e.clientY - movedObject.height / 2);
        movedObject.setCoords();
        canvas.renderAll();
    }
  }
});



回答2:


Going through the Fabric.js code, the place where an object is marked to be moved is in canvas.__on_mouse_down(e) which calls canvas._setupCurrentTransform(e, target) (Only place where this method is used). This constructs an object and assigns it to canvas._currentTransform. This object, in turn, is used in canvas.__onMouseMove(e) to actually move the selected object using canvas._transformObject(e).

The problem is that canvas.__onMouseUp(e) calls canvas._finalizeCurrentTransform(), so the dragging stops there. Fortunately it also fires "mouse:up" right after. So we can override this in the callback:

var mydragging = false;
canvas.on('mouse:up', function(o) {
  if (mydragging) {
    mydragging = false;
    canvas.currentTransform = null;
  }
  else {
    canvas._setupCurrentTransform(o.e, o.target);
    mydragging = true;
  }
});

This puts the canvas in the exact same state as when dragging by holding the mouse button down (before introducing this code), therefore all the built-in behavior remains in place, including firing "object:moving".

Unfortunately canvas._currentTransform and canvas._setupCurrentTransform are marked as private and cannot be relied upon. Perhaps they are willing to make it public.



来源:https://stackoverflow.com/questions/34981369/fabric-js-move-object-without-holding-mouse-button

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