Для прямоугольников математика немного сложнее, чем для кругов.
Во-первых, вам нужно вычислить угол для соединительной линии между двумя объектами:
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);
Второй , когда вы знаете угол, вам нужна функция, которая находит точку границы прямоугольника, которую вы можете использовать для соединения с другим объектом.
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)
};
}
Теперь вам просто нужно сгенерировать точки для формы линии :
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>