Echarts 与 G6实现拓扑图加上边动画,点的涟漪特效

1,955 阅读1分钟

1. Echarts版本

因为在vue中使用,也没使用vue-echarts插件,看了一下官网可以npm安装并且可以按需加载,我的demo是直接把所有全部引入,所以直接写了一个插件在vue中使用,所有动画的操作都可以在这个插件中写 我加了边箭头动画,结点涟漪动画 demo代码


import { init } from 'echarts'
import * as echarts from 'echarts'
// import Csys from '../tools/csys'
// console.log('csys', csys)
const install = function (Vue) {
  Object.defineProperties(Vue.prototype, {
    $chart: {
      get () {
        return {
          // 画拓扑图
          topologicalTravel: function (id, obj) {
            this.chart = init(document.getElementById(id))
            this.chart.clear()
            // console.log(obj.serviceNodeList.sort())
            // const pointData = [] // 点的位置的数组
            // const links = [] // links数组
            const coods = []
            console.log('coods', coods)
            // console.log('pointData', pointData)
            const data = [
              {
                name: '数据中心人员专题库',

                tooltip: {
                  formatter: '{b}: 19999<br />'
                },
                symbol: 'circle',
                symbolSize: [40, 40],
                value: [700, 400],
                x: 800,
                y: 400,
                fixed: true,
                // draggable: false,
                category: 1,
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                rippleEffect: { // 涟漪特效相关配置。
                  brushType: 'stroke' // 波纹的绘制方式,可选 'stroke' 和 'fill'。
                },
                hoverAnimation: true,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              },
              {
                name: '数据治理服务',
                x: 400,
                y: 400,
                value: [400, 400],
                fixed: true,
                symbol: 'circle',
                symbolSize: [35, 35],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                category: 1,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              },
              {
                name: 'OSM',
                x: 200,
                y: 200,
                value: [100, 200],

                fixed: true,
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133'
                },
                category: 1,

                itemStyle: {
                  normal: {
                    color: '#ffb402'
                  }
                }
              },
              {
                name: '人员专题库',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                value: [100, 500],

                x: 200,
                y: 500,
                fixed: true,
                category: 1,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              },
              {
                name: '人员专题库2',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                value: [300, 100],

                x: 300,
                y: 200,
                fixed: true,
                category: 2,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              },
              {
                name: '国家队',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                x: 1000,
                y: 300,
                value: [1000, 300],

                fixed: true,
                category: 1,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              },
              {
                name: '社会专家',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                value: [1000, 100],

                x: 1000,
                y: 100,
                fixed: true,
                category: 2,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              },
              {
                name: '志愿者',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                x: 1000,
                y: 200,
                value: [1000, 200],

                fixed: true,
                category: 2,
                itemStyle: {
                  normal: {
                    // borderColor: "#b457ff",
                    // borderWidth: 4,
                    // shadowBlur: 10,
                    // shadowColor: "#b457ff",
                    color: 'rgb(255, 197, 61)' // 黄色
                  }
                }
              },
              {
                name: '专职队',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                x: 1000,
                y: 400,
                value: [1000, 400],

                fixed: true,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                },
                category: 2
              },
              {
                name: '主机',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                x: 1000,
                y: 600,
                value: [1000, 600],

                fixed: true,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                },
                category: 2
              },
              {
                name: '自建',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                x: 600,
                y: 200,
                value: [600, 600],

                fixed: true,

                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                },
                category: 2
              },
              {
                name: '组织机构',
                symbol: 'circle',
                symbolSize: [30, 30],
                label: {
                  color: '#303133',
                  position: 'bottom'
                },
                value: [1000, 500],

                x: 1000,
                y: 500,
                fixed: true,
                category: 2,
                itemStyle: {
                  normal: {
                    color: '#157eff'
                  }
                }
              }
            ]
            const option = ({

              backgroundColor: '#fff',
              xAxis: {
                show: false,
                type: 'value'
              },
              yAxis: {
                show: false,
                type: 'value'
              },
              tooltip: {},
              series: [
                {
                  type: 'graph',
                  zlevel: 5,
                  draggable: false,
                  coordinateSystem: 'cartesian2d', // 使用二维的直角坐标系(也称笛卡尔坐标系)
                  symbol: 'rect',
                  // symbolOffset: ['15%', 0],
                  label: {
                    normal: {
                      show: true
                    }
                  },
                  data: data,
                  links: [
                    {
                      source: '数据治理服务',
                      target: '数据中心人员专题库'
                    },
                    {
                      source: 'OSM',
                      target: '数据治理服务',
                      symbol: ['none', 'arrow'],
                      label: {
                        show: true,
                        formatter: '×',
                        padding: [0, 0, -13, 0],
                        fontSize: 20
                      },
                      lineStyle: {
                        color: 'red'
                      }
                    },
                    {
                      source: '人员专题库',
                      target: '数据治理服务',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },
                    {
                      source: '数据中心人员专题库',
                      target: '社会专家',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },

                    {
                      source: '数据中心人员专题库',
                      target: '志愿者',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },

                    {
                      source: '数据中心人员专题库',
                      target: '国家队',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },

                    {
                      source: '数据中心人员专题库',
                      target: '专职队'
                      // lineStyle: {
                      //   normal: {
                      //     color: "#12b5d0",
                      //
                      //   }
                      // }
                    },
                    {
                      source: '数据中心人员专题库',
                      target: '组织机构',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },
                    {
                      source: '数据中心人员专题库',
                      target: '主机',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },
                    {
                      source: '自建',
                      target: '数据中心人员专题库',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    },
                    {
                      source: '数据中心人员专题库',
                      target: '人员专题库2',
                      lineStyle: {
                        normal: {
                          // color: "#12b5d0",
                        }
                      }
                    }
                  ],
                  // links: links,

                  lineStyle: {
                    normal: {
                      opacity: 1,
                      color: '#53B5EA',
                      curveness: 0.2,
                      width: 2
                    }
                  }
                },
                {
                  type: 'effectScatter',
                  coordinateSystem: 'cartesian2d',
                  data: data, // 2d坐标系
                  symbolSize: 0,
                  showEffectOn: 'render',
                  rippleEffect: {
                    brushType: 'stroke'
                  },
                  hoverAnimation: true,
                  itemStyle: {
                    normal: {
                      color: 'red',
                      shadowBlur: 10,
                      shadowColor: '#333'
                    }
                  },
                  zlevel: 1
                },
                {
                  type: 'lines',
                  coordinateSystem: 'cartesian2d',
                  z: 1,
                  zlevel: 2,
                  animation: false,
                  effect: {
                    show: true,
                    period: 5,
                    trailLength: 0.01,
                    symbolSize: 12,
                    symbol: 'arrow',
                    loop: true,
                    color: 'rgba(55,155,255,0.5)'
                  },
                  lineStyle: {
                    normal: {
                      color: '#22AC38',
                      width: 0,
                      curveness: 0.2
                    }
                  },

                  data: [
                    {
                      coords: [
                        [100, 200],
                        [200, 300]
                      ]
                    },
                    {
                      coords: [
                        [100, 500],
                        [400, 400]
                      ]
                    },
                    {
                      coords: [
                        [400, 400],
                        [700, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 100]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 200]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 300]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 500]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 600]
                      ]
                    },
                    {
                      coords: [
                        [600, 600],
                        [700, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [300, 100]
                      ]
                    }
                  ]
                },
                {
                  type: 'lines',
                  coordinateSystem: 'cartesian2d',
                  z: 1,
                  zlevel: 2,
                  animation: false,
                  effect: {
                    show: true,
                    period: 6,
                    trailLength: 0.01,
                    symbolSize: 12,
                    symbol: 'arrow',
                    loop: true,

                    // period: 2.5,
                    // trailLength:0,
                    // symbolSize: 12,
                    // symbol: "circle",
                    color: 'rgba(55,155,255,0.5)'
                  },
                  lineStyle: {
                    normal: {
                      color: '#22AC38',
                      width: 0,
                      curveness: 0.2
                    }
                  },

                  data: [
                    {
                      coords: [
                        [100, 200],
                        [400, 400]
                      ]
                    },
                    {
                      coords: [
                        [100, 500],
                        [400, 400]
                      ]
                    },
                    {
                      coords: [
                        [400, 400],
                        [700, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 100]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 200]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 300]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 500]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 600]
                      ]
                    },
                    {
                      coords: [
                        [600, 600],
                        [700, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [300, 100]
                      ]
                    }
                  ]
                },
                {
                  type: 'lines',
                  coordinateSystem: 'cartesian2d',
                  z: 1,
                  zlevel: 2,
                  animation: false,

                  effect: {
                    show: true,
                    period: 8,
                    trailLength: 0.01,
                    symbolSize: 12,
                    symbol: 'arrow',
                    loop: true,

                    // period: 2.5,
                    // trailLength:0,
                    // symbolSize: 12,
                    // symbol: "circle",
                    color: 'rgba(55,155,255,0.5)'
                  },
                  lineStyle: {
                    normal: {
                      color: '#22AC38',
                      width: 0,
                      curveness: 0.2
                    }
                  },

                  data: [
                    {
                      coords: [
                        [100, 200],
                        [400, 400]
                      ]
                    },
                    {
                      coords: [
                        [100, 500],
                        [400, 400]
                      ]
                    },
                    {
                      coords: [
                        [400, 400],
                        [700, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 100]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 200]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 300]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 500]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [1000, 600]
                      ]
                    },
                    {
                      coords: [
                        [600, 600],
                        [700, 400]
                      ]
                    },
                    {
                      coords: [
                        [700, 400],
                        [300, 100]
                      ]
                    }
                  ]
                }
              ]
            })
            this.chart.setOption(option)
            this.chart.on('click', (params) => {
              console.log('params', params)
            })
          },
          // 拓扑图2
          topolog (id) {
            this.chart = init(document.getElementById(id))
            this.chart.clear()

            // 节点图标
            const nodeDataList = [{
              name: '块1-1', // 节点名
              linkTargetName: '节点B', // 连线目标节点
              linkValue: ' ', // 连线介绍
              coordConfig: {
                level: '0-error',
                effect: {
                  show: true,
                  smooth: false,
                  trailLength: 0,
                  symbol: 'circle',
                  color: '#fb3f3f',
                  symbolSize: 10,
                  period: 3,
                  delay: 1500,
                  loop: true
                },
                lineStyle: {
                  normal: {
                    curveness: 0,
                    color: '#fb3f3f',
                    width: 1.4
                  }
                }
              }, // 连线动态箭头配置,没有就不需要此配置
              value: [10, 190],
              draggable: false,
              fixed: true,
              symbol: 'circle',
              symbolSize: 40,
              itemStyle: {
                color: '#fb3f3f'
              }
            },
            {
              name: '块1-2',
              linkTargetName: '节点B',
              linkValue: ' ',
              coordConfig: {
                level: '0'
              },
              value: [10, 150],
              draggable: false,
              fixed: true,
              symbol: 'circle',
              symbolSize: 40
            }, {
              name: '块2',
              linkTargetName: '节点C',
              linkValue: ' ',
              coordConfig: {
                level: '0'
              },
              value: [10, 100],
              draggable: false,
              fixed: true,
              symbol: 'circle',
              symbolSize: 40
            }, {
              name: '块3',
              linkTargetName: '节点D',
              linkValue: ' ',
              coordConfig: {
                level: '0'
              },
              value: [10, 40],
              draggable: false,
              symbol: 'circle',
              symbolSize: 40
            },
            // 节点B,C,D ....n
            {
              name: '节点B',
              linkTargetName: '应用端',
              linkValue: ' ',
              coordConfig: {
                level: '1'
              },
              symbol: 'circle',
              symbolSize: 50,
              draggable: false,
              value: [220, 160]
            }, {
              name: '节点C',
              linkTargetName: '应用端',
              linkValue: ' ',
              coordConfig: {
                level: '1'
              },
              symbol: 'circle',
              symbolSize: 60,
              draggable: false,
              value: [220, 100]
            }, {
              name: '节点D',
              linkTargetName: '应用端',
              linkValue: ' ',
              coordConfig: {
                level: '1'
              },
              symbol: 'circle',
              symbolSize: 60,
              draggable: false,
              value: [220, 40]
            }, {
              name: '应用端',
              linkTargetName: '应用端',
              linkValue: ' ',
              // coordConfig: {level: 2},
              symbolSize: 60,
              symbol: 'circle',
              draggable: false,
              value: [400, 100]
            }
            ]

            const getCoordDataList = function () {
              const coorDataDict = {}
              const defaultConfig = {
                type: 'lines', // 块1,2...n到节点A,B...N
                coordinateSystem: 'cartesian2d',
                // animationDelay: 10000,
                z: 1,
                effect: {
                  show: true,
                  smooth: true,
                  trailLength: 0,
                  symbol: 'arrow',
                  color: '#67c23a',
                  symbolSize: 10,
                  period: 3,
                  delay: 1500,
                  loop: true
                },
                lineStyle: {
                  normal: {
                    curveness: 0,
                    color: '#67c23a',
                    width: 1
                  }
                },
                data: []
              }
              nodeDataList.map(item => {
                if (item.coordConfig !== undefined) {
                  if (!(item.coordConfig.level in coorDataDict)) {
                    const coorConfig = JSON.parse(JSON.stringify(defaultConfig))
                    if (item.coordConfig.lineStyle !== undefined) {
                      coorConfig.lineStyle = item.coordConfig.lineStyle
                    }
                    if (item.coordConfig.effect !== undefined) {
                      coorConfig.effect = item.coordConfig.effect
                    }
                    coorDataDict[item.coordConfig.level] = coorConfig
                  }

                  const coordData = [
                    item.value,
                    nodeDataList.filter(i => i.name === item.linkTargetName)[0].value
                  ]
                  coorDataDict[item.coordConfig.level].data.push({
                    coords: coordData
                  })
                  if (item.coordConfig.bilateral) {
                    coorDataDict[item.coordConfig.level].data.push({
                      coords: coordData.reverse()
                    })
                  }
                }
              })
              return Object.values(coorDataDict)
            }

            console.log(getCoordDataList())

            const option = {
              title: {
                text: 'MySQL应用架构拓扑图',
                top: 'top',
                left: 'center'
              },
              itemStyle: {
                normal: {
                  color: '#67C23A'
                },
                shadowBlur: 0
              },
              textStyle: {
                color: '#444',
                fontSize: 16,
                fontWeight: 600
              },
              // legend: [{
              //   formatter: function (name) {
              //     return echarts.format.truncateText(name, 200, '12px', '…')
              //   },
              //   tooltip: {
              //     show: true
              //   },
              //   selectedMode: 'false',
              //   bottom: 20
              // }],
              // animationDuration: 500,
              // animationEasingUpdate: 'quinticInOut',
              xAxis: {
                show: false,
                type: 'value'
              },
              yAxis: {
                show: false,
                type: 'value'
              },
              series: [{
                type: 'graph',
                coordinateSystem: 'cartesian2d',
                // legendHoverLink: false,
                // hoverAnimation: true,
                // nodeScaleRatio: false,
                // 建头
                edgeSymbol: ['circle', 'none'],
                edgeSymbolSize: [2, 15],
                edgeLabel: {
                  show: false,
                  normal: {
                    show: true,
                    position: 'middle',
                    textStyle: {
                      fontSize: 12
                    },
                    formatter: '{c}'
                  }
                },
                // focusNodeAdjacency: true,
                roam: false,
                // 圆形上面的文字
                label: {
                  normal: {
                    position: 'bottom',
                    show: true,
                    textStyle: {
                      fontSize: 12
                    }
                  }
                },
                itemStyle: {
                  normal: {
                    color: '#409eff'
                  },
                  shadowBlur: 0
                },
                lineStyle: {
                  normal: {
                    width: 0,
                    shadowColor: 'none',
                    color: '#ff0000'
                  }
                },
                data: nodeDataList,

                links: nodeDataList.map(item => {
                  return {
                    source: item.name,
                    value: item.linkValue,
                    target: item.targetName
                  }
                })
              }].concat(getCoordDataList())
            }
            this.chart.setOption(option)
          },
          // click事件

          chartsClick (id) {
            document.getElementById(id).addEventListener('click', (params) => {
              console.log('params', params)
            })
          }
        }
      }
    }
  })
}

export default {
  install
}

2. Antv G6

本来想使用Echarts就可以完成任务了,但是没想到的是,当把数据引入发现当结点动态的时候,每一个结点的坐标很难处理,导致画出来的图非常丑,然后使用AntV 的G6关系图,然后自定义自己需要的特效,demo中实现了涟漪特效,边动画,文字截取,虚线边。不过代码量有点大。

const container = document.getElementById('mountNode')
    const width = container.scrollWidth
    const height = container.scrollHeight || 500
    // let legendDiv = document.createElement('div')
    // 自定义tooltip
    const tooltip = new G6.Tooltip({
      // offsetX and offsetY include the padding of the parent container
      // offsetX 与 offsetY 需要加上父容器的 padding
      offsetX: 10,
      offsetY: 10,
      // the types of items that allow the tooltip show up
      // 允许出现 tooltip 的 item 类型
      itemTypes: ['node', 'edge'],
      // custom the tooltip's content
      // 自定义 tooltip 内容
      getContent: (e) => {
        // console.log('e', e)
        const outDiv = document.createElement('div')
        outDiv.style.width = 'fit-content'
        outDiv.style.height = 'fit-content'
        outDiv.style.textAlign = 'justify'
        const model = e.item.getModel()
        // console.log('model', model)
        if (e.item.getType() === 'node') {
          outDiv.innerHTML = `记录数:${model.logNumber}</br> 耗时:${model.costTime}</br> 系统: ${model.systemName}</br> 服务: ${model.serviceName}`
        } else {
          // console.log('model', model)
          // outDiv.style.display = 'none'
          outDiv.innerHTML = `原点:${model.source}, \n 终点:${model.target}`
        }
        return outDiv
      }
    })
    // Background Animation 背景特效
    G6.registerNode('background-animate', {
      afterDraw (cfg, group) {
        let r = cfg.size / 2
        if (isNaN(r)) {
          r = cfg.size[0] / 2
        }
        // 第一个背景圆
        const back1 = group.addShape('circle', {
          zIndex: -3,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: cfg.color,
            opacity: 0.6
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: 'circle-shape1'
        })
        // 第二个背景圆
        const back2 = group.addShape('circle', {
          zIndex: -2,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: '#4592FF', // 为了显示清晰,随意设置了颜色
            opacity: 0.6
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: 'circle-shape2'
        })
        // 第三个背景圆
        const back3 = group.addShape('circle', {
          zIndex: -1,
          attrs: {
            x: 0,
            y: 0,
            r,
            fill: '#52D5CC',
            opacity: 0.6
          },
          // must be assigned in G6 3.3 and later versions. it can be any value you want
          name: 'circle-shape3'
        })
        group.sort() // 排序,根据 zIndex 排序

        // 第一个背景圆逐渐放大,并消失
        back1.animate({
          r: r + 10,
          opacity: 0.1
        }, {
          repeat: true, // 循环
          duration: 3000,
          easing: 'easeCubic',
          delay: 0 // 无延迟
        })

        // 第二个背景圆逐渐放大,并消失
        back2.animate({
          r: r + 10,
          opacity: 0.1
        }, {
          repeat: true, // 循环
          duration: 3000,
          easing: 'easeCubic',
          delay: 1000 // 1 秒延迟
        }) // 1 秒延迟

        // 第三个背景圆逐渐放大,并消失
        back3.animate({
          r: r + 10,
          opacity: 0.1
        }, {
          repeat: true, // 循环
          duration: 3000,
          easing: 'easeCubic',
          delay: 2000 // 2 秒延迟
        })
      }
    }, 'circle')
    // 边的动画特效
    G6.registerEdge('circle-running', {
      afterDraw (cfg, group) {
        // get the first shape in the group, it is the edge's path here=
        // console.log('group', group)
        const shape = group.get('children')[0]
        // the start position of the edge's path
        const startPoint = shape.getPoint(0)

        // add red circle shape
        const circle = group.addShape('circle', {
          attrs: {
            x: startPoint.x,
            y: startPoint.y,
            fill: 'rgba(82,213,204,0.54)',
            r: 3
          },
          name: 'circle-shape'
        })

        // animation for the red circle
        circle.animate(
          (ratio) => {
            // the operations in each frame. Ratio ranges from 0 to 1 indicating the prograss of the animation. Returns the modified configurations
            // get the position on the edge according to the ratio
            const tmpPoint = shape.getPoint(ratio)
            // returns the modified configurations here, x and y here
            return {
              x: tmpPoint.x,
              y: tmpPoint.y
            }
          },
          {
            repeat: true, // Whether executes the animation repeatly
            duration: 3000 // the duration for executing once
          }
        )
      }
    },
    'cubic' // extend the built-in edge 'cubic'
    )
    const lineDash = [4, 2, 1, 2]
    // 线的特效
    G6.registerEdge('line-dash', {
      afterDraw (cfg, group) {
        // get the first shape in the group, it is the edge's path here=
        const shape = group.get('children')[0]
        let index = 0
        // Define the animation
        shape.animate(
          () => {
            index++
            if (index > 9) {
              index = 0
            }
            const res = {
              lineDash,
              lineDashOffset: -index
            }
            // returns the modified configurations here, lineDash and lineDashOffset here
            return res
          },
          {
            repeat: true, // whether executes the animation repeatly
            duration: 3000 // the duration for executing once
          }
        )
      }
    },
    'cubic' // extend the built-in edge 'cubic'
    )
    const graph = new G6.TreeGraph({
      container: 'mountNode',
      width,
      height,
      plugins: [tooltip],
      modes: {
        default: [
          {
            type: 'collapse-expand',
            onChange: function onChange (item, collapsed) {
              const data = item.get('model').data
              data.collapsed = true
              return true
            }
          },
          'drag-canvas',
          'zoom-canvas'
        ]
      },
      defaultEdge: {
        type: 'circle-running',
        size: 1,
        style: {
          radius: 0,
          offset: 10,
          endArrow: true,
          lineWidth: 0.5,
          /* and other styles */
          stroke: '#B2B2B2'
        }
      },
      layout: {
        type: 'mindmap',
        direction: 'H',
        getHeight: () => {
          return 60
        },
        getWidth: () => {
          return 50
        },
        getVGap: () => {
          return 30
        },
        getHGap: () => {
          return 80
        }
      }
    })

    // 结点位置
    let centerX = 0
    graph.node(function (node) {
      if (node.id === 'Z') {
        centerX = node.x
      }

      // 记录数、节点耗时、系统名称、服务名称
      return {
        // label: `${fittingString(node.label, 140, 12)}`,
        label: `${node.label}`,
        labelCfg: {
          fontSize: 14,
          position:
              node.children && node.children.length > 0
                ? node.id === 'Z' ? 'left' : 'bottom'
                : node.x > centerX
                  ? 'right'
                  : 'left',
          offset: 10
        }
      }
    })
    graph.data(nodeData[0])
    graph.render()
    graph.fitView()
    if (typeof window !== 'undefined') {
      window.onresize = () => {
        if (!graph || graph.get('destroyed')) return
        if (!container || !container.scrollWidth || !container.scrollHeight) return
        graph.changeSize(container.scrollWidth, container.scrollHeight)
      }
    }

3. 自己记录一下自己实现的东西。