antv G6绘制流程图

效果图(优点:可以自定义每一条折线的颜色,可以自定义节点的颜色,以及折线的计算样式等):

代码:

html 复制代码
<!-- 流程图组件 -->
<template>
  <div id="container"></div>
</template>

<script setup lang="ts">
import {watch, reactive, toRefs, nextTick, ref, onBeforeUnmount} from "vue";
import {Graph} from "@antv/g6";
import RuleCommonUtil from "../utils/RuleCommonUtil";
import GlobalConst from "../utils/GlobalConst";
import DictConst from "../enums/DictConst";

const dataValue: any = reactive({
  nodes: [
    // {
    //   id: "dom2",
    //   data: {label: "dom2", width: 60, height: 100},
    //   style: {x: 50, y: 100, width: 100, height: 50},
    // },
    // {
    //   id: "dom3",
    //   data: {label: "dom3", width: 60, height: 100},
    //   style: {x: 150, y: 100, width: 100, height: 50},
    // },
    // {
    //   id: "dom4",
    //   data: {label: "dom4", width: 60, height: 100},
    //   style: {x: 250, y: 100, width: 100, height: 50},
    // },
    // {
    //   id: "dom5",
    //   data: {label: "dom5", width: 50, height: 100},
    //   style: {x: 350, y: 100, width: 100, height: 50},
    // },
  ],
  edges: [
    // {id: "dom2->dom3", source: "dom2", target: "dom3"},
    // {id: "dom3->dom4", source: "dom3", target: "dom4"},
    // {id: "dom4->dom5", source: "dom4", target: "dom5"},
    // {
    //   id: "dom1->dom5",
    //   source: "dom2",
    //   target: "dom5",
    //   style: {
    //     controlPoints: [
    //       [50, 180], // [起始点x轴 ,起始点y轴+要高出部分的]
    //       [350, 180], // [目标点x轴 ,目标点y轴+要高出部分的]
    //     ],
    //   },
    // },
    // {
    //   id: "dom1->dom4",
    //   source: "dom2",
    //   target: "dom4",
    //   style: {
    //     controlPoints: [
    //       [50, 180], // [起始点x轴 ,起始点y轴+要高出部分的]
    //       [250, 180], // [目标点x轴 ,目标点y轴+要高出部分的]
    //     ],
    //   },
    // },
  ],
});
// 新增:声明图表实例引用
const graphInstance = ref<any>(null);
const props = defineProps({
  nodeList: {
    type: Array,
    default: () => [],
  },
  process: {
    type: Object,
    default: () => ({}),
  },
});
const {nodeList, process} = toRefs(props);
// 新增:组件卸载时自动销毁图表
onBeforeUnmount(() => {
  destroyGraph();
});

watch(
  () => nodeList.value,
  (newValue) => {
    nextTick(async () => {
      if (newValue) {
        setNodes();
        setEdges();
        await initDataList();
      } else {
        destroyGraph();
      }
    });
  },
  {
    deep: true,
    immediate: true,
  },
);
// 新增:销毁图表的方法
const destroyGraph = () => {
  if (graphInstance.value) {
    graphInstance.value.destroy(); // 销毁图表实例
    graphInstance.value = null;
  }
};
const initDataList = () => {
  // 销毁旧实例
  destroyGraph();
  // 创建新实例
  graphInstance.value = new Graph({
    container: document.getElementById("container") as any,
    autoFit: "center",
    data: dataValue,
    behaviors: [
      "zoom-canvas", // 保留缩放功能
      "drag-canvas", // 保留画布拖拽功能
      // "drag-node"     // 移除或不启用拖拽节点的行为
    ],
    node: {
      type: "rect",
      style: {
        size: (d: any) => [d.data.width, d.data.height] as any,
        radius: 10,
        iconText: (d: any) => d.data.label as any,
        iconFontSize: 10,
      },
      palette: {
        type: "group",
        field: "label",
      },
    },
    edge: {
      type: "polyline",
      style: {
        stroke: (d: any) => d.color as any,
        lineWidth: 2,
        lineAppendWidth: 8, // 加宽线宽度
        endArrow: {
          // path: Arrow.triangle(10, 10, 2), // 使用导入的箭头路径
          // fill: "#18c298ad", // 填充颜色
        } as any,
        offset: 20, // 设置箭头偏移
      },
    },
    plugins: [
      {
        type: "tooltip",
        getContent: (_event: any, items: any) => {
          return `<span>${items[0]?.logicNode}</span>`;
        },
      },
    ],
  });
  graphInstance.value.render();
};
const setNodes = () => {
  dataValue.nodes = nodeList.value.map((item: any, index: number) => {
    return {
      id: `${item.seq}`,
      data: {label: item?.taskName || "--", width: 80, height: 100},
      logicNode: item?.taskName || "--",
      style: {
        x: 50 + index * 150,
        y: 100,
        width: 100,
        height: 50,
        fill: "#3761f5", // 或者你可以设置为一个统一颜色,比如 "#FFFFFF"
        stroke: "#f0f0f0", // 设置边框颜色 (黑色)
        lineWidth: 2, // 设置边框宽度
        radius: 10, // 如果你希望有圆角,可以保持这一行
        color: "#6c8bf7",
      },
    };
  });
};
const setEdges = () => {
  const list: any = nodeList.value;
  const aaa = list.map((item: any, index: number) => {
    if (list[index + 1]) {
      return {
        id: `${item.seq}->${list[index + 1].seq}`,
        logicNode: setTooltip(
          item.taskConditionList.find((c: any) => list[index + 1].taskCode === c.targetTaskCode)
            ?.logicNode || {},
        ),
        source: `${item.seq}`,
        target: `${list[index + 1].seq}`,
        color: "#41d89f",
      };
    }
  });
  dataValue.edges = aaa.filter((item: any) => item);
  relationship();
};
// 计算非直连的节点关系表
const relationship = () => {
  let topArrow: number[] = [];
  const list: any = nodeList.value;
  //先过滤出有条件的节点
  const subset = list.filter(
    (item: any) => item?.taskConditionList && item?.taskConditionList.length > 0,
  );
  let subsetlength = subset.length || 0;

  subset.forEach((item: any, index: number) => {
    item.taskConditionList.forEach((v: any) => {
      // 目标节点
      const objIndex = list.findIndex((vv: any) => vv.taskCode === v.targetTaskCode);
      const obj = list.find((vv: any) => vv.taskCode === v.targetTaskCode);
      if (obj && objIndex > -1 && item.seq + 1 !== obj.seq) {
        dataValue.edges.push({
          id: `${item.seq}->${v.targetTaskCode}`,
          source: `${item.seq}`,
          target: `${obj.seq}`,
          logicNode: setTooltip(v?.logicNode || {}),
          // color: item.seq >= 1 ? "#1783ff" : "#41d89f", //设置线条颜色
          color: "#41d89f",
          style: {
            controlPoints: [
              [
                50 + (item.seq - 1) * 150,
                topArrow.includes(item.seq)
                  ? 100 +
                    ((topArrow.indexOf(item.seq) + 1) * 80) /
                      (topArrow.indexOf(item.seq) + 1 > 1 ? 1.5 : 1)
                  : 100 - ((index + 1) * 80) / (index + 1 > 1 ? 1.5 : 1),
              ], // [起始点x轴 ,起始点y轴+要高出部分的]
              [
                50 + objIndex * 150,
                topArrow.includes(item.seq)
                  ? 100 +
                    ((topArrow.indexOf(item.seq) + 1) * 80) /
                      (topArrow.indexOf(item.seq) + 1 > 1 ? 1.5 : 1)
                  : 100 - ((index + 1) * 80) / (index + 1 > 1 ? 1.5 : 1),
              ], // [目标点x轴 ,目标点y轴+要高出部分的]
            ],
          },
        });
        topArrow.push(obj.seq);
      }
    });
    subsetlength--;
  });
};

//动态设置线条的tooltip
const setTooltip = (logicNode: any) => {
  
  return "1111";
};
</script>
相关推荐
故事不长丨1 小时前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
源心锁1 小时前
👋 手搓 gzip 实现的文件分块压缩上传
前端·javascript
哈库纳玛塔塔1 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
phltxy2 小时前
从零入门JavaScript:基础语法全解析
开发语言·javascript
Kagol2 小时前
JavaScript 中的 sort 排序问题
前端·javascript
天“码”行空3 小时前
java面向对象的三大特性之一多态
java·开发语言·jvm
cos4 小时前
Fork 主题如何更新?基于 Ink 构建主题更新 CLI 工具
前端·javascript·git
odoo中国4 小时前
Odoo 19 模块结构概述
开发语言·python·module·odoo·核心组件·py文件按
代码N年归来仍是新手村成员4 小时前
【Java转Go】即时通信系统代码分析(一)基础Server 构建
java·开发语言·golang
Z1Jxxx5 小时前
01序列01序列
开发语言·c++·算法