问题描述
所以我要用KonvaJS和KonvaReact构建一个UML绘图工具,为此我需要用线连接形状.我在网站上的已连接对象 https://konvajs.org/docs/sandbox/Connected_Objects.html .
So I am building a UML drawing tool with KonvaJS and KonvaReact, for that I need to connect shapes with lines. I saw the tutorial on the website on connected objects https://konvajs.org/docs/sandbox/Connected_Objects.html.
它们使用函数get_connecter_points
,该函数根据圆上的弧度从直线计算位置.
They use a function get_connecter_points
that calculates the possition from the line based on the radians on the circle.
function getConnectorPoints(from, to) {
const dx = to.x - from.x;
const dy = to.y - from.y;
let angle = Math.atan2(-dy, dx);
const radius = 50;
return [
from.x + -radius * Math.cos(angle + Math.PI),
from.y + radius * Math.sin(angle + Math.PI),
to.x + -radius * Math.cos(angle),
to.y + radius * Math.sin(angle)
];
}
我正在尝试提供一个类似函数,但是无法提出一个好的解决方案或找到一个很好的例子.如您所见,在函数中,我只是从x和y返回到x和y,因此这些线将放置在每个正方形的左上角.
I am trying to comeup with a simular function, but can't comeup with a good solution or find a good example. As you can see in the immage I just returned the from x and y and to x and y in the function and so the lines will be placed in the left top corner of every square.
该函数的目标应该是将线条放置在正方形侧面的一半,以及正方形的正确侧面上.因此,当将to square放置在其下方时,它应显示在底部.
The goal of the function should be to place the lines halfway to the side of the square and on the correct side of the square. So when the to square is placed below it should appear on the bottom side.
因此,如果有人有解决方案,我们将不胜感激.
So if someone has a solution, any help is appreciated.
推荐答案
对于矩形,数学要比对圆形复杂.
For the rectangles, the math is a bit more complex than for circles.
首先,您需要计算两个对象之间的连接线角度:
First, you need to calculate the angle for connection line, between two objects:
function getCenter(node) {
return {
x: node.x() + node.width() / 2,
y: node.y() + node.height() / 2
}
}
const c1 = getCenter(object1);
const c2 = getCenter(object2;
const dx = c1.x - c2.x;
const dy = c1.y - c2.y;
const angle = Math.atan2(-dy, dx);
第二,当您知道角度时,您需要一个函数,该函数找到矩形边界的一个点,您可以使用该点与另一个对象连接.
Second, when you know the angle, you need a function, that finds a point of the rectangle border that you can use to connect with another object.
function getRectangleBorderPoint(radians, size, sideOffset = 0) {
const width = size.width + sideOffset * 2;
const height = size.height + sideOffset * 2;
radians %= 2 * Math.PI;
if (radians < 0) {
radians += Math.PI * 2;
}
const phi = Math.atan(height / width);
let x, y;
if (
(radians >= 2 * Math.PI - phi && radians <= 2 * Math.PI) ||
(radians >= 0 && radians <= phi)
) {
x = width / 2;
y = Math.tan(radians) * x;
} else if (radians >= phi && radians <= Math.PI - phi) {
y = height / 2;
x = y / Math.tan(radians);
} else if (radians >= Math.PI - phi && radians <= Math.PI + phi) {
x = -width / 2;
y = Math.tan(radians) * x;
} else if (radians >= Math.PI + phi && radians <= 2 * Math.PI - phi) {
y = -height / 2;
x = y / Math.tan(radians);
}
return {
x: -Math.round(x),
y: Math.round(y)
};
}
现在,您只需要为线形生成点:
Now, you just need to generate points for line shape:
function getPoints(r1, r2) {
const c1 = getCenter(r1);
const c2 = getCenter(r2);
const dx = c1.x - c2.x;
const dy = c1.y - c2.y;
const angle = Math.atan2(-dy, dx);
const startOffset = getRectangleBorderPoint(angle + Math.PI, r1.size());
const endOffset = getRectangleBorderPoint(angle, r2.size());
const start = {
x: c1.x - startOffset.x,
y: c1.y - startOffset.y
};
const end = {
x: c2.x - endOffset.x,
y: c2.y - endOffset.y
};
return [start.x, start.y, end.x, end.y]
}
function updateLine() {
const points = getPoints(rect1, rect2);
line.points(points);
}
所有这些都作为演示:
function getRectangleBorderPoint(radians, size, sideOffset = 0) {
const width = size.width + sideOffset * 2;
const height = size.height + sideOffset * 2;
radians %= 2 * Math.PI;
if (radians < 0) {
radians += Math.PI * 2;
}
const phi = Math.atan(height / width);
let x, y;
if (
(radians >= 2 * Math.PI - phi && radians <= 2 * Math.PI) ||
(radians >= 0 && radians <= phi)
) {
x = width / 2;
y = Math.tan(radians) * x;
} else if (radians >= phi && radians <= Math.PI - phi) {
y = height / 2;
x = y / Math.tan(radians);
} else if (radians >= Math.PI - phi && radians <= Math.PI + phi) {
x = -width / 2;
y = Math.tan(radians) * x;
} else if (radians >= Math.PI + phi && radians <= 2 * Math.PI - phi) {
y = -height / 2;
x = y / Math.tan(radians);
}
return {
x: -Math.round(x),
y: Math.round(y)
};
}
const stage = new Konva.Stage({
container: 'container',
width: window.innerWidth,
height: window.innerHeight
});
const layer = new Konva.Layer();
stage.add(layer);
const rect1 = new Konva.Rect({
x: 20,
y: 20,
width: 50,
height: 50,
fill: 'green',
draggable: true
});
layer.add(rect1);
const rect2 = new Konva.Rect({
x: 220,
y: 220,
width: 50,
height: 50,
fill: 'red',
draggable: true
});
layer.add(rect2);
const line = new Konva.Line({
stroke: 'black'
});
layer.add(line);
function getCenter(node) {
return {
x: node.x() + node.width() / 2,
y: node.y() + node.height() / 2
}
}
function getPoints(r1, r2) {
const c1 = getCenter(r1);
const c2 = getCenter(r2);
const dx = c1.x - c2.x;
const dy = c1.y - c2.y;
const angle = Math.atan2(-dy, dx);
const startOffset = getRectangleBorderPoint(angle + Math.PI, rect1.size());
const endOffset = getRectangleBorderPoint(angle, rect2.size());
const start = {
x: c1.x - startOffset.x,
y: c1.y - startOffset.y
};
const end = {
x: c2.x - endOffset.x,
y: c2.y - endOffset.y
};
return [start.x, start.y, end.x, end.y]
}
function updateLine() {
const points = getPoints(rect1, rect2);
line.points(points);
}
updateLine();
layer.on('dragmove', updateLine);
layer.draw();
<script src="https://unpkg.com/konva@^3/konva.min.js"></script>
<div id="container"></div>
这篇关于KonvaJS连接正方形和正确的线位置?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!