我目前正在使用javascript
在SVG
中编写图表编辑器。
我遇到了有关矩形之间连接的问题。我找到了很多资源来绘制圆圈之间的连接,但没有任何关于矩形的信息。
所以现在我得到的是,我可以通过用鼠标拖动线来绘制两个矩形之间的连接线,但是连接显示在它们内部,因为我从矩形的中点计算连接。
正如你在下面的图片中看到的那样,我给自己做了一些想法,但我没有完成最后一步。
我只想绘制标记为红色的线条。
稍后我想拖动矩形并且应该更新这条线但是现在我只需要计算这条线。
有人有个好主意吗?
答案 0 :(得分:4)
假设您有两个职位,并且您知道他们的中心(cx1
,cy1
)和(cx2
,cy2
)。你还有宽度和高度除以2 (即从中心到边的距离):( w1
,h1
)和(w2
, h2
)。
它们之间的距离是:
var dx = cx2 - cx1;
var dy = cy2 - cy1;
然后您可以使用以下方法计算两个rects的交点:
var p1 = getIntersection(dx, dy, cx1, cy1, w1, h1);
var p2 = getIntersection(-dx, -dy, cx2, cy2, w2, h2);
getIntersection
的位置:
function getIntersection(dx, dy, cx, cy, w, h) {
if (Math.abs(dy / dx) < h / w) {
// Hit vertical edge of box1
return [cx + (dx > 0 ? w : -w), cy + dy * w / Math.abs(dx)];
} else {
// Hit horizontal edge of box1
return [cx + dx * h / Math.abs(dy), cy + (dy > 0 ? h : -h)];
}
};
以下是一个例子:
var rect1 = document.getElementById('rect1');
var rect2 = document.getElementById('rect2');
var cxn = document.getElementById('connection');
updateConnection();
function updateConnection() {
// Top left coordinates
var x1 = parseFloat(rect1.getAttributeNS(null, 'x'));
var y1 = parseFloat(rect1.getAttributeNS(null, 'y'));
var x2 = parseFloat(rect2.getAttributeNS(null, 'x'));
var y2 = parseFloat(rect2.getAttributeNS(null, 'y'));
// Half widths and half heights
var w1 = parseFloat(rect1.getAttributeNS(null, 'width')) / 2;
var h1 = parseFloat(rect1.getAttributeNS(null, 'height')) / 2;
var w2 = parseFloat(rect2.getAttributeNS(null, 'width')) / 2;
var h2 = parseFloat(rect2.getAttributeNS(null, 'height')) / 2;
// Center coordinates
var cx1 = x1 + w1;
var cy1 = y1 + h1;
var cx2 = x2 + w2;
var cy2 = y2 + h2;
// Distance between centers
var dx = cx2 - cx1;
var dy = cy2 - cy1;
var p1 = getIntersection(dx, dy, cx1, cy1, w1, h1);
var p2 = getIntersection(-dx, -dy, cx2, cy2, w2, h2);
cxn.setAttributeNS(null, 'x1', p1[0]);
cxn.setAttributeNS(null, 'y1', p1[1]);
cxn.setAttributeNS(null, 'x2', p2[0]);
cxn.setAttributeNS(null, 'y2', p2[1]);
}
function getIntersection(dx, dy, cx, cy, w, h) {
if (Math.abs(dy / dx) < h / w) {
// Hit vertical edge of box1
return [cx + (dx > 0 ? w : -w), cy + dy * w / Math.abs(dx)];
} else {
// Hit horizontal edge of box1
return [cx + dx * h / Math.abs(dy), cy + (dy > 0 ? h : -h)];
}
};
function makeDraggable(evt) {
var svg = evt.target;
svg.addEventListener('mousedown', startDrag);
svg.addEventListener('mousemove', drag);
svg.addEventListener('mouseup', endDrag);
function getMousePosition(evt) {
var CTM = svg.getScreenCTM();
return {
x: (evt.clientX - CTM.e) / CTM.a,
y: (evt.clientY - CTM.f) / CTM.d
};
}
var selectedElement, offset;
function startDrag(evt) {
if (evt.target.classList.contains('draggable')) {
selectedElement = evt.target;
offset = getMousePosition(evt);
offset.x -= parseFloat(selectedElement.getAttributeNS(null, "x"));
offset.y -= parseFloat(selectedElement.getAttributeNS(null, "y"));
}
}
function drag(evt) {
if (selectedElement) {
var coord = getMousePosition(evt);
selectedElement.setAttributeNS(null, "x", coord.x - offset.x);
selectedElement.setAttributeNS(null, "y", coord.y - offset.y);
updateConnection();
}
}
function endDrag(evt) {
selectedElement = null;
}
}
.static {
cursor: not-allowed;
}
.draggable {
cursor: move;
fill: #007bff;
fill-opacity: 0.1;
stroke: #007bff;
stroke-width: 0.2;
}
#connection {
stroke-width: 0.1;
stroke: red;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 30 20" onload="makeDraggable(evt)" width="400" height="200">
<rect id="rect1" class="draggable" x="4" y="5" width="4" height="3"/>
<rect id="rect2" class="draggable" x="18" y="5" width="3" height="5"/>
<line id="connection" />
</svg>