antv G6绘制流程图

发布于:2025-02-23 ⋅ 阅读:(20) ⋅ 点赞:(0)

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

代码:

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