🎨 在理想的最美好世界中,一切都是为最美好的目的而设。 —— 伏尔泰
如果可以实现记得点赞分享,谢谢老铁~
一、技术选型
•从可维护性和可拓展性出发
•基本满足
1:链接: https://github.com/hukaibaihu/vue-org-tree
•线条用canvas绘画,其他元素用HTML实现。
2:https://segmentfault.com/a/1190000021972969
•便于后期灵活拓展,优先选择
3: http://antv-2018.alipay.com/zh-cn/g6/3.x/index.html
二、Graph G6
创建一个 G6 的关系图仅需要下面几个步骤:
1.创建关系图的 HTML 容器;
2.数据准备;
3.创建关系图;
4.配置数据源,渲染。
Step 1 创建容器
需要在 HTML 中创建一个用于容纳 G6 绘制的图的容器,通常为 div 标签。G6 在绘制时会在该容器下追加 canvas 标签,然后将图绘制在其中。
HTML
Step 2 数据准备
引入 G6 的数据源为 JSON 格式的对象。该对象中需要有节点(nodes)和边(edges)字段,分别用数组表示:
const data = {
// 点集
nodes: [{
id: 'node1', // String,该节点存在则必须,节点的唯一标识
x: 100, // Number,可选,节点位置的 x 值
y: 200 // Number,可选,节点位置的 y 值
},{
id: 'node2', // String,该节点存在则必须,节点的唯一标识
x: 300, // Number,可选,节点位置的 x 值
y: 200 // Number,可选,节点位置的 y 值
}],
// 边集
edges: [{
source: 'node1', // String,必须,起始点 id
target: 'node2' // String,必须,目标点 id
}]
};
注意
•nodes 数组中包含节点对象,唯一的 id 是每个节点对象中必要的属性,x、 y 用于定位;
•edges 数组中包含边对象,source 和 target 是每条边的必要属性,分别代表了该边的起始点 id 与 目标点 id。
•点和边的其他属性参见链接:G6 的内置节点和边。
Step 3 创建关系图
创建关系图(实例化)时,至少需要为图设置容器、宽和高:
const graph = new G6.Graph({
container: 'mountNode', // String | HTMLElement,必须,在 Step 1 中创建的容器 id 或容器本身
width: 800, // Number,必须,图的宽度
height: 500 // Number,必须,图的高度
});
Step 4 配置数据源,渲染
graph.data(data); // 读取 Step 2 中的数据源到图上
graph.render(); // 渲染图
最终的结果
三、项目应用
如何自定义节点,自定义样式?
第一种:通过 图形 Shape 内置节点类型自定义节点
•会按照addShape顺序来解析节点
G6.registerNode(
'nodeName',
{
options: {
style: {},
stateStyles: {
hover: {},
selected: {},
},
},
/**
* 绘制节点,包含文本
* @param {Object} cfg 节点的配置项
* @param {G.Group} group 图形分组,节点中图形对象的容器
* @return {G.Shape} 返回一个绘制的图形作为 keyShape,通过 node.get('keyShape') 可以获取。
* 关于 keyShape 可参考文档 核心概念-节点/边/Combo-图形 Shape 与 keyShape
*/
draw:(cfg, group) => {
// 最外面的那层
group.addShape('rect', {
attrs: {
x: 0,
y: 0,
width: 125,
height: 40,
fill: cfg.style.fill, // 填充色
stroke: '', // 边框
radius: 8
},
// must be assigned in G6 3.3 and later versions. it can be any value you want
name: 'rect-shape',
zIndex: 1,
});
// 里面的那层
group.addShape('rect', {
draggable: true,
attrs: {
x: 5,
y: 0,
width: 120,
height: 40,
fill: '#fff', // 填充色
stroke: '', // 边框
radius: 6
}
});
// 文字
group.addShape('text', {
attrs: {
// textBaseline: 'center',
y: 25,
x: 24,
lineHeight: 10,
text: cfg.label,
fill: '#000'
}
});
},
},
// 继承内置节点类型的名字,例如基类 'single-node',或 'circle', 'rect' 等
// 当不指定该参数则代表不继承任何内置节点类型
extendedNodeName,
);
第二种:使用 DOM 自定义节点
SVG 与 DOM 图形在 V3.3.x 中不支持。 仅在 Graph 的 renderer 为 ‘svg’ 时可以使用 DOM 自定义节点。
⚠️ 注意:
•只支持原生 HTML DOM,不支持各类 react、vue 组件;
•使用 ‘dom’ 进行自定义的节点或边,不支持 G6 的交互事件,请使用原生 DOM 的交互事件;
•在 Safari 中,若 dom 节点被设置了 position:relative,将会导致渲染异常。Issus。
G6.registerNode(
'dom-node',
{
draw: (cfg: ModelConfig, group: Group) => {
const shape = group.addShape('dom', {
attrs: {
x: 0,
y: 0,
width: 100,
height: 24,
html: `
<div id=${cfg.id} class='dom-node' style="background-color: #fff; border: 2px solid red; border-radius: 5px; width: 300px; height: 200px; display: flex;">
<div style="height: 100%; width: 33%; background-color: #CDDDFD">
<img alt="" style="line-height: 100%; margin-left: 7px;" src="https://xxxx" width="20" height="20" />
</div>
<span style="margin:auto; padding:auto; color: #5B8FF9">${cfg.label}</span>
</div>`
}
});
return shape;
},
},
'single-node',
);
第三种:使用类 JSX 语法定义 G6 节点
在 G6 3.7.0 及以后的版本中,用户以使用类似 JSX 的语法来定义节点。只需要在使用 G6.registerNode 自定义节点时,将第二个参数设置为字符串或一个返回值为 string 的 function。
推荐用法
•在最外层包裹 group 标签,保证节点里面图形树结构完整
•字符串最好使用单引号包裹,以免遇到解析错误
•style 中随 node 变化的变量推荐使用 ${} 的模板语法加入
•图形内的相对定位推荐使用 marginTop 和 marginLeft 进行设置,x 与 y 会破坏层级关系定位
•如果涉及到需要横向排列的元素,在上一个元素使用next: inline来实现下一个元素跟随在上个元素后方
import { groupXML } from '../xml/groupXML.js'
G6.registerNode('rect-xml', {
jsx: groupXML
})
export const rootXML = (cfg) =>`
<rect style={{
width: 520,
height: 40,
textAlign: 'center',
fill: ${cfg.account_type == '' ? cfg.rootTitleColor : '#2D8CF0'},
radius: [10, 10, 0, 0],
name: 'rootHeader'
}}>
<text style={{
marginTop: 10,
marginLeft: 230,
fontWeight: '500',
fontSize: '16',
fill: '#FFFFFF' }}> ${cfg.nameHeader}</text>
</rect>`
第四种:使用React直接定义节点
下载依赖安装包
npm install @antv/g6-react-node