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绘制流程图内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • el-form-item表单label添加提示图标的实现

    el-form-item表单label添加提示图标的实现

    本文主要介绍了el-form-item表单label添加提示图标的实现,我们将了解El-Form-Item的基本概念和用法,及添加提示图标以及如何自定义图标样式,感兴趣的可以了解一下
    2023-11-11
  • vue图片压缩与批量上传方式

    vue图片压缩与批量上传方式

    文章介绍了使用Vue和Element UI的el-upload组件实现图片的批量上传和压缩功能,前端需引入image-conversion库并设置相关属性,关闭自动上传,通过on-change事件校验文件名和大小,并增加一个提交到服务器的按钮
    2025-01-01
  • 在Vue中使用HOC模式的实现

    在Vue中使用HOC模式的实现

    这篇文章主要介绍了在Vue中使用HOC模式的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • vue前端框架vueuse的useScroll函数使用源码分析

    vue前端框架vueuse的useScroll函数使用源码分析

    这篇文章主要为大家介绍了vueuse的useScroll函数源码分析详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • vue新手入门出现function () { [native code] }错误的解决方案

    vue新手入门出现function () { [native code]&nbs

    这篇文章主要介绍了vue新手入门出现function () { [native code] }错误的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • 5个实用的Vue技巧分享

    5个实用的Vue技巧分享

    在这篇文章中,我们将探讨五个实用的 Vue 技巧,这些技巧可以使你日常使用 Vue 编程更高效、更富有成效,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-08-08
  • Vue的混合继承详解

    Vue的混合继承详解

    这篇文章主要介绍了Vue的混合继承,有需要的朋友可以借鉴参考下,希望能够有所帮助,希望能够给你带来帮助
    2021-11-11
  • vue类名如何获取动态生成的元素

    vue类名如何获取动态生成的元素

    这篇文章主要介绍了vue类名如何获取动态生成的元素,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-04-04
  • Vue如何使用Element-ui表单发送数据与多张图片到后端详解

    Vue如何使用Element-ui表单发送数据与多张图片到后端详解

    在做项目的时候遇到一个问题,前端需要上传表单到后端,表单数据包括文本内容和图片,这篇文章主要给大家介绍了关于Vue如何使用Element-ui表单发送数据与多张图片到后端的相关资料,需要的朋友可以参考下
    2022-04-04
  • Vue判断数组内是否存在某一项的两种方法

    Vue判断数组内是否存在某一项的两种方法

    这篇文章主要介绍了Vue判断数组内是否存在某一项,今天给大家分享两种方法,分别是findIndex()和 indexOf()方法,本文结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-07-07

最新评论