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