如果还有更简单的实现,欢迎指教。
概览
实现
step1: 依赖安装
npm i @ant-design/graphs
// OR
yarn add @ant-desing/graphs
step2: 组件实现,为了不占用篇幅,我们仅用三条数据
import React from 'react';
import { DecompositionTreeGraph } from '@ant-design/graphs';
export const TreeGraph = () => {
const data = {
id: 'A0',
value: {
title: '订单金额',
items: [
{
text: '3031万',
},
],
},
children: [
{
id: 'A1',
value: {
title: '华南',
items: [
{
text: '1152万',
},
{
text: '占比',
value: '30%',
},
],
},
},
{
id: 'A2',
value: {
title: '华北',
items: [
{
text: '595万',
},
{
text: '占比',
value: '30%',
icon: 'https://gw.alipayobjects.com/zos/antfincdn/iFh9X011qd/7797962c-04b6-4d67-9143-e9d05f9778bf.png',
},
],
},
},
],
};
const config = {
data,
};
return <DecompositionTreeGraph {...config} />;
};
功能介绍
上面案例虽然简答,但也难满足业务需求,我们需要润色并丰富相关功能,由于功能配置较多,以下介绍都只是提及,详情参看官网。
交互
marker:给节点加上一些 marker 用于展开收起交互
const config = {
data,
markerCfg: (cfg) => {
const { children } = cfg;
return {
show: true,
collapsed: !children?.length,
};
},
};
behaviors:图表默认会内置画布缩放、节点拖拽等交互,也可以自己指定
const config = {
data,
markerCfg: (cfg) => {
const { children } = cfg;
return {
show: true,
collapsed: !children?.length,
};
},
behaviors: ['drag-canvas', 'zoom-canvas', 'drag-node'],
};
布局调整
默认是水平向右,垂直向下的情况请也比较多,调整布局会涉及出桩和入桩位置的调整。
const config = {
data,
layout: {
direction: 'TB',
getVGap: () => {
return 40;
},
},
nodeCfg: {
anchorPoints:[[0.5, 0],[0.5,1]]
},
edgeCfg: {
type: 'polyline',
},
};
事件
可以通过 graph.on 与 graph.off 进行绑定/解绑监听函数,支持各种事件。
const config = {
data,
onReady: (graph)=>{
graph.on('node:click', (e)=>{
console.log(e.item.getModel())
})
},
};
异步请求
一次展示所有节点不切实际,正常情况下都会异步加载,我们看下 DecompositionTreeGraph 是如何实现的,点击 + 号即可看到效果。
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(
[1, 2].map(() => ({
id: 'A2' + Math.random().toString(),
value: {
title: '异步节点' + Math.random().toString(),
items: [
{
text: '595万',
},
{
text: '占比',
value: '50%',
},
],
},
})),
);
}, 1000);
});
};
const getChildren = async () => {
return await fetchData();
};
const config = {
data,
nodeCfg: {
getChildren,
},
markerCfg: (cfg) => {
const { children } = cfg;
return {
show: true,
collapsed: !children?.length,
};
},
};
自定义节点
这么丑的节点,你能忍?反正我是不能忍!当然,节点样式和边样式完全可以自定义配置,也可 通过回调的方式个性化设置。
const config = {
data,
nodeCfg: {
title: {
containerStyle: {
fill: 'transparent',
},
style: {
fill: '#000',
},
},
items: {
containerStyle: {
fill: '#fff',
},
style: (cfg, group, type) => {
const styles = {
icon: {
width: 10,
height: 10,
},
value: {
fill: '#52c41a',
},
text: {
fill: '#aaa',
},
};
return styles[type];
},
},
style: {
stroke: '#40a9ff',
strokeWidth: 1
},
},
edgeCfg: {
style: (item, graph) => {
/**
* graph.findById(item.target).getModel()
* item.source: 获取 source 数据
* item.target: 获取 target 数据
*/
// console.log(graph.findById(item.source).getModel());
return {
stroke: '#40a9ff',
lineWidth: Math.random() * 10 + 1,
strokeOpacity: 0.5,
};
},
edgeStateStyles: false,
},
};
好像还是很丑!算了,总之,支持各种个性化配置!
自定义节点
业务需求各异,自定义节点也显的比较重要,这里需要一些 canvas 常识,详见。
总结
缺点很多,但也支持了无数项目,欢迎大家来一起修 issues!