1 设计节点
在 registerNode 中定义所有的节点
G6.registerNode('tree-node', {
drawShape: function drawShape(cfg, group) {
定义图中需要的节点
}
}, 'single-node',);
为了使用内置的布局方式,选择参数为 ‘tree-node’ 树节点类型,数据格式可以存在children子节点,效果自动生成子树
cfg 可以拿到数据,如cfg.id、cfg.name
1.1 定义节点和文本
使用 group.addShape(‘rect’, {}) 定义节点 rect
配置参数:https://antv-g6.gitee.io/zh/docs/api/shapeProperties/#fill
// 定义节点 rect
const rect = group.addShape('rect', { // 'rect'表示矩形图形
attrs: {
// 节点定义参数:颜色、阴影...
},
name: 'rect-shape', // 为这个节点起名字 不过没有使用过这个名字
});
使用 group.addShape(‘text’, {}) 定义文本 text
// 定义文本text
const text = group.addShape('text', { // 'text'表示文本
attrs: {
// 参数:颜色、文字...
},
name: 'text-shape',
});
节点和文字生成后,再定义他们的相对位置
参考官网定义复杂图样式的方式:https://antv-g6.gitee.io/zh/examples/tree/customItemTree#customTree
使用 .getBBox() 获得该文本的盒子bbox,使用文本盒子的相对位置后面的位置坐标
const bbox = text.getBBox(); // 获得文本的盒子
// 设置rect 节点的位置
rect.attr({
x: -bbox.width / 2 - 5, // x坐标
y: -bbox.height, // y坐标
width: bbox.width + 12 , // 宽
height: bbox.height + 8, // 高
});
// 设置text文本的位置
text.attr({
x: -bbox.width / 2,
y: -bbox.height / 2 + 3,
})
效果如下
1.2 增加节点
如果想为节点再增加一个小节点,并且位置随着大节点移动,如图
新增节点和文本 rect2 text2
rect2 = group.addShape('rect', {
attrs: {
// 参数
},
name: 'rect-shape2',
});
const text2 = group.addShape('text', {
attrs: {
// 参数
},
name: 'text-shape2',
});
为rect2 text2设置坐标,以bbox作为参考位置
// 设置坐标轴和宽高
rect2.attr({
x: -bbox.width / 2 - 24,
y: -bbox.height / 2 - 1,
width: 14,
height: 10,
});
text2.attr({
x: -bbox.width / 2 - 23,
y: -bbox.height / 2 + 4,
})
1.3 自定义节点样式
roup.addShape('dom', {
attrs: {
x: -bbox.width / 2 - 24 + 14, // 即:rect的坐标 + rect的宽
y: -bbox.height / 2 - 1,
width: 10,
height: 10,
html: `
<div style="border: 5px solid red;">
自定义dom
</div>
`,
},
draggable: true,
});
使用自定义dom,在 new G6.TreeGraph中 需要设置
renderer : 'svg', // 奇怪的是设置之后原来节点的布局有些影响
2 树图配置
2.1 允许使用自定义dom节点
renderer : 'svg',
2.2 内置行为
https://antv-g6.gitee.io/zh/docs/manual/middle/states/defaultBehavior#%E5%86%85%E7%BD%AE-behavior
modes: {
default: [
{
type: 'collapse-expand',
onChange: function onChange(item, collapsed) {
const data = item.get('model');
graph.updateItem(item, {
collapsed,
});
data.collapsed = collapsed;
return true;
},
},
'drag-canvas', // 允许拖动
'zoom-canvas', // ....
],
},
自定义边
defaultEdge: {
type: 'cubic-horizontal',
style: {
stroke: 'red' //红色
},
},
layout布局
https://antv-g6.gitee.io/zh/docs/manual/middle/layout/tree-graph-layout
layout: {
type: 'indented',
direction: 'LR', // 节点从左向右分布
dropCap: false,
indent: 190,
getHeight: () => {
return 13;
},
getVGap: function getVGap () {
return 10;
},
},
demo
<template>
<div class="main-content-box">
<div id="container"></div>
</div>
</template>
<script>
import G6 from '@antv/g6';
export default {
name: 'multTagsSec',
data () {
return {
gDatas:{
"id": "1",
"name": "storehouse A",
"children": [
{
"id": "2",
"name": "B",
"percentage": "60%",
"children": [
{
"id": "3",
"name": "storehouse C",
"percentage": "80%",
"children": [
{
"name": "storehouse C",
"percentage": "80%",
"children": [
{
"name": "D",
"percentage": "20%"
},
{
"name": "storehouselllllll C",
"percentage": "20%"
}
]
},
{
"name": "storehouse D",
"percentage": "20%"
}
]
},
{
"name": "storehouse D",
"percentage": "20%"
}
]
},
{
"name": "storehouse C",
"percentage": "100%"
},
{
"name": "storehouse B",
"percentage": "20%"
},
{
"name": "storehouse C",
"percentage": "20%"
},
{
"name": "storehouse C",
"percentage": "20%",
"children": [
{
"name": "D",
"percentage": "20%"
},
{
"name": "storehouse A",
"percentage": "20%"
}
]
}
]
}
}
},
mounted() {
this.getInit();
},
methods: {
getInit () {
// var mycfg = null;
G6.registerNode('tree-node', {
drawShape: function drawShape(cfg, group) {
// console.log(cfg)
// --------------------标签内容节点----------------------
var hasChildren = cfg.children && cfg.children.length > 0; // 是否有孩子节点
var strokeColor = hasChildren == true ? 'red' : null // 有孩子 为红色
// 节点设置
const rect = group.addShape('rect', {
attrs: {
fill: '#fff',
stroke: strokeColor, // 边框颜色
lineWidth: 1, // 边框粗细
radius: 2,
shadowBlur: 15,
shadowColor: '#666',
// shadowOffsetX: 2,
// shadowOffsetY: 2
},
name: 'rect-shape',
});
// 文本设置
const text = group.addShape('text', {
attrs: {
text: cfg.name, // 赋值name属性
fontFamily: 'normal',
fontSize: 11,
fontWeight: 800,
x: 0,
y: 0,
textAlign: 'left',
textBaseline: 'middle',
fill: '#666'
},
name: 'text-shape',
});
const bbox = text.getBBox(); // 获得文本的盒子 之后的两个节点的xy轴坐标参考bbox
//const minbbox = rect.getBBox();
// 设置 rect方框和text文本 的 x y坐标轴
rect.attr({
x: -bbox.width / 2 - 5,
y: -bbox.height,
// width: bbox.width + (hasChildren ? 20 : 12),
width: bbox.width + 12 ,
height: bbox.height + 8,
});
text.attr({
x: -bbox.width / 2,
y: -bbox.height / 2 + 3,
})
// -----------百分比节点----------
var hasPercentage = cfg.percentage;
var rect2 = 0;
if(hasPercentage){
// 节点设置 2
rect2 = group.addShape('rect', {
attrs: {
fill: '#4682B4',
stroke: '', // 边框颜色
lineWidth: 0, // 边框粗细
shadowBlur: 0,
shadowColor: '',
},
name: 'rect-shape2',
});
// 文本设置 2
const text2 = group.addShape('text', {
attrs: {
text: cfg.percentage, // 赋值name属性
fontFamily: 'normal',
fontSize: 5,
fontWeight: 500,
textAlign: 'left',
textBaseline: 'middle',
fill: 'white'
},
name: 'text-shape2',
});
// 设置坐标轴和宽高
rect2.attr({
x: -bbox.width / 2 - 24,
y: -bbox.height / 2 - 1,
width: 14,
height: 10,
});
text2.attr({
x: -bbox.width / 2 - 23,
y: -bbox.height / 2 + 4,
})
// -------连接两个节点的小节点----------
// const rect3 = group.addShape('rect', {
// attrs: {
// fill: '#00BFFF',
// stroke: '', // 边框颜色
// lineWidth: 0, // 边框粗细
// shadowBlur: 0,
// shadowColor: '',
// },
// name: 'rect-shape3',
// });
// rect3.attr({
// x: -bbox.width / 2 - 24 + 14, // 即:rect的坐标 + rect的宽
// y: -bbox.height / 4 + 1,
// width: 4,
// height: 4
// });
// -------连接两个节点的小节点 三角形----------
// 需要设置svg才能使用
group.addShape('dom', {
attrs: {
x: -bbox.width / 2 - 24 + 14, // 即:rect的坐标 + rect的宽
y: -bbox.height / 2 - 1,
width: 10,
height: 10,
html: `
<div style="border-left: 5px solid red;
border-right: 5px solid transparent;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;">
</div>
`,
},
draggable: true,
});
}
// 小圆圈
if (hasChildren) {
const redcircle = group.addShape('marker', {
attrs: {
symbol: cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse,
// symbol: cfg.collapsed ? COLLAPSE_ICON : EXPAND_ICON,
stroke: 'red',
fill: 'red',
lineWidth: 1.8,
},
name: 'collapse-icon',
});
redcircle.attr({
x: bbox.width / 2 + 7,
y: -3 ,
r: 4,
})
}
return rect;
},
update: (cfg, item) => {
const group = item.getContainer();
const icon = group.find((e) => e.get('name') === 'collapse-icon');
icon.attr('symbol', cfg.collapsed ? G6.Marker.expand : G6.Marker.collapse);
},
},
'single-node',
);
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new G6.TreeGraph({
renderer : 'svg', // 创建自定义DMO时定义 会报一个错 但好像不影响
container: 'container',
width,
height,
modes: {
default: [
{
type: 'collapse-expand',
onChange: function onChange(item, collapsed) {
const data = item.get('model');
graph.updateItem(item, {
collapsed,
});
data.collapsed = collapsed;
return true;
},
},
// 'drag-canvas', // 不可拖动
'zoom-canvas',
],
},
defaultNode: {
type: 'tree-node',
anchorPoints: [
[0, 0.5],
[1, 0.5],
],
},
// 设置边的参数
defaultEdge: {
type: 'cubic-horizontal',
style: {
stroke: 'red'
},
},
layout: {
type: 'indented',
direction: 'LR',
dropCap: false,
indent: 190,
getHeight: () => {
return 13;
},
getVGap: function getVGap () {
return 10;
},
},
});
graph.data(this.gDatas);
graph.render();
graph.fitView();
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);
};
},
}
}
</script>
<style scoped>
</style>