antv g6实现自定义决策树 vue2
<template>
<div id="container"></div>
</template>
<script>
import G6 from "@antv/g6";
export default {
name: "index",
mounted() {
// console.log(777777778889);
// this.treedata= JSON.parse(JSON.stringify(this.treedata).replace(/"name"/g,'"label"'))
// this.treedata= JSON.parse(JSON.stringify(this.treedata).replace(/"sub_folder"/g,'"children"'))
let nodesizeWidth = 100//节点高
let nodesizeHeight = 32//节点宽
let iconSize=10//icon
let direction='LR'// 根节点在左,往右布局 H / V / LR / RL / TB / BT
let label=8//title
let subLabel=10//左下
let sub2Label=10//右下
let increaseHeight=13
let increaseWidth=34
let HGap=20
let VGap=20
let radius=2//节点弧度
let leftx=10//左下x
let lefty=12//左下x
let rightx=15//左下x
let righty=3//左下x
let backgroundColor = 'rgba(255,255,255,0.88)'
let fontColor = 'rgb(0,0,0)'
let trueincreaseColor = 'rgb(111,255,115)' //右下为true颜色 影响边框的颜色
let increaseFontColor = 'rgb(255,255,255)' //右下颜色 影响边框的颜色
let falseincreaseColor = 'rgb(255,0,0)'//右下false颜色
let circleColor = 'rgba(17,28,236,0.85)'
let lineColor = 'rgba(83,124,248,0.85)'
let heardBackgroundtrueColor = '#fff5f1'//heard false背景颜色
let heardBackgroundfalseColor = '#eef4ff'//heard false背景颜色
let lineBackgroundtrueColor = '#fc8d5e'//边框颜色
let lineBackgroundfalseColor = '#316fff'//边框颜色
this.init(lineBackgroundtrueColor,lineBackgroundfalseColor,heardBackgroundtrueColor,heardBackgroundfalseColor,righty,rightx,lefty,leftx,radius,VGap,HGap,direction,increaseHeight,increaseWidth,sub2Label,label,subLabel,iconSize,nodesizeWidth,nodesizeHeight, backgroundColor, fontColor, trueincreaseColor, falseincreaseColor, circleColor, lineColor, increaseFontColor);
},
// props:["treedata"],
methods: {
init(lineBackgroundtrueColor,lineBackgroundfalseColor,heardBackgroundtrueColor,heardBackgroundfalseColor,righty,rightx,lefty,leftx,radius,VGap,HGap,direction,increaseHeight,increaseWidth,sub2Label,label,subLabel,iconSize,nodesizeWidth,nodesizeHeight, color, fontColor, trueincreaseColor, falseincreaseColor, circleColor, lineColor, increaseFontColor) {
// root node
G6.registerNode('root', {
draw: (cfg, group) => {
const size = [80, 30];
const keyShape = group.addShape('rect', {
attrs: {
width: size[0],
height: size[1],
x: -size[0] / 2,
y: -size[1] / 2,
fill: color,
stroke: cfg.heardincrease?heardBackgroundtrueColor:heardBackgroundfalseColor, // 填充色
radius: 5
},
draggable: true,
name: 'root-keyshape'
});
group.addShape('text', {
attrs: {
text: `${cfg.ratio}%`,
fill: fontColor,
fontSize: 6,
x: 10 - size[0] / 2,
y: 3,
},
draggable: true,
name: 'ratio-shape'
});
group.addShape('text', {
attrs: {
text: `${cfg.label}`,
fill: fontColor,
fontSize: 9,
x: -6,
y: 0,
},
draggable: true,
name: 'label-shape'
});
group.addShape('line', {
attrs: {
x1: -6,
x2: 35,
y1: 2,
y2: 2,
stroke: 'rgba(255, 255, 255, 0.85)',
lineWidth: 0.5
},
draggable: true,
name: 'divider-shape'
});
group.addShape('text', {
attrs: {
text: `${cfg.subLabel}`,
fill: fontColor,
fontSize: 6,
x: -6,
y: 10,
},
draggable: true,
name: 'sublabel-shape'
});
return keyShape;
}
});
// other node
G6.registerNode('othernode', {
draw: (cfg, group) => {
const size = [nodesizeWidth, nodesizeHeight];
const keyShape = group.addShape('rect', {
attrs: {
width: size[0],
height: size[1],
x: -size[0] / 2,
y: -size[1] / 2,
fill: color,
//节点边框颜色
stroke: cfg.heardincrease?lineBackgroundtrueColor:lineBackgroundfalseColor,
radius: radius,
size: [270, 80],
},
draggable: true,
name: 'level1node-keyshape'
});
// 背景板
group.addShape('rect', {
attrs: {
x: -size[0] / 2,
y: -size[1] / 2,
width: size[0],
height: size[1] / 2,
radius: [radius,radius,0,0],
// radius: [0, 0, rectConfig.radius, rectConfig.radius],//锐角化
fill: cfg.heardincrease?heardBackgroundtrueColor:heardBackgroundfalseColor, // 填充色
}
})
//图标
group.addShape('image', {
attrs: {
x: size[0] / 2 - 12,
y: -size[1] / 2 + 2,
img: require('@/assets/感叹号中.png'),
width: iconSize,
height: iconSize,
cursor: 'pointer'
},
name: 'gt'
})
group.addShape('image', {
attrs: {
x: size[0] / 2 - 24,
y: -size[1] / 2 + 3,
img: require('@/assets/闪电发货.png'),
width: iconSize,
height: iconSize,
cursor: 'pointer'
},
name: 'sd'
})
//上面的字
group.addShape('text', {
attrs: {
text: `${cfg.label}`,
fill: fontColor,
fontSize: label,
x: 10 - size[0] / 2,
y: -2,
textAlign: 'left'
},
draggable: true,
name: 'label-shape'
});
//左下字
group.addShape('text', {
attrs: {
text: `${cfg.subLabel}`,
fill: fontColor,
fontSize: subLabel,
fontWeight: 800,
x: leftx - size[0] / 2,
y: lefty,
textAlign: 'left'
},
draggable: true,
name: 'sublabel-shape'
});
group.addShape('rect', {
attrs: {
x: 12,
y: 1,
width: increaseWidth,
height: increaseHeight,
radius: 2,
fill: cfg.increase ? trueincreaseColor : falseincreaseColor
},
draggable: true,
name: 'ratio-box'
})
//右下字
group.addShape('text', {
attrs: {
text: cfg.increase ? `+${cfg.ratio}%` : `-${cfg.ratio}%`,
fill: increaseFontColor,
fontSize: sub2Label,
x: rightx,
y: righty,
textAlign: 'left',
textBaseline: 'top'
},
draggable: true,
name: 'ratio-shape'
});
// edge end
group.addShape('line', {
attrs: {
x1: -size[0] / 2,
x2: -size[0] / 2 + 6,
y1: 0,
y2: 0,
lineWidth: 1,
stroke: lineColor,
}
});
return keyShape;
},
update: undefined
}, 'rect')
// edge
G6.registerEdge('round-poly', {
getControlPoints: (cfg) => {
const {startPoint, endPoint} = cfg;
return [
startPoint,
{
x: startPoint.x,
y: endPoint.y
},
endPoint
];
}
}, 'polyline')
const data = {
id: 'root',
label: '利息收入',
subLabel: '3,283.456',
ratio: 3,
children: [
{
id: 'child-a',
label: '平均利息',
subLabel: '9%',
ratio: 1,
increase: true,
heardincrease: true,
children: [
{
id: 'child-a-1',
label: '平均利息1',
subLabel: '9%',
ratio: 1,
increase: true,
heardincrease: false,
children: [
{
id: 'child-a-1-1',
label: '平均利息1-1',
subLabel: '9%',
ratio: 1,
increase: true,
tootip: {
leftData: '800万元',
rightData: '700万元'
}
},
{
id: 'child-a-1-2',
label: '平均利息1-2',
subLabel: '9%',
ratio: 1,
increase: true,
tootip: {
leftData: '800万元',
rightData: '700万元'
}
}]
},
{
id: 'child-a-2',
label: '平均利息2',
subLabel: '9%',
ratio: 1,
increase: false,
}]
}, {
id: 'child-b',
label: '贷款余额',
subLabel: '1,789,567',
ratio: 23,
increase: true,
children: [{
id: 'child-b-a',
label: '投放金额',
subLabel: '2,385,124',
ratio: 17,
increase: true,
operator: '-',
}, {
id: 'child-b-b',
label: '还款金额',
subLabel: '595,557',
ratio: 12,
increase: true,
}
]
}, {
id: 'child-c',
label: '还款期限',
subLabel: '7',
ratio: 23,
increase: true,
}
]
};
G6.Util.traverseTree(data, subtree => {
if (subtree.level === undefined) subtree.level = 0;
// subtree.children?.forEach(child => child.level = subtree.level + 1);
if (subtree.children && subtree.children.forEach) {
subtree.children.forEach(child => {
if (child) {
child.level = subtree.level + 1;
}
});
}
switch (subtree.level) {
case 0:
subtree.type = 'root';
break;
default:
subtree.type = 'othernode';
}
});
const width = container.scrollWidth;
const height = (container.scrollHeight || 500) - 30;
const tooltip = new G6.Tooltip({
getContent(e) {
// console.log("e=======>", e)
if (e.item._cfg.model.tootip != undefined) {
const outDiv = document.createElement("div");
if (e.item._cfg.type == "node") {
outDiv.style.width = "150px";
outDiv.innerHTML = `
<div style="border: 1px solid #06a6db;position: relative;z-index:12">
<div style="background-color: #0786e0;padding: 10px 20px; font-size:12px;">${e.item._cfg.model.label}</div>
<div style="padding: 12px;position: relative;z-index:12">
<span>${e.item._cfg.model.tootip.leftData}</span>
<span>-></span>
<span>${e.item._cfg.model.tootip.rightData}</span>
</div>
</div>
`;
return outDiv;
} else {
outDiv.style.display = "none";
return outDiv;
}
}
},
shouldBegin(e) {
console.log("shouldBegin=======>e====>", e.item._cfg.model.tootip)
if (e.item._cfg.model.tootip != undefined) {
if (e.target.cfg.name == 'gt') {
return true;
}
} else {
return false;
}
},
itemTypes: ['node']
});
const tooltip2 = new G6.Tooltip({
getContent(e) {
const outDiv = document.createElement("div");
if (e.item._cfg.type == "node") {
outDiv.style.width = "150px";
outDiv.innerHTML = `
<div style="border: 1px solid #06a6db;position: relative;z-index:12">
<div style="background-color: #f5f5f5;padding: 10px 20px; font-size:12px;">血缘归因</div>
</div>
`;
return outDiv;
} else {
outDiv.style.display = "none";
return outDiv;
}
},
shouldBegin(e) {
// console.log("shouldBegin=======>e====>", e)
if (e.target.cfg.name == 'sd') {
return true;
}
},
itemTypes: ['node']
});
const graph = new G6.TreeGraph({
container: 'container',
width,
height,
fitView: true,
layout: {
type: 'compactBox',
preventOverlap: true, // 防止节点重叠
direction:direction , // 根节点在左,往右布局 H / V / LR / RL / TB / BT
getHGap: function getHGap() {
return HGap; // 每一层节点之间的间距
},
getVGap: function getVGap() {
return VGap; // 每个节点的垂直间距
},
},
defaultEdge: {
type: 'round-poly',
sourceAnchor: 0,
targetAnchor: 1,
// style: {
// radius: 8,
// stroke: lineColor
// }
style: {
// endArrow: true,
// startArrow: true,
stroke: lineColor,
lineWidth: 1,
},
},
defaultNode: {
size: [270, 80],
anchorPoints: [
[0.9, 0.5],
[0, 0.5]
]
},
nodeStateStyles: {
hover: {
fill: '#fff',
shadowBlur: 30,
shadowColor: '#ddd',
},
operatorhover: {
'operator-box': {
opacity: 1
}
}
},
plugins: [tooltip, tooltip2], //浮框样式
modes: {
default: ['zoom-canvas', 'drag-canvas', 'collapse-expand']
}
});
graph.on('node:mouseenter', e => {
// if (e.target.get('name')?.includes('operator')) {
if (e.target && e.target.get && e.target.get('name') && e.target.get('name').includes('operator')) {
graph.setItemState(e.item, 'operatorhover', true);
} else {
graph.setItemState(e.item, 'hover', true);
}
})
graph.on('node:mouseleave', e => {
graph.setItemState(e.item, 'operatorhover', false);
graph.setItemState(e.item, 'hover', false);
});
graph.data(data);
graph.render();
},
},
};
</script>