使用svg在元素直接绘制连线箭头

这篇具有很好参考价值的文章主要介绍了使用svg在元素直接绘制连线箭头。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

注意:svg的图形绘制的点位置坐标是基于画布的位置坐标,相当于从左上角的点为起点。

先来个简单示例:

在点与点之间绘制连线箭头

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <svg width="300" height="300" style="background: #efefef">
    <path d="M 100 50 L 50 100" stroke="url(#grad1)" stroke-width="2" marker-end="url(#arrowhead)" />
    <path d="M 100 50 L 100 100" stroke="black" stroke-width="2" marker-end="url(#arrowhead)" />
    <path d="M 100 50 L 150 100" stroke="black" stroke-width="2" marker-end="url(#arrowhead)" />
    <defs>
      <marker id="arrowhead" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
        <path d="M 0 0 L 10 5 L 0 10 z" />
      </marker>
      <linearGradient id="grad1" x1="0%" y1="0%" x2="100%" y2="0%">
        <stop offset="0%" stop-color="#ff0000" />
        <stop offset="100%" stop-color="#00ff00" />
      </linearGradient>
    </defs>
  </svg>
</body>
</html>

使用svg在元素直接绘制连线箭头
上面示例中可以看到,svg画布的位置在哪,path中点的坐标就从哪里开始,默认是从浏览器可视窗口的左上角开始。那么我们只要知道点的坐标就能绘制箭头了。
接下来,就是获取dom元素的位置坐标,使用到Element.getBoundingClientRect()
使用svg在元素直接绘制连线箭头
比如,我们现在需要在1个顶点,2个终点之间设置连线,由于path的点坐标是基于svg的画布位置,所以我们可以把画布的位置基于元素定位,画布的宽为3个元素之间最大-宽度最小的值,高为高度最高-高度最低的值。粉色框为svg画布的位置,框1、框2、框3表示顶点元素可能出现的位置。
使用svg在元素直接绘制连线箭头

代码示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div style="width: 50px;height: 50px;position: absolute;left: 55px;top: 160px;background: red;" id="box1"></div>
  <div style="width: 50px;height: 50px;position: absolute;left: 55px;top: 530px;background: blue;" id="box2"></div>
  <div style="width: 50px;height: 50px;position: absolute;left: 925px;top: 530px;background: green;" id="box3"></div>
  <script>
    // 获取元素
    const box1 = document.querySelector('#box1')
    const box2 = document.querySelector('#box2')
    const box3 = document.querySelector('#box3')
    // 获取坐标
    const coordinate1 = getPosition(box1, 'bottom')
    const coordinate2 = getPosition(box2, 'top')
    const coordinate3 = getPosition(box3, 'top')

    // 动态创建svg
    let svgWidth = 0
    let pointStart = 0
    // 获取svg的宽度
    let coordinateArr = [coordinate1[0], coordinate2[0], coordinate3[0]].sort((a, b) => b - a);
    // 如果开始元素宽度最大,则设为svg的宽
    if (coordinate1[0] > coordinate2[0] && coordinate1[0] > coordinate3[0]) {
      svgWidth = coordinate1[0] - 75; // 50 + 25,需要减去最左侧盒子的left+width/2
      // 第二个箭头的结束点位置
      pointStart = coordinate3[0] - 75;
    } else {
      // 用最大宽度-最小宽度
      svgWidth = coordinateArr[0] - coordinateArr[2];
      pointStart = svgWidth - 5;
    }
    const svgHeight = coordinate3[1] - coordinate1[1]
    const svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    // 如果只有一个分支可以考虑设置svg的宽高直接为10,然后左上角坐标 = (start元素底部中心点横坐标 - 5, start元素底部中心点纵坐标)
    // 默认是设置宽高为10的原因在于画布需要有空间,这样箭头才能正常显示

    // 以下是针对有两个分支的情况
    // svg的顶部中心位置就是起始坐标
    // svg的左右两个角落位置就是两个结束点坐标
    const start = `${coordinate1[0] - coordinate2[0]}`
    svgEl.innerHTML = `
      <path d="M ${start} 0 L 0 ${svgHeight}" stroke="url(#grad1)" stroke-width="2" marker-end="url(#arrowhead)" />
      <path d="M ${start} 0 L ${pointStart} ${svgHeight}" stroke="url(#grad1)" stroke-width="2" marker-end="url(#arrowhead)" />
      <defs>
        <marker id="arrowhead" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
          <path d="M 0 0 L 10 5 L 0 10 z" fill="red" />
        </marker>
        <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" stop-color="#ff0000" />
          <stop offset="100%" stop-color="#00ff00" />
        </linearGradient>
      </defs>
    `
    svgEl.setAttribute('width', svgWidth)
    svgEl.setAttribute('height', svgHeight)
    svgEl.style.cssText = `background: #ddd; position: absolute;left: ${coordinate2[0]}px;top: ${coordinate1[1]}px;`
    document.body.appendChild(svgEl)


    function getPosition (el, direction) {
      const rect = el?.getBoundingClientRect()
      const x = (rect.right - rect.left) / 2 + rect.left
      const y = rect[direction]
      return [x, y]
    }
  </script>
</body>
</html>

使用svg在元素直接绘制连线箭头

注意:当点与点之前的x坐标相同,如果填充色是渐变色的话,会存在path的箭头变为0的情况。我们可以设置点的位置偏差来避免这种情况;还有部分三角形箭头被遮挡的情况,可以把点的y坐标适当减个5的值,避免这种情况

优化代码:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
<!--可以修改left的值-->
  <div style="width: 50px;height: 50px;position: absolute;left: 55px;top: 160px;background: red;" id="box1"></div>
  <div style="width: 50px;height: 50px;position: absolute;left: 55px;top: 530px;background: blue;" id="box2"></div>
  <div style="width: 50px;height: 50px;position: absolute;left: 925px;top: 530px;background: green;" id="box3"></div>

  <script>
    // 获取元素
    const box1 = document.querySelector('#box1')
    const box2 = document.querySelector('#box2')
    const box3 = document.querySelector('#box3')
    // 获取坐标
    const coordinate1 = getPosition(box1, 'bottom')
    const coordinate2 = getPosition(box2, 'top')
    const coordinate3 = getPosition(box3, 'top')
    console.log(coordinate1)
    console.log(coordinate2)
    console.log(coordinate3)

    // 动态创建svg
    const pad = 10 // 偏移量,避免箭头宽度为0
    let svgWidth = 0
    let pointStart = 0
    // 获取svg的宽度
    let coordinateArr = [coordinate1[0], coordinate2[0], coordinate3[0]].sort((a, b) => b - a);
    // 如果开始元素宽度最大,则设为svg的宽
    if (coordinate1[0] > coordinate2[0] && coordinate1[0] > coordinate3[0]) {
      svgWidth = coordinate1[0] - 75 + pad; // 50 + 25,需要减去最左侧盒子的left+width/2
      // 第二个箭头的结束点位置
      pointStart = coordinate3[0] - 75 + pad;
    } else {
      // 用最大宽度-最小宽度
      svgWidth = coordinateArr[0] - coordinateArr[2] + pad;
      pointStart = svgWidth - 5;
    }
    const svgHeight = coordinate3[1] - coordinate1[1]
    const svgEl = document.createElementNS("http://www.w3.org/2000/svg", "svg");
    // 如果只有一个分支可以考虑设置svg的宽高直接为10,然后左上角坐标 = (start元素底部中心点横坐标 - 5, start元素底部中心点纵坐标)
    // 默认是设置宽高为10的原因在于画布需要有空间,这样箭头才能正常显示

    // 以下是针对有两个分支的情况
    // svg的顶部中心位置就是起始坐标
    // svg的左右两个角落位置就是两个结束点坐标
    const start = `${coordinate1[0] - coordinate2[0] + 8}`
    const pointEnd = svgHeight - 5
    svgEl.innerHTML = `
      <path d="M ${start} 0 L ${pad} ${pointEnd}" stroke="url(#grad1)" stroke-width="2" marker-end="url(#arrowhead)" />
      <path d="M ${start} 0 L ${pointStart} ${pointEnd}" stroke="url(#grad1)" stroke-width="2" marker-end="url(#arrowhead)" />
      <defs>
        <marker id="arrowhead" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="6" markerHeight="6" orient="auto">
          <path d="M 0 0 L 10 5 L 0 10 z" fill="red" />
        </marker>
        <linearGradient id="grad1" x1="0%" y1="0%" x2="0%" y2="100%">
          <stop offset="0%" stop-color="#ff0000" />
          <stop offset="100%" stop-color="#00ff00" />
        </linearGradient>
      </defs>
    `
    svgEl.setAttribute('width', svgWidth)
    svgEl.setAttribute('height', svgHeight)
    // 这个地方left - 10是为了避免开始点和结束点的x点坐标一样的时候,使用渐变色填充宽度消失的问题,将画布左移10px避免偏差
    svgEl.style.cssText = `background: #ddd; position: absolute;left: ${coordinateArr[2] - pad}px;top: ${coordinate1[1]}px;`
    document.body.appendChild(svgEl)


    function getPosition (el, direction) {
      const rect = el?.getBoundingClientRect()
      const x = (rect.right - rect.left) / 2 + rect.left
      const y = rect[direction]
      return [x, y]
    }
  </script>
</body>
</html>

使用svg在元素直接绘制连线箭头

注意:在创建之前需要判断当前文档是否存在svg元素,如果存在需要先删除再创建,避免存在多个svg元素文章来源地址https://www.toymoban.com/news/detail-440608.html

到了这里,关于使用svg在元素直接绘制连线箭头的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Android-高级-UI-进阶之路-(七)-SVG-基础使用-+-绘制中国地图

    输入搜索动画 利用在线绘制 SVG 图标网站 制作搜索图标 可以自己随意捣鼓绘制,绘制好了之后点击视图-源代码,将 SVG 代码复制出来保存成 search_svg.xml 在线转换 svg2vector 点击空白或者直接将 SVG 拖拽指定区域进行转换 将转换好的 Android 格式的 vector 导入 AS 开始制作动画关联

    2024年03月20日
    浏览(52)
  • Matplotlib——绘制散点图并连线

    x_values y_values

    2024年02月14日
    浏览(41)
  • Unity实现杀戮尖塔出牌效果( 三. 贝塞尔曲线引导箭头绘制,卡牌使用效果制作)

    1. 攻击类型卡牌 ①拖拽超过一定高度之后卡牌会移动到手牌中心位置 ②出现攻击引导箭头 (塞贝尔曲线) ③成功指向目标怪物后打出 2. 技能能力类型卡牌 ①可自由拖动 ②脱离手牌高度后打出 这里只展示此效果核心代码内容,重复代码不做赘述,上期(二.鼠标指向卡牌时,

    2024年04月12日
    浏览(57)
  • 利用R分别绘制配对连线散点图、云雨图、山脊图

           大家好,我是带我去滑雪!        精美的科研绘图总会给人眼前一亮,今天学习利用R绘制 多组配对连线散点图、云雨图、山脊图 ,这三幅图最近都曾出现在Nature Communications (IF 16.6)中,比如配对连线散点图,如下所示:         因此值得一学,方便后续用于自己的

    2024年02月16日
    浏览(39)
  • 使用html2canvas将整个元素导出为图片,其中包含svg和img,解决img跟svg导出时img或svg(canvg处理)不显示的问题,以及相关优化

    目录 前言 一、准备 二、解决问题 1.将svg跟img转为canvas的方法 2.将base64转换成file文件的方法 3.点击下载使用方法 1).对dom没有处理,需求只是将图片导出即可  2).涉及对dom的拖拽,流程图之类的(需复制dom,在复制的dom上进行处理)  三、效果图如下 查阅很多相关的文章和

    2024年01月20日
    浏览(64)
  • 使用OpenCV绘制图形

    绘制黄色的线: 绘制矩形: 绘制圆形: 绘制多边形: 绘制文字:

    2024年01月22日
    浏览(49)
  • 使用MFC绘制一些简单图形

    目录 一、画直线 更改画笔样式 二、使用画刷画一个矩形 透明矩形 自定义颜色填充矩形 自定义图形填充矩形 四、实现一个画笔 五、画扇形 六、画椭圆 七、画圆 八、输出文本     画一条直线需要一个起点和一个终点,当鼠标按下时记录为起点坐标,鼠标弹起时记录为终点

    2024年02月07日
    浏览(49)
  • SVG图形

    SVG(Scalable Vector Graphics)是一种用于描述二维矢量图形的XML 格式文件。它是一种用于在网络上显示图形的开放标准,旨在与Web上的其他技术(如HTML和CSS)集成,并支持在不失真的情况下缩放和调整大小。SVG 图形可以以矢量形式表示,这意味着它们由一系列的数学公式和形状

    2024年02月07日
    浏览(30)
  • Android-高级-UI-进阶之路-(七)-SVG-基础使用-+-绘制中国地图,Android面试中常问的MMAP到底是啥东东

    iv.setImageDrawable(animatedVectorDrawable) val animatable = iv.drawable as Animatable animatable.start() } } 输入搜索动画 利用在线绘制 SVG 图标网站 制作搜索图标 可以自己随意捣鼓绘制,绘制好了之后点击视图-源代码,将 SVG 代码复制出来保存成 search_svg.xml 在线转换 svg2vector 点击空白或者直接将

    2024年04月25日
    浏览(47)
  • 基于 SVG 的图形交互方案实践

    不知道从什么时候起,人们开始喜欢上数字大屏这种“ 花里胡哨 ”的东西,仿佛只要用上“ 科技蓝 ”这样神奇的色调,就可以让一家公司焕然一新,瞬间变得科技感满满。不管数字大屏的实际意义,是用来帮助企业监控和决策,还是为了方便领导参观和视察,抑或是为了向

    2024年02月11日
    浏览(32)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包