背景:dagre可以在节点数据中配置layer字段,为节点指定层级,但layer的指定不能违背图结构与层次布局的原则,也就是说每一条边的起点的layer一定小于终点的layer值,否则会导致布局失败。
解决办法:动态添加节点,在需要增加同级节点的node处添加一个影子节点,隐藏该影子节点,将需要添加的节点动态添加到该影子节点上。
示例图:
代码如下:
import G6 from '@antv/g6';
import insertCss from 'insert-css';
insertCss(`
.g6-tooltip {
border-radius: 6px;
font-size: 12px;
color: #fff;
background-color: #000;
padding: 2px 8px;
text-align: center;
}
`);
const data = {
nodes: [
{
id: '1',
dataType: 'alps',
name: '1',
layer:0
},
{
id: '2',
dataType: 'alps',
name: '2',
layer:0
},
{
id: '3',
dataType: 'alps',
name: '3',
layer:1
},
{
id: '6',
dataType: 'sql2',
name: '6',
layer:3
},
{
id: '7',
dataType: 'sql2',
name: '7',
layer:3
},
],
edges: [
{
source: '2',
target: '3',
},
{
source: '1',
target: '3',
},
{
source: '3',
target: '6',
},
{
source: '3',
target: '7',
},
],
};
G6.registerNode(
'sql',
{
drawShape(cfg, group) {
const rect = group.addShape('rect', {
attrs: {
x: -75,
y: -25,
width: 150,
height: 50,
radius: 10,
stroke: '#5B8FF9',
fill: '#C6E5FF',
lineWidth: 3,
},
name: 'rect-shape',
});
if (cfg.name) {
group.addShape('text', {
attrs: {
text: cfg.name,
x: 0,
y: 0,
fill: '#00287E',
fontSize: 14,
textAlign: 'center',
textBaseline: 'middle',
fontWeight: 'bold',
},
name: 'text-shape',
});
}
return rect;
},
},
'single-node',
);
const container = document.getElementById('container');
const width = container.scrollWidth;
const height = container.scrollHeight || 500;
const graph = new G6.Graph({
container: 'container',
width,
height,
layout: {
type: 'dagre',
ranksep: 70,
controlPoints: true,
},
defaultNode: {
type: 'sql',
size: [48, 48],
anchorPoints: [
// [0, 0],代表节点左上角的锚点,[1, 1],代表节点右下角的锚点。
[0.5, 0], // 顶部中心锚点
[0.5, 1], // 底部中心锚点
],
},
defaultEdge: {
type: 'cubic-vertical',
sourceAnchor: 1,
style: {
// radius: 20,
// offset: 45,
// endArrow: true,
lineWidth: 1,
stroke: '#C9CDD4',
shadowBlur: 10,
},
},
nodeStateStyles: {
selected: {
stroke: '#d9d9d9',
fill: '#5394ef',
},
},
modes: {
default: [
'drag-canvas',
'zoom-canvas',
'click-select',
],
},
fitView: true,
});
graph.data(data);
graph.render();
graph.on('afterrender',()=>{
const targerNode = graph.findById('3');
const realModel = targerNode.getModel();
graph.addItem("node", {
id: 'shadowNode',
x: realModel.x,
y: realModel.y,
label: '影子节点',
anchorPoints: [[0, 0.5], [1, 0.5]],
});
graph.findById('shadowNode').hide();
graph.addItem("node", {
id: 'add1',
x: realModel.x + 200 + 20 * 3,
y: realModel.y,
label: '额外节点',
anchorPoints: [[0.5, 0], [0.5, 0]]
});
graph.addItem("edge", {
source: 'shadowNode',
target: 'add1',
type: 'arc',
});
graph.addItem("node", {
id: 'add11',
x: realModel.x + 400 + 20 * 3,
y: realModel.y,
label: '额外节点2',
anchorPoints: [[0.5, 0], [0.5, 0]]
});
graph.addItem("edge", {
source: 'shadowNode',
target: 'add11',
type: 'arc',
});
})
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);
};