Rotation and Scaling controls are off after using setAngle() in Fabric.js

拟墨画扇 提交于 2020-01-21 18:54:19

问题


I want to let users rotate objects on the Fabric.js powered canvas, but limit their rotation to 90 deg increments. Idea is that as they rotate and then stop, the object would "snap" into place at the closest angle.

This works okay by listening to "object:rotating", setting the closest angle, then calling object.setAngle(angleClosestTo90). However, once the object has been "snapped", the controls for scaling/rotating the image are off. You can still select them, but it's finicky - I guess the object is expected to be at it's last location, not the one recalculated via setAngle().

This JSFiddle demonstrates the issue:

var canvas = new fabric.Canvas("c");

var rect = new fabric.Rect({
  left: 100,
  top: 100,
  fill: 'red',
  width: 90,
  height: 90
});

canvas.add(rect);
canvas.renderAll();

var lastClosestAngle = 0,
    snapAfterRotate = false;

function calculateClosestAngle(targetObj) {
  // if angle > 360 then mod 360
  var currentAngle = targetObj.angle;
  var normalizedAngle = Math.abs(Math.round(Math.asin(Math.sin(currentAngle * Math.PI/360.0)) * 360.0/Math.PI));
  console.log("normalized: ", normalizedAngle);
  snapAfterRotate = true;
  if (normalizedAngle >= 45 && normalizedAngle < 135) {
    return 90;
  } else if (normalizedAngle >= 135 && normalizedAngle < 225) {
    return 180;
  } else if (normalizedAngle >= 225 && normalizedAngle < 315) {
    return 270;
  } else if ((normalizedAngle >= 315 && normalizedAngle <= 360) || (normalizedAngle >= 0 && normalizedAngle < 45)) {
    return 0;
  }
  return currentAngle;
}

canvas.on("object:rotating", function(rotEvtData) {
  var targetObj = rotEvtData.target;
  lastClosestAngle = calculateClosestAngle(targetObj);
});

canvas.on("object:modified", function(modEvtData) {
  // modified fires after object has been rotated 
  var modifiedObj = modEvtData.target;
  if (modifiedObj.angle && snapAfterRotate) {
      modifiedObj.setAngle(lastClosestAngle);
      snapAfterRotate = false;
      canvas.renderAll();
  }
})

Rotate the box, then let go of the mouse. The object will be selected, but try to rotate it again. The pointer is hard to find/unavailable.

If you click away from the object, then reselect (or just move the object after rotating), it is fine.


回答1:


Run setCoords() after setAngle(). This will update the position of the controls. Tried it in your fiddle. Works fine.

   canvas.on("object:modified", function(modEvtData) {
     // modified fires after object has been rotated 
     var modifiedObj = modEvtData.target;
     if (modifiedObj.angle && snapAfterRotate) {
         modifiedObj.setAngle(lastClosestAngle).setCoords();
         snapAfterRotate = false;
         canvas.renderAll();
     }
   })

regards, Benick




回答2:


FabricJS now supports this natively through 'setAngle', along with 'snapThreshold' property.

https://github.com/kangax/fabric.js/pull/3383

Example:

canvas.add(new fabric.Circle({
  snapAngle: 90,
  snapThreshold: 45,
  left: 100, 
  top: 100, 
  radius:50,
  fill: '#9f9', 
  centeredRotation: true
}));

https://jsfiddle.net/2t2d1zj9/1/



来源:https://stackoverflow.com/questions/23230348/rotation-and-scaling-controls-are-off-after-using-setangle-in-fabric-js

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