从 div 到 div 绘制弯曲的 SVG 箭头线

问题描述 投票:0回答:3

我想使用SVG绘制两条弯曲的箭头线来连接两个元素以指示它们来回移动,如下所示:

enter image description here

我读过一些有关 SVG 的内容,但我不完全确定如何创建垂直线。

其次,如果SVG需要坐标,我是否必须在创建SVG绘图之前找到元素的坐标位置?调整窗口大小是否需要重新绘制?

javascript html css dom svg
3个回答
167
投票

创建一个

svg
元素(不可见)作为整个文档的基础。这将容纳两个箭头。插入两个 svg
path
元素(箭头),其起点和终点坐标是根据要连接的 div 的位置计算的,并且其曲线是根据这些起点和终点坐标以您想要的方式创建的。

对于下面的示例,单击“运行代码片段”。然后单击并拖动任一 div 以查看箭头是如何动态创建的,即它们随 div 一起移动。代码片段中使用 jQuery 和 jQueryUI 只是为了让 div 能够轻松拖动,与箭头的创建和使用无关。

此示例有两个箭头,从 div 两侧的中间开始和结束。当然,曲线的细节取决于您。箭头线是使用 svg

d
path
属性构造的。在此示例中,“M”是路径开始的“moveTo”坐标,“C”点是三次贝塞尔曲线的第一个和第二个控制点以及最终坐标。您必须“查找这些内容”才能了解它们是什么,但它们是在 svg 元素中创建平滑曲线的通用方法。箭头是使用 svg <marker> 元素添加的,您可以在
here
阅读该元素。 更复杂的文档需要更加小心地确定 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 + divB.offsetHeight / 2 }; var posnBRight = { x: divB.offsetLeft + divB.offsetWidth + 8, y: divB.offsetTop + divB.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. */
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;
}
<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>


10
投票
draw_arrow.js

,它导出一个函数

draw_arrow( sel1, locs1, sel2, locs2, arr )
。这会从 CSS 选择器
sel1
标识的元素到
sel2
标识的元素绘制一个箭头。
locs1
locs2
指示箭头在元素上的开始或结束位置。
arr
标识容纳箭头的 SVG 路径。
您可以从

http://www.chromophilia.uk/posts/dress-reform-architecture-and-modernism.html

末尾的链接下载此内容并查看两个演示。作为动画的一部分,我需要箭头来描绘与现代主义相关的各种主题之间的关系。这就是促使我寻找并改编 Andrew 代码的原因。 这是一个建议的改进。我最初将其写为一个新的附加答案,但一些评论者对此表示谴责,所以我不得不将其放在这里并希望它得到注意。我追求这一点是因为模块化很重要。像

draw_arrow

这样的例程应该要求用户对其周围的代码执行尽可能少的操作。但目前,它需要用户在

<path>
内创建一个
<svg>
元素来绘制每个箭头,并为路径创建 ID。我建议
draw_arrow
通过更新 DOM 树来做到这一点会更好。赞成还是反对的评论?
    


9
投票

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; }

已测试,有效!

© www.soinside.com 2019 - 2024. All rights reserved.