antv G6绘制流程图

news/2025/2/23 10:38:58

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

代码:

<!-- 流程图组件 -->
<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>


http://www.niftyadmin.cn/n/5863330.html

相关文章

前端面试-JavaScript 数据类型详解

目录 一、数据类型分类 二、核心区别对比 1. 存储方式 2. 比较方式 3. 类型检测方法 三、特殊类型详解 1. Symbol 2. BigInt 3. null vs undefined 四、常见面试扩展问题 五、总结 一、数据类型分类 JavaScript 数据类型分为 基本数据类型&#xff08;原始类型&…

hot100_74. 搜索二维矩阵

hot100_74. 搜索二维矩阵 思路 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。 每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否…

网络空间安全(2)应用程序安全

前言 应用程序安全&#xff08;Application Security&#xff0c;简称AppSec&#xff09;是一个综合性的概念&#xff0c;它涵盖了应用程序从开发到部署&#xff0c;再到后续维护的整个过程中的安全措施。 一、定义与重要性 定义&#xff1a;应用程序安全是指识别和修复应用程序…

二级公共基础之数据结构与算法篇(五)树和二叉树

目录 前言 一、树的基本概念 1.父结点和根节点 2.子节点和叶子节点 3.度和深度 4.子树 二、二叉树及其基本性质 1. 二叉树的定义 2. 二叉树的基本性质 性质1 性质2 性质3 性质4 性质5 性质6 三、二叉树的存储结构 四、二叉树的遍历 1.遍历二叉树的概念 1. 前…

基于ffmpeg+openGL ES实现的视频编辑工具-添加贴纸(八)

在当下丰富多元的音视频编辑应用领域,添加贴纸已然成为一项广受欢迎的功能,它能够为音视频作品注入独特的趣味与创意元素。本文将深入探究音视频添加贴纸背后所涉及的技术原理与实现路径。 一、技术原理概述 音视频从本质上来说,是由一系列连续的图像帧(针对视频部分)以…

排序链表--字节跳动

少年的书桌上没有虚度的光阴 题目描述 请你对链表进行排序 思路分析 核心思想&#xff1a;归并排序 有三个部分 链表排序实现 1. merge 函数 21.见 合并两个有序链表&#xff0c; 首先创建一个虚拟头节点 newhead&#xff0c;并使用指针 tail 来构建合并后的链表。 通过…

Windows安装MySQL教程

1.下载 下载地址&#xff1a;https://www.mysql.com/downloads/ 下载版本&#xff1a;MySQL Installer for Window 2.安装MySQL 以下只列出需要注意的一些界面&#xff0c;没出现的界面默认继续即可。 1.选择安装类型 提供了多种安装模式&#xff0c;包括默认开发版、仅…

高清下载油管视频到本地

下载工具并安装: yt-dlp官网地址&#xff1a; GitHub - yt-dlp/yt-dlp: A feature-rich command-line audio/video downloader ffmpeg官网地址&#xff1a; Download FFmpeg 注&#xff1a;记住为其添加环境变量 操作命令&#xff1a; 该指令表示以720p码率下载VIDEO_UR…