React使用@antv/g6绘制树形图

参考:

官网:@antv/g6
官网:React中使用@antv/g6
官网:使用dom自定义节点
⚠️ 注意: G6 的节点/边事件不支持 DOM 类型的图形。如果需要为 DOM 节点绑定事件,请使用原生 DOM 事件。例如:
官网:React中自定义节点

直接上代码

1、自定义边

const flowLine = {
  draw(cfg: any, group: any) {
    const startPoint = cfg.startPoint;
    const endPoint = cfg.endPoint;
    const sourceModel = cfg?.sourceNode?._cfg?.model;
    const targetModel = cfg?.targetNode?._cfg?.model;
    const path = [
          ['M', startPoint.x, startPoint.y - 20],
          ['L', startPoint.x, (startPoint.y + endPoint.y) / 2 + 8],
          ['L', endPoint.x, (startPoint.y + endPoint.y) / 2 + 8],
          ['L', endPoint.x, endPoint.y],
        ];

    const sourceSelected = sourceModel?.isAbnormal;
    const targetSelected = targetModel?.isAbnormal;
    const isSelected = !!sourceModel?.parentMetricNodeId
      ? targetSelected && sourceSelected
      : targetSelected;

    const shape = group.addShape('path', {
      attrs: {
        stroke: isSelected ? 'red' : '#cacaca',
        path,
      },
    });
    return shape;
  },  
}

2、自定义node

import React from 'react';
import { Rect, Text, Group } from '@antv/g6-react-node';
import { nullIf, toFixed, toPercentage } from '@/utils/tools';

interface Props {
  cfg: any;
}
export default function ParentChild({ cfg }: Props) {
  const { name, value, cycleValueDiff = 0, onClick } = cfg;

  return (
    <Group draggable>
      <Rect
        style={{
          width: 180,
          height: 'auto',
          fill: '#fff',
          shadowColor: '#ddd',
          shadowBlur: 4,
          radius: [4],
          justifyContent: 'center',
        }}
      >
        <Rect style={{ fill: '#FBEAEA' }}>
          <Text
            style={{
              fill: '#000',
              margin: [6, 12, 8, 14],
              fontSize: 14,
              fontWeight: 'bold',
            }}
          >
            {nullIf(name)}
          </Text>
          <Text style={{ fill: '#1890FF', fontSize: 18, margin: [0, 12, 6, 14] }}>
            {nullIf(value ? parseFloat(value) : null, { render: toFixed })}
          </Text>
        </Rect>
        <Rect
          style={{
            padding: [5, 0],
            width: 'auto',
            margin: [8, 14, 6, 14],
            flexDirection: 'row',
          }}
          onClick={onClick}
        >
          <Text style={{ fill: '#5F5F5F', fontSize: 14 }} onClick={onClick}>{`环比:`}</Text>
          <Text
            style={{ fill: '#E66060', fontSize: 14 }}
            onClick={onClick}
          >
            {nullIf(cycleValueDiff, { render: toPercentage })?.toString()}
          </Text>
        </Rect>
      </Rect>
    </Group>
  );
}

3、在组件里边使用

const graphRef = useRef<any>();

useEffect(() => {
    G6.registerNode('node-child', createNodeFromReact(<ParentChild />));
    G6.registerEdge('flow-line', flowLine);

    const container: any = document.getElementById('container');
    const width = container.scrollWidth;
    const height = container.scrollHeight || window.innerHeight;

    const cfg = getTreeGraphCofig({ width, height });
    const graph = new G6.TreeGraph(cfg);
    graphRef.current = graph;

    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);
      };
  }, []);

//加载渲染数据
const graph = graphRef.current;
    getIndicatorsTree(defaultParams).then((res) => {
      if (res?.data?.length > 0) {
        graph.data(res?.data?.[0]);
        graph.setMaxZoom(1);
        graph.render();
        graph.fitView([8, 16], { onlyOutOfViewPort: true, ratioRule: 'min' });
        // 添加事件
        appenAutoShapeListener(graph);
      }
    });

4、最终结果

image.png
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容