vue3中如何使用d3.js绘制流程图(TS语法)

 更新时间:2023年10月17日 11:23:05   作者:是浅笑耶  
这篇文章主要给大家介绍了关于vue3中如何使用d3.js绘制流程图的相关资料,D3.js是由javaScript语言编写绘图库,其原理是通过调用一系列内置函数,生成SVG,并在网页渲染,需要的朋友可以参考下

先放效果图:

1.安装dagre-d3和d3:

npm install d3
npm install dagre-d3

2.在组件中导入并使用d3和dagre-d3:

<script>
    import * as d3 from 'd3';
    import dagreD3 from 'dagre-d3';
</script>

3.在模板中创建节点元素:

<template>
    <div class="top_model">
        <div class="flow_chart" ref="flowchartContainer"></div>
    </div>
</template>

4.在setup中定义所需数据:

setup()  {
    //创建一个ref引用对象,它用于引用以上绑定ref为flowchartContainer的DOM元素
    const flowchartContainer = ref(null);
    const taskLogData = reactive({
        dataSource: [] as any,
        //流程图数据
        list: {
          nodeInfos: [] as any,
          edges: [] as any,
        },
    })
}

5.进行绘制:

//mounted生命周期钩子函数是在组件实例挂载到 DOM 后调用的,
//在这个时候可以获取到组件的根元素,并且可以执行相应的操作
//因此将绘制代码放在这里执行
onMounted(async () => {
    //调用了接口getListData,需要从其中取出数据,因此需要执行异步方法async/await
    await getListData();
    //nextTick函数确保了在DOM更新之后再执行相应的操作,
    //避免了由于异步更新导致的状态不一致问题
    nextTick(() => {
        //使用dagreD3库来创建一个有向无环图的图形
        var g = new dagreD3.graphlib.Graph().setGraph({
          rankdir: 'LR', // 指定布局方向为从左到右
          nodesep: 200, // 设置节点间距
          ranksep: 250, //垂直间距
        });
        //添加节点
        taskLogData.list.nodeInfos.forEach(
          (
            item: {
              id: string;
              label: any;
              tooltip: any;
              tipone: any;
              tiptow: any;
              tipthree: any;
              color: any;
            },
            index: any,
          ) => {
            //设置图形中指定节点的属性
            g.setNode(item.id, {
              label: item.label,//节点内容
              //自定义属性,调整样式使其成为节点备注
              tooltip: item.tooltip,//节点备注(对应图片中的节点下的名称,开始-结束)
              tipone: item.tipone,//节点备注1(对应图片中的时间)
              tiptow: item.tiptow,//节点备注2(对应图片中的操作人员)
              tipthree: item.tipthree,//节点备注3(对应图片中的蓝色备注)
              style: `fill: ${item.color}`,//节点填充颜色,item.color为变量
              shape: 'circle',//节点形状设置为圆形
              class: 'node',//设置节点类名
              rank: 0, // 设置节点的rank属性为0,表示在同一水平排列
            });
          },
        );
        //添加节点关系
        taskLogData.list.edges.forEach(
          (item: { source: string; target: string; edgeColor: string }) => {
            //创建并设置图形中两个节点之间的边(Edge)
            g.setEdge(item.source, item.target, {
              // 设置边的样式
              style: 'stroke: ' + item.edgeColor + '; 
              fill: none; stroke-width: 2px;',
              arrowheadStyle: 'fill: none;', // 设置箭头样式为无箭头
            });
          },
        );
        //创建一个SVG元素作为绘图容器,
        //并将其添加到flowchartContainer.value所引用的DOM元素中
        const svg = d3
          .select(flowchartContainer.value)
          //在选定的DOM元素内添加一个SVG元素
          .append('svg')
          //设置SVG元素的宽度与高度属性
          .attr('width', '')
          .attr('height', 240);
        // 创建渲染器
        const render = new dagreD3.render();
        // 执行渲染
        render(svg as any, g as any);
        // 添加节点备注
        //获取并遍历类名为node的元素
        svg.selectAll('.node').each((nodeId, index) => {
          // 获取节点的备注信息
          const tooltipText = g.node(nodeId as any).tooltip;
          const tipone = g.node(nodeId as any).tipone;
          const tiptow = g.node(nodeId as any).tiptow;
          const tipthree = g.node(nodeId as any).tipthree;
          //获取节点对象
          const node = d3.select(flowchartContainer.value);
          // 获取元素的位置
          const bbox = g.node(nodeId as any);
          // 在节点下方添加备注文本
          const remarkText = (node as any)
            .append('text')
            .attr('class', 'node-remark')
            .text(tooltipText);
          const remarkTextone = (node as any)
            .append('text')
            .attr('class', 'node-remark')
            .text(tipone);
          const remarkTexttow = (node as any)
            .append('text')
            .attr('class', 'node-remark')
            .text(tiptow);
          const remarkTextthree = (node as any)
            .append('text')
            .attr('class', 'node-remark')
            .text(tipthree)
            .attr('class', 'remarkLast')
            .attr('id', 'remarkLast' + nodeId);
          //添加气泡弹窗
          const remarkTextFour = (node as any)
            .append('div')
            .attr('class', 'remarkFlow')
            .attr('id', 'remarkFlow' + nodeId)
            .text(tipthree);
          // 调整备注位置
          remarkText
            .style('position', 'absolute')
            .style('top', `${bbox.y + 60}px`)
            .style('left', `${bbox.x + 30}px`);
          remarkTextone
            .style('position', 'absolute')
            .style('top', `${bbox.y + 80}px`)
            .style('left', `${bbox.x + 30}px`);
          remarkTexttow
            .style('position', 'absolute')
            .style('top', `${bbox.y + 100}px`)
            .style('max-width', '130px')
            .style('left', `${bbox.x + 30}px`);
          remarkTextthree
            .style('position', 'absolute')
            .style('top', `${bbox.y + 130}px`)
            .style('left', `${bbox.x + 30}px`);
          remarkTextFour
            .style('position', 'absolute')
            .style('top', `${bbox.y + 60}px`)
            .style('left', `${bbox.x + 30}px`);
          //鼠标悬停效果
          (document.getElementById('remarkLast' + nodeId) as any).onmouseover
            = function () {
               (document.getElementById('remarkFlow' + nodeId) as any)
               .style.display = 'block';
           };
          (document.getElementById('remarkLast' + nodeId) as any).onmouseout
            = function () {
                (document.getElementById('remarkFlow' + nodeId) as any)
                .style.display = 'none';
           };
        });
      });
});

6.对接口数据进行处理:

// 获取流程图数据
    const getListData = async () => {
      const res: any = await getTaskLogs();
      console.log('res', res);
      if (res.status_code == '0000') {
        const nodeList= res.data;
        // 打印数组中的节点
        console.log('节点:', nodeList);
        for (var i = 0; i < nodeList.length; i++) {
          //默认节点连线颜色为绿色
          let edgeColor = '#52c41a';
          //当前节点之后的节点都设为灰色
          for (var j = i - 1; j > 0; j--) {
            if (nodeList[j].isCurNode == true) {
              taskLogData.list.nodeInfos[i].color = '#d9d9d9';
              edgeColor = '#d9d9d9';
            }
          }
          //当前节点设为蓝色
          if (nodeList[i].isCurNode == true) {
            taskLogData.list.nodeInfos[i].color = '#1890ff';
            edgeColor = '#1890ff';
          }
          //节点之间的连线
          if (i > 0) {
            taskLogData.list.edges.push({
              source: nodeList[i - 1].nodeId,
              target: nodeList[i].nodeId,
              edgeColor: edgeColor,
              style: 'stroke-solid',
            });
          }
        }
      } else {
        message.error(res.reason);
      }
    };

总结 

到此这篇关于vue3中如何使用d3.js绘制流程图的文章就介绍到这了,更多相关vue3用d3.js绘制流程图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Vue项目中使用flow做类型检测的方法

    Vue项目中使用flow做类型检测的方法

    这篇文章主要介绍了Vue项目中使用flow做类型检测的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • vue使用echarts实现地图的方法详解

    vue使用echarts实现地图的方法详解

    这篇文章主要为大家详细介绍了vue使用echarts实现地图的方法,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-03-03
  • vue中通过iframe方式加载本地的vue页面的解决方法

    vue中通过iframe方式加载本地的vue页面的解决方法

    这篇文章主要给大家介绍了在vue中如何通过iframe方式加载本地的vue页面的解决方法,文中有详细的解决流程,需要的朋友可以参考下
    2023-06-06
  • Vue实现Chrome小恐龙游戏的示例代码

    Vue实现Chrome小恐龙游戏的示例代码

    Google 给 Chrome 浏览器加了一个有趣的彩蛋,本文就详细的介绍一下Vue实现Chrome小恐龙游戏的示例代码,具有一定的参考价值,感兴趣的可以了解一下
    2022-04-04
  • vue自定义过滤器创建和使用方法详解

    vue自定义过滤器创建和使用方法详解

    这篇文章主要为大家详细介绍了vue自定义过滤器创建和使用方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-11-11
  • vue video和vue-video-player实现视频铺满教程

    vue video和vue-video-player实现视频铺满教程

    这篇文章主要介绍了vue video和vue-video-player实现视频铺满教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-10-10
  • vuejs2.0实现一个简单的分页示例

    vuejs2.0实现一个简单的分页示例

    本篇文章主要介绍了vuejs2.0实现一个简单的分页示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02
  • 启动myvue报错npm ERR! code ENOENT npm ERR! syscall open的解决办法

    启动myvue报错npm ERR! code ENOENT npm ERR! syscall open的解

    这篇文章主要介绍了启动myvue报错npm ERR! code ENOENT npm ERR! syscall open的解决办法,文中给出了详细的解决方法,并通过图文结合的方式介绍的非常详细,需要的朋友可以参考下
    2024-03-03
  • Vue开发中常见的套路和技巧总结

    Vue开发中常见的套路和技巧总结

    这篇文章主要给大家介绍了关于Vue开发中常见的套路和技巧的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • vue3中使用logicFlow的方法代码示例

    vue3中使用logicFlow的方法代码示例

    在Vue3环境下,使用LogicFlow可实现流程图的绘制,详细步骤包括引入LogicFlow库,注册节点与边,设置主题和渲染数据,还包括使用Map和Menu进行功能扩展和右键编辑,以及通过事件监听实现交互,
    2024-10-10

最新评论