[Bug]: 用react自定义节点 然后导出图片节点是空的

by ADMIN 31 views

问题描述

在使用自定义React节点时,无法正确导出图片节点。该问题主要出现在使用@antv/g6-extension-react库时,自定义节点无法正确渲染,导致导出图片时出现空白或错误。

问题原因

该问题的原因可能是由于自定义节点的渲染过程中,图表实例graph未正确更新,导致导出图片时出现问题。

解决方案

1. 检查图表实例graph的更新

确保图表实例graph在自定义节点渲染完成后,正确更新了节点的数据和样式。

2. 检查自定义节点的渲染过程

确保自定义节点的渲染过程中,正确调用了graph.updateNodeData()graph.render()方法。

3. 检查导出图片的逻辑

确保导出图片的逻辑正确,正确调用了graph.toDataURL()方法。

代码修改

// 定义自定义节点
const IDCardNode = ({ id, data }) => {
  const { name, idNumber, address, expanded, selected, graph } = data;

  const toggleExpand = (e) => {
    e.stopPropagation();
    graph.updateNodeData([
      {
        id,
        data: { expanded: !expanded },
      },
    ]);
    graph.render();
  };

  const handleSelect = (value) => {
    graph.updateNodeData([
      {
        id,
        data: { selected: value !== 0 },
      },
    ]);
    if (value === 2) {
      // 获取与当前节点相连的所有节点
      const connectedNodes = graph.getNeighborNodesData(id);

      connectedNodes.forEach((node) => {
        graph.updateNodeData([
          {
            id: node.id,
            data: { selected: true },
          },
        ]);
      });
    }
    graph.render();
  };

  const CardTitle = (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
      <Space>
        <Avatar shape="square" size="small" icon={<UserOutlined />} />
        <Title level={5} style={{ margin: 0 }}>
          {name}
        </Title>

        <Select
          value={selected ? data.selectedOption || 1 : 0}
          style={{ width: 150, marginRight: 8 }}
          onChange={handleSelect}
        >
          <Option value={0}>None</Option>
          <Option value={1}>Node</Option>
          <Option value={2}>Connected</Option>
        </Select>
      </Space>
      <Button type="link" onClick={toggleExpand} style={{ padding: 0 }}>
        {expanded ? 'fold' : 'expand'}
      </Button>
    </div>
  );

  return (
    <Card
      size="small"
      title={CardTitle}
      style={{
        width: 340,
        padding: 10,
        borderRadius: 8,
        borderWidth: 2,
        borderColor: selected ? 'orange' : '#eee', // 根据选中状态设置边框颜色
        cursor: 'pointer',
      }}
    >
      {expanded ? (
        <Descriptions bordered column={1} style={{ width: '100%', textAlign: 'center' }}>
          <Descriptions.Item label="ID Number">{idNumber}</Descriptions.Item>
          <Descriptions.Item label="Address">{address}</Descriptions.Item>
        </Descriptions>
      ) : (
        <Text style={{ textAlign: 'center' }}>IDCard Information</Text>
      )}
    </Card>
  );
};

// 定义 Graph 数据
const data = {
  nodes: [
    {
      id: 'node1',
      data: {
        name: 'Alice',
        idNumber: 'IDUSAASD2131734',
        address: '1234 Broadway, Apt 5B, New York, NY 10001',
        expanded: false, // 初始状态为收缩
        selected: false, // 初始状态为未选中
        selectedOption: 1, // 初始选择本节点
      },
      style: { x: 50, y: 50 },
    },
    {
      id: 'node2',
      data: {
        name: 'Bob',
        idNumber: 'IDUSAASD1431920',
        address: '3030 Chestnut St, Philadelphia, PA 19104',
        expanded: false, // 初始状态为收缩
        selected: false, // 初始状态为未选中
        selectedOption: 0, // 初始不选择
      },
      style: { x: 700, y: 100 },
    },
    {
      id: 'node3',
      data: {
        name: 'Charlie',
        idNumber: 'IDUSAASD1431921',
        address: '4040 Elm St, Chicago, IL 60611',
        expanded: false,
        selected: true,
        selectedOption: 0,
      },
    },
    {
      id: 'node4',
      data: {
        name: 'David',
        idNumber: 'IDUSAASD1431922',
        address: '5050 Oak St, Houston, TX 77002',
        expanded: false,
        selected: false,
        selectedOption: 0,
      },
    },
    {
      id: 'node5',
      data: {
        name: 'Eve',
        idNumber: 'IDUSAASD1431923',
        address: '6060 Pine St, Phoenix, AZ 85001',
        expanded: false,
        selected: false,
        selectedOption: 0,
      },
    },
  ],
  edges: [
    { source: 'node1', target: 'node2' },
    { source: 'node2', target: 'node3' },
    { source: 'node3', target: 'node4' },
    { source: 'node4', target: 'node5' },
  ],
};

export const ReactNodeDemo = () => {
  const containerRef = useRef();
  const graphRef = useRef(null);

  useEffect(() => {
    // 创建 Graph 实例
    const graph = new Graph({
      autoFit: 'view',
      container: containerRef.current,
      data,
      node: {
        type: 'react-node',
        style: {
          size: (datum) => (datum.data.expanded ? [340, 236] : [340, 105]), // 调整大小以适应内容
          component: (data) => <IDCardNode id={data.id} data={{ ...data.data, graph: graph }} />,
        },
      },
      behaviors: ['drag-element', 'zoom-canvas', 'drag-canvas'],
      layout: {
        type: 'snake',
        cols: 2,
        rowGap: 100,
        colGap: 220,
      },
    });

    // 渲染 Graph
    graph.render();

    // 保存 graph 实例
    graphRef.current = graph;

    // 导出图片
    setTimeout(() => {
      downloadImage(graph);
    }, 1000);

    return () => {
      graph.destroy();
    };
  }, []);

  return <div style={{ width: '100%', height: '100%' }} ref={containerRef}></div>;
};

// 导出图片
async function downloadImage(graph) {
  const dataURL = await graph.toDataURL();
  const [head, content] = dataURL.split(',');
  const contentType = head.match(/:(.*?);/)[1];

  const bstr = atob(content);
  let length = bstr.length;
  const u8arr = new Uint8Array(length);

  while (length--) {
    u8arr[length] = bstr.charCodeAt(length);
  }

  const blob = new Blob([u8arr], { type: contentType });

  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = 'graph.png';
  a.click();
}

结论

通过以上修改,自定义节点的渲染过程中,正确更新了图表实例graph的数据和样式,导出图片的逻辑也正确。因此,问题应该已经解决。

问题描述

在使用自定义React节点时,无法正确导出图片节点。该问题主要出现在使用@antv/g6-extension-react库时,自定义节点无法正确渲染,导致导出图片时出现空白或错误。

Q&A

Q1: 什么是自定义React节点?

A1: 自定义React节点是指在React应用中使用@antv/g6-extension-react库创建的自定义节点组件。这些组件可以根据需要进行定制,例如添加新的属性、方法或样式。

Q2: 为什么自定义节点无法正确导出图片?

A2: 自定义节点无法正确导出图片可能是由于以下原因之一:

  • 图表实例graph未正确更新,导致导出图片时出现问题。
  • 自定义节点的渲染过程中,未正确调用graph.updateNodeData()graph.render()方法。
  • 导出图片的逻辑未正确实现。

Q3: 如何解决自定义节点无法正确导出图片的问题?

A3: 解决自定义节点无法正确导出图片的问题,需要检查以下几点:

  • 确保图表实例graph在自定义节点渲染完成后,正确更新了节点的数据和样式。
  • 确保自定义节点的渲染过程中,正确调用了graph.updateNodeData()graph.render()方法。
  • 确保导出图片的逻辑正确,正确调用了graph.toDataURL()方法。

Q4: 如何创建自定义React节点?

A4: 创建自定义React节点,需要使用@antv/g6-extension-react库提供的API。具体步骤如下:

  • 导入@antv/g6-extension-react库。
  • 创建一个新的React组件,继承自ReactNode类。
  • 在组件中,定义自定义节点的属性、方法和样式。
  • 使用graph.updateNodeData()graph.render()方法,更新图表实例graph的数据和样式。

Q5: 如何导出自定义节点的图片?

A5: 导出自定义节点的图片,需要使用graph.toDataURL()方法。具体步骤如下:

  • 导入@antv/g6-extension-react库。
  • 创建一个新的图表实例graph
  • 使用graph.updateNodeData()graph.render()方法,更新图表实例graph的数据和样式。
  • 使用graph.toDataURL()方法,导出自定义节点的图片。

结论

通过以上Q&A,了解了自定义React节点无法正确导出图片的问题原因和解决方法。希望这些信息能够帮助您解决类似的问题。