Javascript 如何通过单击任意点选择/拖动来旋转fabricjs中的线?

Javascript 如何通过单击任意点选择/拖动来旋转fabricjs中的线?,javascript,fabricjs,Javascript,Fabricjs,我有一条线,一端固定在一个点上,用户可以旋转或拉伸 JSFIDLE 似乎在Fabjjs中,选择一个线/物体旋转的唯一方法是中间的一个小选择框。此外,直线很窄,因此很难选择。通常,必须在直线上拖动一个矩形选择框来选择它,然后抓取未标记的旋转框 我想将其简化为:单击直线上的任意位置并拖动以旋转 想法 thx 代码段: var canvas = new fabric.Canvas("c", {stateful: true}); var line1 = new fabric.Line([ 100,

我有一条线,一端固定在一个点上,用户可以旋转或拉伸

JSFIDLE

似乎在Fabjjs中,选择一个线/物体旋转的唯一方法是中间的一个小选择框。此外,直线很窄,因此很难选择。通常,必须在直线上拖动一个矩形选择框来选择它,然后抓取未标记的旋转框

我想将其简化为:单击直线上的任意位置并拖动以旋转

想法

thx

代码段:

var canvas = new fabric.Canvas("c", {stateful: true});


var line1 = new fabric.Line([ 100, 200, 330, 200 ], {
      fill: 'red',
      stroke: 'red',
      strokeWidth: 3,
      selectable: true,
      evented: false,
      minScaleLimit: 0.25,
      lockRotation: false,
      centeredRotation: false,
      centeredScaling: false,

      originX: "left",    // origin of rotation/transformation.      
      originY: "bottom",    // origin of rotation/transformation.

      lockMovementX: true,
      lockMovementY: true,
      lockScalingFlip: true,
      lockScalingX: false,
      lockScalingY: false,
      lockSkewingX: false,
      lockSkewingY: false,
      lockUniScaling: true
    });

这里有一种方法可以满足你的需要

我们的想法是,在每个
scale
事件中,我们将使用fabric的内部
fabric.canvas.\u rotateObject()
,为它提供当前指针的位置来旋转行。然后,立即调整线的长度以匹配刻度,并将线的刻度重置为1

可能就是这样,但尽管您的示例相对简单(直线是水平的),但如果您想初始化对角线,则要复杂得多。想象一条线,坐标为
[0,0,100,100]
。这将渲染一个矩形100x100边界框。你可以旋转线,但是巨大的边界框显然不是你想要的

因此,我们需要初始化直线,就像它被旋转回水平位置一样,然后设置它应该具有的角度。为此,我们扩展了内置的
fabric.Line
类,并修改构造函数进行计算。而且,由于我们已经有了新的类,我们还将向其中添加
scale
处理程序和默认选项。构造函数签名保持不变-
新结构。旋转线([x1,y1,x2,y2],选项)
,其中
x1,y1
-固定点,
x2,y2
-可拖动尖端

最后,我们正在改变一些属性。例如,
evented:false
是您无法在单击时选择行的原因

下面是带有更多注释的代码段,以防万一

const canvas=new fabric.canvas(“c”,{stateful:true})
fabric.RotatingLine=fabric.util.createClass(fabric.Line{
minLength:50,//我们现在需要在px中设置这个东西
初始化:功能(点、选项){
常数a=新结构点(点[0],点[1])
常数b=新结构点(点[2],点[3])
//找到这条线的向量
常数向量b=b减去(a)
//求直线向量和x轴之间的角度
设angelrad=Math.atan2(vectorB.y,vectorB.x)
如果(角度小于0){
angleRad=2*Math.PI+angleRad
}
const angleDeg=织物使用弧度(angleRad)
//通过向后旋转尖端找到初始水平位置
常数c=fabric.util.rotatePoint(b.clone(),a,-angleRad)
选项=选项| |{}
//最后,使用变换点进行初始化以生成一条水平线
this.callSuper('initialize',[a.x,a.y,c.x,c.y]{
noScaleCache:false,//false在缩放时强制缓存更新(否则不会重新绘制部分行)
是的,
evented:true,//true,因为您要在单击时选择行
//minScaleLimit:0.25,//现在无效,因为我们正在对每个缩放事件重置缩放
锁旋转:错误,
hasRotatingPoint:false,//禁用旋转控制
中心旋转:错误,
centeredScaling:错误,
原点:“左”//旋转/变换原点。
原点:“底部”//旋转/变换原点。
lockMovementX:对,
洛克·莫文蒂:没错,
lockScalingFlip:对,
lockScalingX:错误,
lockScalingY:错,
lockSkewingX:错误,
lockSkewingY:错,
lockUniScaling:没错,
…选项,
angle:angleDeg//请注意,无论发生什么情况,我们都使用计算出的角度
})
此项为.setControlsVisibility({
tr:错,
tl:错,
基本法:错,,
mt:false,//中间顶部禁用
mb:false,//中间底部
ml:false,//左中
先生:错,//我想你明白了
})
此。on('scaling',函数(e){
//旋转到指针的x,y
这个.canvas.\u旋转对象(e.pointer.x,e.pointer.y)
//当_rotateObject()尝试将左/顶保持在初始值时,
//有时由于舍入误差(?)而失败
//所以我们需要再次手动操作
this.set({left:this.x1,top:this.y1})
//在重置刻度之前计算新长度
常量xOffset=(this.x2-this.x1)*this.scaleX
const newLength=Math.max(this.minLength,xOffset)
//重置scaleX/scaleY并为尖端点设置新的x坐标
这台({
scaleX:1,
斯卡利:1,
x2:this.x1+newLength
})
})
}
})
const line1=新织物旋转线([200200330200]{
填充:“红色”,
笔划:“红色”,
冲程宽度:3,
});
const line2=新织物旋转线([200200100100]{
填充:“蓝色”,
笔划:“蓝色”,
冲程宽度:3,
});
canvas.add(第1行,第2行)
//禁用组选择。
canvas.on('selection:created',(e)=>{
如果(e.target.type==='activeSelection'){
canvas.discardActiveObject();
}否则{
//无所事事
}
})
//将对象保留在画布中。撤消画布外的移动/旋转/缩放。
canvas.on('object:modified',函数(选项){
设obj=options.target;
设boundingRect=obj.getBoundingRect(true);
如果(boundingRect.left<0
||boundingRect.top<0
||boundingRect.left+boundingRect.width>canvas.getWidth()
||boundingRect.top+boundingRect.height>canvas.getHeight(){
obj.top=obj.\u stateProperties.top;
obj.left=obj.\u stateProperties.left;
obj.angle=obj.\u stateProperties.angle;
obj.scaleX=obj.\u stateProperties.scaleX;
obj.scaleY=obj.\u stateproperty