dsp*_*099 15 html javascript css svg dom
我想使用SVG绘制两条弯曲的箭头线来连接两个元素以指示它们来回走动,如下所示:
我已经阅读了一些关于SVG的内容,但我并不完全确定如何创建一个垂直的线.
其次,如果SVG采用坐标,在创建SVG绘图之前是否必须找到元素的坐标位置?如果调整窗口大小,是否必须重新绘制?
And*_*ems 59
创建一个svg(隐藏)整个文档的元素.这将保持两个箭头.插入两个svg path元素(箭头),其开始和结束坐标是根据要连接的div的位置计算的,并且根据这些开始和结束坐标以任何方式创建其曲线.
对于下面的示例,请单击"运行代码段".然后单击并拖动其中一个div以查看箭头是如何动态创建的,即它们随div移动.在代码片段中使用jQuery和jQueryUI只是为了允许div的简单可拖动性,并且与箭头的创建和使用无关.
这个例子有两个箭头开始和结束在div的两侧.当然,曲线的细节取决于您.箭头线是使用dsvg 的属性构造的path.在这个例子中,"M"是路径将开始的"moveTo"坐标,"C"点是立方贝塞尔曲线的第一和第二控制点和最终坐标.你必须看看那些高达了解它们是什么,但他们在SVG元素创建平滑曲线的一般方式.箭头是使用svg <marker>元素添加的,您可以在这里阅读.
更复杂的文档需要更加谨慎来确定svg path元素的开始和结束坐标,即箭头,但这个例子至少为你提供了一个开始的地方.
您的具体问题的答案:
如果SVG采用坐标,在创建SVG绘图之前是否必须找到元素的坐标位置?是的,正如我在我的代码中所做的那样.
如果调整窗口大小,是否必须重新绘制?可能是的,取决于窗口调整大小时div本身会发生什么.
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.
*/Run Code Online (Sandbox Code Playgroud)
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;
}Run Code Online (Sandbox Code Playgroud)
<p id="instructions">Click and drag either div to see automatic arrow adjustments.</p>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.12.0/jquery-ui.min.js"></script>
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
<defs>
<marker id="arrowhead" viewBox="0 0 10 10" refX="3" refY="5"
markerWidth="6" markerHeight="6" orient="auto">
<path d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs>
<g fill="none" stroke="black" stroke-width="2" marker-end="url(#arrowhead)">
<path id="arrowLeft"/>
<path id="arrowRight"/>
</g>
</svg>
<div id="a">Div 1</div>
<div id="b">Div 2</div>Run Code Online (Sandbox Code Playgroud)
我发现安德鲁·威廉姆斯的答案非常有用。我已经对其进行了修改,以创建一个库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。我建议最好draw_arrow通过更新DOM树来做到这一点。评论是赞成还是反对?
我们终于拥有了!看看这个:
https://www.npmjs.com/package/arrows-svg
还有一个 React 版本:
https://www.npmjs.com/package/react-arrows
因此,如果您有两个 div,让我们说 ids named:from并to根据您示例中的 div,那么您可以:
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);
Run Code Online (Sandbox Code Playgroud)
当然还有一些css:
.arrow {
pointer-events: none;
}
.arrow__path {
stroke: #000;
fill: transparent;
stroke-dasharray: 4 2;
}
.arrow__head line {
stroke: #000;
stroke-width: 1px;
}
Run Code Online (Sandbox Code Playgroud)
经测试有效!
| 归档时间: |
|
| 查看次数: |
8649 次 |
| 最近记录: |