使用SVG绘制流程图

本篇主要记录流程图的实现过程中的难点和核心技术点,先上效果图:

1414921-20190404152210038-475767668.png

节点可以任意拖拽,曲线跟随变化
1414921-20190404154219462-2117166038.png

正在连接的线
1414921-20190404140852631-1732980855.png

1、节点实现

流程图是基于SVG绘制的,节点主要利用 gforeignObject的特性来实现:

   <g  class="pane-node">
        <foreignObject width="180" height="50">
          <body xmlns="http://www.w3.org/1999/xhtml">
            <div  class="pane-node-content">
              <span class="iconfont icon-datas"></span>
              <span class="name" :title="item.name">{{item.name}}</span>             
              <!-- 节点进 -->
              <div  class="pane-port-list in">
                ......
              </div>
              <!-- 节点出 -->
              <div class="pane-port-list out">
                ......
              </div>
            </div>
          </body>
        </foreignObject>
    </g>
  • g元素:特性是可以包裹元素,并进行位置变化,这样拖拽的时候获取对应的坐标改变 transform 的值就可以整体移动了;
  • foreignObject标签:借助<foreignObject>标签,可以直接在SVG内部嵌入XHTML元素,尤其一些需要css进行控制的样式类,但是这个兼容性较差,主要是IE浏览器。

2、曲线的绘制
1414921-20190404161448223-1159077789.png

核心代码:

   <g class="pane-link">
      <path class="connector-wrap" :d="`M ${pos.startS} Q ${pos.curveS}  T ${pos.endS}`"></path>
      <path
        class="target-marker"
        d="M 5 0 L 0 3.6327126400268037 L 5 7.265425280053607 Z"
        :transform="`translate(${item.endPosX - 4},${item.endPosY + 4}) scale(1,1) rotate(-90)`"
      ></path>
    </g>

这里使用的是svg中的path中的M Q T

  • Mmoveto 这里是初始节点的底部连接点
  • Qquadratic Bézier curve 二次贝塞尔曲线
    1414921-20190404142458244-312127285.png【截图源于网络】
  • Tsmooth quadratic Bézier curveto 二次贝塞尔曲线平滑延伸
    1414921-20190404143722635-510629902.png【截图源于网络】

这里的T指的是通过一个控制点推断出一个新的控制点,T前面必须是一个Q命令或者是另一个T命令

由此可见,只要确认三个点(起点,控制点,终点),就可以绘制出平滑好看的曲线啦~

/**
* startPosX 起节点的左上角x
* endPosX  终节点的左上角x
* sizeX 节点的一半宽度 sizeY 是节点的高度
/
// 起始点
 let startS = `${startPosX + sizeX} ${startPosY + sizeY}`;

// 二次贝尔曲线
 let curveS = `${startPosX + sizeX} ${startPosY + sizeY + 40} ${
    this.endNode
    ? (startPosX + endPosX+ 2 * sizeX) / 2
     : (startPosX + endPosX+ sizeX) / 2
 } ${(startPosY + endPosY + 20) / 2}`;

// 终点
let endS = `${this.endNode ? endPosX + sizeX : endPosX}  ${endPosY}`;

至于节点的拖拽就比较简单了,点击移动的时候获取位置信息更transformtranslate属性即可。

转载于:https://www.cnblogs.com/webhmy/p/10649668.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值