gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-30 06:20:35 27 4
gpt4 key购买 nike

我有一条线,一端位于固定点,用户可以旋转或拉伸(stretch)它。

jsfiddle here

似乎在 fabricJS 中选择要旋转的线/对象的唯一方法是中间的小选择框。另外,一条线很窄,所以很难选择。通常,必须将一个矩形选择框拖过直线以将其选中,然后捕获未标记的旋转框。

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

想法?

谢谢。

代码片段:

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._rotateObject() 旋转线条,为其提供当前指针位置。然后,立即调整线的长度以匹配比例并将线的比例重置为 1。

就是这样,但是虽然您的示例相对容易实现(线是水平的),但如果您想初始化对 Angular 线,它会变得更加棘手。想象一条以 [0, 0, 100, 100] 作为坐标的线。这将呈现一个矩形 100x100 边界框。您可以旋转线条,但巨大的边界框显然不是您想要的。

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

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

以下是带有更多评论的代码段,以防万一。

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

fabric.RotatingLine = fabric.util.createClass(fabric.Line, {
minLength: 50, // we need to set this thing in px now

initialize: function (points, options) {
const a = new fabric.Point(points[0], points[1])
const b = new fabric.Point(points[2], points[3])
// find this line's vector
const vectorB = b.subtract(a)
// find angle between line's vector and x axis
let angleRad = Math.atan2(vectorB.y, vectorB.x)
if (angleRad < 0) {
angleRad = 2 * Math.PI + angleRad
}
const angleDeg = fabric.util.radiansToDegrees(angleRad)
// find initial horizontal position by rotating the tip back
const c = fabric.util.rotatePoint(b.clone(), a, -angleRad)
options = options || {}
// finally, initialize using transform points to make a horizontal line
this.callSuper('initialize', [a.x, a.y, c.x, c.y], {
noScaleCache: false, // false to force cache update while scaling (doesn't redraw parts of line otherwise)
selectable: true,
evented: true, // true because you want to select line on click
//minScaleLimit: 0.25, // has no effect now because we're resetting scale on each scale event
lockRotation: false,
hasRotatingPoint: false, // to disable rotation control
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,
...options,
angle: angleDeg // note that we use the calculated angle no matter what
})

this.setControlsVisibility({
tr: false,
tl: false,
bl: false,
mt: false, // middle top disable
mb: false, // midle bottom
ml: false, // middle left
mr: false, // I think you get it
})

this.on('scaling', function (e) {
// rotate to the pointer's x,y
this.canvas._rotateObject(e.pointer.x, e.pointer.y)
// while _rotateObject() tries to keep left/top at initial value,
// it sometimes fails because of rounding errors (?)
// so we need to do it manually again
this.set({left: this.x1, top: this.y1})
// calculate new length before resetting scale
const xOffset = (this.x2 - this.x1) * this.scaleX
const newLength = Math.max(this.minLength, xOffset)
// reset scaleX/scaleY and set new x coord for the tip point
this.set({
scaleX: 1,
scaleY: 1,
x2: this.x1 + newLength
})
})
}
})


const line1 = new fabric.RotatingLine([ 200, 200, 330, 200 ], {
fill: 'red',
stroke: 'red',
strokeWidth: 3,
});

const line2 = new fabric.RotatingLine([ 200, 200, 100, 100 ], {
fill: 'blue',
stroke: 'blue',
strokeWidth: 3,
});

canvas.add(line1, line2)

// Disables group selection.
canvas.on('selection:created', (e) => {
if(e.target.type === 'activeSelection') {
canvas.discardActiveObject();
} else {
//do nothing
}
})

// Keeps objects inside canvas. undos move/rotate/scale out of canvas.
canvas.on('object:modified', function (options) {
let obj = options.target;
let boundingRect = obj.getBoundingRect(true);
if (boundingRect.left < 0
|| boundingRect.top < 0
|| boundingRect.left + boundingRect.width > canvas.getWidth()
|| boundingRect.top + boundingRect.height > canvas.getHeight()) {
obj.top = obj._stateProperties.top;
obj.left = obj._stateProperties.left;
obj.angle = obj._stateProperties.angle;
obj.scaleX = obj._stateProperties.scaleX;
obj.scaleY = obj._stateProperties.scaleY;
obj.setCoords();
obj.saveState();
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/2.4.3/fabric.min.js"></script>
<canvas id='c' width="500" height="400"></canvas>

关于javascript - 如何通过单击任意点选择/拖动来旋转 fabricjs 中的线?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53379861/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com