我想使用SVG绘制两条弯曲的箭头线来连接两个元素以指示它们来回走动,如下所示:
我已经阅读了一些关于SVG的内容,但我并不完全确定如何创建一个垂直的线。
其次,如果SVG采用坐标,在创建SVG绘图之前是否必须找到元素的坐标位置?如果调整窗口大小,是否必须重新绘制?
答案 0 :(得分:46)
创建svg
元素(无形)作为整个文档的基础。这将保持两个箭头。插入两个svg path
元素(箭头),其开始和结束坐标是根据要连接的div的位置计算的,并且根据这些元素的开始和方式以任何方式创建其曲线。结束坐标。
对于下面的示例,请点击"运行代码段"。然后单击并拖动div中的任何一个以查看箭头是如何动态创建的,即它们随div移动。 jQuery和jQueryUI在代码片段中使用,只是为了让div的易于拖动,与箭头的创建和使用无关。
这个例子有两个箭头,在div的中间开始和结束。两侧。当然,曲线的细节取决于您。箭头线是使用svg d
的{{1}}属性构造的。在这个例子中," M"是" moveTo"坐标路径将开始的位置和" C"点是三次贝塞尔曲线的第一和第二控制点和最终坐标。您必须look those up才能了解它们是什么,但它们是在svg元素中创建平滑曲线的一般方法。使用svg path
元素添加箭头,您可以阅读here。
更复杂的文档需要更加谨慎地确定svg <marker>
元素的开始和结束坐标,即箭头,但这个例子至少为您提供了一个开始的地方。
您特定问题的答案:
如果SVG采用坐标,在创建SVG绘图之前是否必须找到元素的坐标位置?是的,正如我在我的代码中所做的那样。
如果调整窗口大小,是否必须重新绘制?可能是的,取决于调整窗口大小时div本身会发生什么。
path
&#13;
var divA = document.querySelector("#a");
var divB = document.querySelector("#b");
var arrowLeft = document.querySelector("#arrowLeft");
var arrowRight = document.querySelector("#arrowRight");
var drawConnector = function() {
var posnALeft = {
x: divA.offsetLeft - 8,
y: divA.offsetTop + divA.offsetHeight / 2
};
var posnARight = {
x: divA.offsetLeft + divA.offsetWidth + 8,
y: divA.offsetTop + divA.offsetHeight / 2
};
var posnBLeft = {
x: divB.offsetLeft - 8,
y: divB.offsetTop + divA.offsetHeight / 2
};
var posnBRight = {
x: divB.offsetLeft + divB.offsetWidth + 8,
y: divB.offsetTop + divA.offsetHeight / 2
};
var dStrLeft =
"M" +
(posnALeft.x ) + "," + (posnALeft.y) + " " +
"C" +
(posnALeft.x - 100) + "," + (posnALeft.y) + " " +
(posnBLeft.x - 100) + "," + (posnBLeft.y) + " " +
(posnBLeft.x ) + "," + (posnBLeft.y);
arrowLeft.setAttribute("d", dStrLeft);
var dStrRight =
"M" +
(posnBRight.x ) + "," + (posnBRight.y) + " " +
"C" +
(posnBRight.x + 100) + "," + (posnBRight.y) + " " +
(posnARight.x + 100) + "," + (posnARight.y) + " " +
(posnARight.x ) + "," + (posnARight.y);
arrowRight.setAttribute("d", dStrRight);
};
$("#a, #b").draggable({
drag: function(event, ui) {
drawConnector();
}
});
setTimeout(drawConnector, 250);
/* The setTimeout delay here is only required to prevent
* the initial appearance of the arrows from being
* incorrect due to the animated expansion of the
* Stack Overflow code snippet results after clicking
* "Run Code Snippet." If this was a simpler website,
* a simple command, i.e. `drawConnector();` would suffice.
*/
&#13;
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
#instructions {
position: fixed;
left: 50%;
}
#a, #b {
color: white;
text-align: center;
padding: 10px;
position: fixed;
width: 100px;
height: 20px;
left: 100px;
}
#a {
background-color: blue;
top: 20px;
}
#b {
background-color: red;
top: 150px;
}
&#13;
答案 1 :(得分:3)
我发现安德鲁·威廉姆斯的答案非常有用。我已经对其进行了修改,以创建一个库draw_arrow.js
,该库导出了一个函数draw_arrow( sel1, locs1, sel2, locs2, arr )
。这从CSS选择器sel1
标识的元素到sel2
标识的元素绘制了一个箭头。 locs1
和locs2
指示箭头应在元素上的开始或结束位置。 arr
标识要保留箭头的SVG路径。
您可以从http://www.chromophilia.uk/blog/dress-reform-architecture-and-modernism/末尾的链接下载此文件并查看两个演示。作为动画的一部分,我需要箭头来描述与现代主义相关的各个主题之间的关系。这就是促使我找到并改编安德鲁代码的原因。
这是建议的改进。我最初将其写为一个新的附加答案,但是一些评论者已经执行了该命令,因此我必须将其放在此处,并希望它能引起注意。我之所以这样做,是因为模块化很重要。诸如draw_arrow
之类的例程应要求其用户对周围的代码进行尽可能少的处理。但是目前,它需要用户在<path>
内为要绘制的每个箭头创建一个<svg>
元素,并为路径创建ID。我建议通过更新DOM树来使draw_arrow
更好。赞成还是反对评论?
答案 2 :(得分:3)
我们终于有了它!看看这个:
https://www.npmjs.com/package/arrows-svg
还有一个React版本:
https://www.npmjs.com/package/react-arrows
因此,如果您有两个div,根据您示例中的div分别将其ID分别命名为from
和to
,那么您可以这样做:
import arrowCreate, { DIRECTION } from 'arrows'
const arrow = arrowCreate({
className: 'arrow',
from: {
direction: DIRECTION.LEFT,
node: document.getElementById('from'),
translation: [-0.5, -1],
},
to: {
direction: DIRECTION.LEFT,
node: document.getElementById('to'),
translation: [0.9, 1],
},
})
/*
- arrow.node is HTMLElement
- arrow.timer is idInterval from setInterval()
REMEMBER about clearInterval(node.timer) after unmount
*/
document.body.appendChild(arrow.node);
当然还有一些CSS:
.arrow {
pointer-events: none;
}
.arrow__path {
stroke: #000;
fill: transparent;
stroke-dasharray: 4 2;
}
.arrow__head line {
stroke: #000;
stroke-width: 1px;
}
经过测试,可以正常工作!