阅读 345

我在G6关系图上用React画出了自定义节点

G6如果我不用默认图形的话,真的很难受,我只需要“亿点点”的addShape,数据绑定什么的?不存在的。

于是就有了这个库 @antv/g6-react-node,让你开发自定义节点像是开发react组件一样简单。我们支持了类似于Flex布局的自动布局,并且对事件定义精细到了shape级别,只要你会使用react,就会写G6的自定义节点。并且支持图形元素的组件级复用,让你开发图元素更加便捷。

安装

npm install --save @antv/g6-react-node
# or
yarn add @antv/g6-react-node
复制代码

推荐配合G6 4+使用,但是本插件也兼容G6 3.x版本。

用React定义节点

一、 定义节点keyshape,添加阴影

image.png 所有的React定义节点,我们都推荐用一个Group作为根节点来包裹。首先我们定义来这个节点的主要图形(keyshape)。

<Group>
      <Rect
        style={{
          radius: [8],
          fill: '#fff',
          shadowColor: '#ddd',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 2,
        }}
        keyshape
        draggable
      />
    </Group>
复制代码

二、 利用G的渐变方法给节点加一个标题区

image.png 我们在上一步的基础上,再次定义一个带渐变的header。这里内容涉及到了flex布局的小知识,用direction来让元素改变排列的方式,使用flex属性的空元素来让两边可以更好左对齐和右对齐。

<Group>
    <Rect
      style={{
        radius: [8],
        fill: '#fff',
        shadowColor: '#ddd',
        shadowBlur: 8,
        shadowOffsetX: 2,
        shadowOffsetY: 2,
      }}
      keyshape
      draggable
    >
      <Rect
        style={{
          minWidth: 200,
          fill: 'l(0) 0:#0049FF 1:#0EB7FF', //使用G的渐变定义fill
          radius: [8, 8, 0, 0],
          padding: 12,
          flexDirection: 'row',//内部元素水平排列
          cursor: 'pointer',
          alignContent: 'center',
        }}
      >
        <Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
        <Group style={{ flex: 1 }} /> // 通过flex 1的空Group来实现两个元素两端对齐
        <Circle
          style={{
            r: 5,
            fill: '#00CF10',
          }}
        />
      </Rect>
    </Rect>
  </Group>
复制代码

三、 在余下区域给节点取值来进行详细信息的补充

image.png 需要对不同节点的信息进行透出,那么你可以使用cfg,cfg是这个节点本身的model数据,你可以通过它来展示信息,甚至是控制渲染细节。

const Card = ({ cfg }) => {
  return (
    <Group>
      <Rect
        style={{
          radius: [8],
          fill: '#fff',
          shadowColor: '#ddd',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 2,
        }}
        keyshape
        draggable
      >
        <Rect
          style={{
            minWidth: 200,
            fill: 'l(0) 0:#0049FF 1:#0EB7FF',
            radius: [8, 8, 0, 0],
            padding: 12,
            flexDirection: 'row',
            cursor: 'pointer',
            alignContent: 'center',
          }}
        >
          <Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
          <Group style={{ flex: 1 }} />
          <Circle
            style={{
              r: 5,
              fill: '#00CF10',
            }}
          />
        </Rect>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Text style={{ fill: '#222', fontWeight: 'bold' }}>节点ID</Text>
          <Text style={{ fill: '#000', margin: [0, 4] }}>{cfg?.id}</Text>
        </Group>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Text style={{ fill: '#222', fontWeight: 'bold' }}>日志来源</Text>
          <Text style={{ fill: '#000', margin: [0, 4] }}>点击埋点数据源</Text>
        </Group>
      </Rect>
    </Group>
  );
};
复制代码

四、 定义组件让开发更加顺畅

image.png 我们支持来大部分组件的嵌套逻辑,这样就可以将一些相同的视觉元素绑定到一起,可以大幅度减少重复开发。在这里我们定义了一个Button组件来定义按钮组件。

const Button = ({ color = '#2D5AF6', children, onClick }) => (
  <Rect
    onClick={onClick}
    style={{
      padding: [4, 8],
      fill: color,
      margin: [0, 4],
      radius: 4,
      cursor: 'pointer',
    }}
  >
    <Text style={{ fill: '#fff', cursor: 'pointer' }} onClick={onClick}>
      {children}
    </Text>
  </Rect>
);

const Card = ({ cfg }) => {
  return (
    <Group>
      <Rect
        style={{
          radius: [8],
          fill: '#fff',
          shadowColor: '#ddd',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 2,
        }}
        keyshape
        draggable
      >
        <Rect
          style={{
            minWidth: 200,
            fill: 'l(0) 0:#0049FF 1:#0EB7FF',
            radius: [8, 8, 0, 0],
            padding: 12,
            flexDirection: 'row',
            cursor: 'pointer',
            alignContent: 'center',
          }}
        >
          <Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
          <Group style={{ flex: 1 }} />
          <Circle
            style={{
              r: 5,
              fill: '#00CF10',
            }}
          />
        </Rect>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Text style={{ fill: '#222', fontWeight: 'bold' }}>节点ID</Text>
          <Text style={{ fill: '#000', margin: [0, 4] }}>{cfg?.id}</Text>
        </Group>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Text style={{ fill: '#222', fontWeight: 'bold' }}>日志来源</Text>
          <Text style={{ fill: '#000', margin: [0, 4] }}>点击埋点数据源</Text>
        </Group>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Button>详情</Button>
          <Button color="#FF1313">停止</Button>
        </Group>
      </Rect>
    </Group>
  );
};
复制代码

五、组件上的事件绑定

image.png 我们将G6大部分事件进行了独立封装,可以基于shape来定义事件的触发,方便更直观的管理事件。

        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Button
            onClick={() => {
              alert(`你点击了${cfg.id}的详情`);
            }}
          >
            详情
          </Button>
          <Button
            onClick={() => {
              alert(`你点击了${cfg.id}的停止`);
            }}
            color="#FF1313"
          >
            停止
          </Button>
        </Group>

复制代码

在G6中使用React定义的节点

当你已经使用React定义了一个节点后,我们就可以使用G6来注册这个自定义节点了

import React from 'react';
import G6 from '@antv/g6';
import {
  Rect,
  Text,
  Circle,
  Image,
  Group,
  createNodeFromReact,
  appenAutoShapeListener,
} from '@antv/g6-react-node';

const Button = ({ color = '#2D5AF6', children, onClick }) => (
  <Rect
    onClick={onClick}
    style={{
      padding: [4, 8],
      fill: color,
      margin: [0, 4],
      radius: 4,
      cursor: 'pointer',
    }}
  >
    <Text style={{ fill: '#fff', cursor: 'pointer' }} onClick={onClick}>
      {children}
    </Text>
  </Rect>
);

const Card = ({ cfg }) => {
  return (
    <Group>
      <Rect
        style={{
          radius: [8],
          fill: '#fff',
          shadowColor: '#ddd',
          shadowBlur: 8,
          shadowOffsetX: 2,
          shadowOffsetY: 2,
        }}
        keyshape
        draggable
      >
        <Rect
          style={{
            minWidth: 200,
            fill: 'l(0) 0:#0049FF 1:#0EB7FF',
            radius: [8, 8, 0, 0],
            padding: 12,
            flexDirection: 'row',
            cursor: 'pointer',
            alignContent: 'center',
          }}
        >
          <Text style={{ fill: '#fff' }}>数据输入节点 - 日志源</Text>
          <Group style={{ flex: 1 }} />
          <Circle
            style={{
              r: 5,
              fill: '#00CF10',
            }}
          />
        </Rect>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Text style={{ fill: '#222', fontWeight: 'bold' }}>节点ID</Text>
          <Text style={{ fill: '#000', margin: [0, 4] }}>{cfg.id}</Text>
        </Group>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Text style={{ fill: '#222', fontWeight: 'bold' }}>日志来源</Text>
          <Text style={{ fill: '#000', margin: [0, 4] }}>点击埋点数据源</Text>
        </Group>
        <Group style={{ flexDirection: 'row', margin: [6, 12] }}>
          <Button
            onClick={() => {
              alert(`你点击了${cfg.id}的详情`);
            }}
          >
            详情
          </Button>
          <Button
            onClick={() => {
              alert(`你点击了${cfg.id}的停止`);
            }}
            color="#FF1313"
          >
            停止
          </Button>
        </Group>
      </Rect>
    </Group>
  );
};

G6.registerNode('test', createNodeFromReact(Card));

// 当你创建好Graph后,如果需要使用在节点内定义的事件

appenAutoShapeListener(graph)

复制代码
文章分类
前端