gpt4 book ai didi

javascript - 将一个旋转对象包含在另一个旋转对象中 FabricJS

转载 作者:行者123 更新时间:2023-11-28 03:03:01 25 4
gpt4 key购买 nike

我有两个对象,一个父对象(红色)和一个子对象(蓝色)。 父对象是固定的,不能移动,只有子对象是可移动的,并且子对象总是比父对象大。无论以何种方式移动子对象,它都应该始终包含在子对象内部,这意味着我们永远不应该看到红色矩形。

enter image description here

演示:https://codesandbox.io/s/force-contain-of-object-inside-another-object-fabric-js-7nt7q

我知道有一些解决方案可以将对象包含在 Canvas 或其他对象边界内(例如 Move object within canvas boundary limit ),这主要强制顶部/右侧/底部/左侧值不超过父值,但这里我们有 < strong>两个物体旋转相同 Angular 情况。

当用户将照片上传到框架容器时,我有一个现实场景。照片通常总是比相框容器大。用户可以在相框内移动照片,但不应允许他创建任何空白空间,照片应始终包含在相框内。

最佳答案

我会使用纯 Canvas (没有fabricjs),从头开始,这样你就可以很好地理解你面临的问题,然后如果你需要它,相同的逻辑应该很容易移植到任何图书馆。

你有一些规则:

  • 父对象是固定的,无法移动,
  • 子对象是可移动的。
  • child 总是比 parent 大。
  • 子对象始终受到父对象的约束。

所以我的想法是获取所有四个 Angular ,这样在移动时我们可以使用这些坐标来确定它是否可以移动到新位置,代码应该很容易理解,但是询问你是否有任何疑虑。

我正在使用光线转换算法:
https://github.com/substack/point-in-polygon/blob/master/index.js
这样,我们需要做的就是检查子项的 Angular 是否不在父项的内部,并且父项是否在子项的内部,仅此而已。

我不是 FabricJS 方面的专家,所以我最好的可能也不是很多......
但下面是我尝试让你的代码运行的尝试。

<canvas id="canvas" width="500" height="350"></canvas>

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>
<script>
var canvas = new fabric.Canvas("canvas");
canvas.stateful = true;

function getCoords(rect) {
var x = rect.left;
var y = rect.top;
var angle = (rect.angle * Math.PI) / 180;

var coords = [{ x, y }];
x += rect.width * Math.cos(angle);
y += rect.width * Math.sin(angle);
coords.push({ x, y });

angle += Math.PI / 2;
x += rect.height * Math.cos(angle);
y += rect.height * Math.sin(angle);
coords.push({ x, y });

angle += Math.PI / 2;
x += rect.width * Math.cos(angle);
y += rect.width * Math.sin(angle);
coords.push({ x, y });
return coords;
}

function inside(p, vs) {
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i].x, yi = vs[i].y;
var xj = vs[j].x, yj = vs[j].y;
var intersect =
yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}

var parent = new fabric.Rect({
width: 150, height: 100, left: 200, top: 50, angle: 25, selectable: false, fill: "red"
});
var pCoords = getCoords(parent);

var child = new fabric.Rect({
width: 250, height: 175, left: 180, top: 10, angle: 25, hasControls: false, fill: "rgba(0,0,255,0.9)"
});

canvas.add(parent);
canvas.add(child);

canvas.on("object:moving", function (e) {
var cCoords = getCoords(e.target);
var inBounds = true;
cCoords.forEach(c => { if (inside(c, pCoords)) inBounds = false; });
pCoords.forEach(c => { if (!inside(c, cCoords)) inBounds = false; });
if (inBounds) {
e.target.setCoords();
e.target.saveState();
e.target.set("fill", "rgba(0,0,255,0.9)");
} else {
e.target.set("fill", "black");
e.target.animate({
left: e.target._stateProperties.left,
top: e.target._stateProperties.top
},{
duration: 500,
onChange: canvas.renderAll.bind(canvas),
easing: fabric.util.ease["easeInBounce"],
onComplete: function() {
e.target.set("fill", "rgba(0,0,255,0.9)");
}
});
}
});
</script>

该代码也在沙箱上:
https://codesandbox.io/s/force-contain-of-object-inside-another-object-fabric-js-dnvb5

不必担心对所有点击/按住/拖动结构进行编码,这确实很好,这使得这变得非常容易......

我正在尝试 FabricJS, Canvas 有一个很好的属性
(canvas.stateful = true;)
这使我们能够跟踪我们去过的地方,如果我们超出界限,我们可以恢复该运动,同时还可以使用动画向用户提供不允许该运动的视觉反馈。

这是另一个没有动画的版本:

<canvas id="canvas" width="500" height="350"></canvas>

<script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.6.2/fabric.min.js"></script>
<script>
var canvas = new fabric.Canvas("canvas");
canvas.stateful = true;

function getCoords(rect) {
var x = rect.left;
var y = rect.top;
var angle = (rect.angle * Math.PI) / 180;

var coords = [{ x, y }];
x += rect.width * Math.cos(angle);
y += rect.width * Math.sin(angle);
coords.push({ x, y });

angle += Math.PI / 2;
x += rect.height * Math.cos(angle);
y += rect.height * Math.sin(angle);
coords.push({ x, y });

angle += Math.PI / 2;
x += rect.width * Math.cos(angle);
y += rect.width * Math.sin(angle);
coords.push({ x, y });
return coords;
}

function inside(p, vs) {
var inside = false;
for (var i = 0, j = vs.length - 1; i < vs.length; j = i++) {
var xi = vs[i].x, yi = vs[i].y;
var xj = vs[j].x, yj = vs[j].y;
var intersect =
yi > p.y !== yj > p.y && p.x < ((xj - xi) * (p.y - yi)) / (yj - yi) + xi;
if (intersect) inside = !inside;
}
return inside;
}

var parent = new fabric.Rect({
width: 150, height: 100, left: 200, top: 50, angle: 25, selectable: false, fill: "red"
});
var pCoords = getCoords(parent);

var child = new fabric.Rect({
width: 250, height: 175, left: 180, top: 10, angle: 25, hasControls: false, fill: "rgba(0,0,255,0.9)"
});

canvas.add(parent);
canvas.add(child);

canvas.on("object:moving", function (e) {
var cCoords = getCoords(e.target);
var inBounds = true;
cCoords.forEach(c => { if (inside(c, pCoords)) inBounds = false; });
pCoords.forEach(c => { if (!inside(c, cCoords)) inBounds = false; });
if (inBounds) {
e.target.setCoords();
e.target.saveState();
} else {
e.target.left = e.target._stateProperties.left;
e.target.top = e.target._stateProperties.top;
}
});
</script>

<小时/>

该算法也为其他形状打开了大门,这是一个六边形版本:
https://raw.githack.com/heldersepu/hs-scripts/master/HTML/canvas_contained2.html

关于javascript - 将一个旋转对象包含在另一个旋转对象中 FabricJS,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60822474/

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