先上图:
自定义节点样式
自定义边
在this.graph = new G6.Graph内的defaultEdge内引用自定义线条type:"hvh"
defaultEdge: {
type: 'hvh',
},
G6.registerEdge('hvh', {
setState(name, value, item) {
const group = item.getContainer();
const shape = group.get('children')[0]; // 顺序根据 draw 时确定
if (name === 'active') {
if (value) {
shape.attr('stroke', 'lightgrey');
} else {
shape.attr('stroke', 'darkgrey');
}
}
if (name === 'selected') {
if (value) {
shape.attr('lineWidth', 4);
} else {
shape.attr('lineWidth', 3);
}
}
},
draw(cfg, group) {
const startPoint = cfg.startPoint;
const endPoint = cfg.endPoint;
const Ydiff = endPoint.y - startPoint.y;
const Xdiff = endPoint.x - startPoint.x;
let path = [];
// 根据节点之间的距离,调整线
if ((Ydiff <= 30 && Ydiff > 0) || (Ydiff >= -30 && Ydiff < 0)) {
path = [
['M', startPoint.x, startPoint.y],
['L', endPoint.x, endPoint.y],
];
} else if (Xdiff >= 35 && Ydiff <= 0) {
path = [
['M', startPoint.x, startPoint.y],
['L', startPoint.x + 10, startPoint.y],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x - 10, startPoint.y],
['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y, endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y - 10],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y + 10],
['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y, (endPoint.x / 3 + (2 / 3) * startPoint.x) + 13, endPoint.y,],
['L', endPoint.x + (-15), endPoint.y],
['L', endPoint.x, endPoint.y],
]
} else if (Xdiff >= 35 && Ydiff > 0) {
path = [
['M', startPoint.x, startPoint.y],
['L', startPoint.x + 10, startPoint.y],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x - 10, startPoint.y],
['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y, endPoint.x / 3 + (2 / 3) * startPoint.x, startPoint.y + 10],
['L', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y - 10],
['Q', endPoint.x / 3 + (2 / 3) * startPoint.x, endPoint.y, (endPoint.x / 3 + (2 / 3) * startPoint.x) + 13, endPoint.y,],
['L', endPoint.x + (-15), endPoint.y],
['L', endPoint.x, endPoint.y],
]
} else if (Xdiff < 35 && Ydiff >= 0) {
path = [
['M', startPoint.x, startPoint.y], // 起点
['L', startPoint.x + 13, startPoint.y], // 第一个定拐点 x变化y不变
['Q', startPoint.x + 20, startPoint.y, startPoint.x + 20, startPoint.y + 7],
['L', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y - 12],
['Q', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y, startPoint.x + 10, endPoint.y / 3 + 2 / 3 * startPoint.y],
['L', endPoint.x / 3 + 2 / 3 * startPoint.x - 9, endPoint.y / 3 + 2 / 3 * startPoint.y], // 第2个拐点x 自由变化 三分之几处 y方向不变// 三分之一处
['L', endPoint.x + (-20), endPoint.y / 3 + 2 / 3 * startPoint.y],
['Q', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y, endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y + 10],
['L', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y + 10],
['L', endPoint.x + (-30), endPoint.y - 10],
['Q', endPoint.x + (-30), endPoint.y, endPoint.x + (-20), endPoint.y],
['L', endPoint.x + (-20), endPoint.y],
['L', endPoint.x, endPoint.y]
]
} else if (Xdiff < 35 && Ydiff < 0) {
path = [
['M', startPoint.x, startPoint.y], // 起点
['L', startPoint.x + 13, startPoint.y], // 第一个定拐点 x变化y不变
['Q', startPoint.x + 20, startPoint.y, startPoint.x + 20, startPoint.y - 7],
['L', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y + 12],
['Q', startPoint.x + 20, endPoint.y / 3 + 2 / 3 * startPoint.y, startPoint.x + 10, endPoint.y / 3 + 2 / 3 * startPoint.y],
['L', endPoint.x / 3 + 2 / 3 * startPoint.x + 9, endPoint.y / 3 + 2 / 3 * startPoint.y], // 第2个拐点x 自由变化 三分之几处 y方向不变// 三分之一处
['L', endPoint.x + (-25), endPoint.y / 3 + 2 / 3 * startPoint.y],
['Q', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y, endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y - 10],
['L', endPoint.x + (-30), endPoint.y / 3 + 2 / 3 * startPoint.y - 10],
['L', endPoint.x + (-30), endPoint.y + 10],
['Q', endPoint.x + (-30), endPoint.y, endPoint.x + (-20), endPoint.y],
['L', endPoint.x + (-20), endPoint.y],
['L', endPoint.x, endPoint.y]
]
}
const shape = group.addShape('path', {
attrs: {
path,
endArrow: {
path: 'M 0,0 L 12,6 L 9,0 L 12,-6 Z',
fill: 'darkgrey',
},
shadowColor: 'darkgreygrey',
shadowBlur: 10,
shadowOffsetY: 5,
shadowOffsetX: 5,
lineAppendWidth: 10,
lineWidth: 3,
stroke: 'darkgrey',
lineJoin: 'round'
}
});
return shape;
}
});
线条可拖拽
modes: {
default: [{
type: 'drag-node',
// updateEdge: true,
// shouldUpdate: (e) => {
// return true
// }
}, 'drag-canvas', 'drag-add-edge',
{
type: 'zoom-canvas',
sensitivity: 2.5,
},],
},
G6.registerBehavior('drag-add-edge', {
getEvents() {
return {
'node:mousedown': 'onNodeMousedown',
'node:mouseup': 'onNodeMouseup',
'edge:mouseup': 'onEdgeMouseup',
"mousemove": 'onMousemove',
};
},
onNodeMousedown(event) {
const self = this;
// 交互过程中的信息
self.evtInfo = {
action: null,
node: event.item,
target: event.target
};
if (self.evtInfo.target && self.evtInfo.target.attrs.fill) {
if (self.evtInfo.target.attrs.fill === '#72CC4A') {
self.evtInfo.action = 'drawEdge';
}
}
if (self.evtInfo && self.evtInfo.action) {
self[self.evtInfo.action].start.call(self, event);
}
},
onNodeMouseup(event) {
const self = this;
if (self.evtInfo && self.evtInfo.action) {
self[self.evtInfo.action].stop.call(self, event);
}
},
onEdgeMouseup(event) {
const self = this;
if (self.evtInfo && self.evtInfo.action === 'drawEdge') {
self[self.evtInfo.action].stop.call(self, event);
}
},
onMousemove(event) {
const self = this;
if (self.evtInfo && self.evtInfo.action) {
self[self.evtInfo.action].move.call(self, event);
}
},
drawEdge: {
graph: this.graph,
isMoving: false,
currentLine: null,
start(event) {
const self = this;
// 处理线条目标点
if (self.evtInfo.node.getAnchorPoints() && self.evtInfo.node.getAnchorPoints().length) {
// 获取距离指定坐标最近的一个锚点
const sourceAnchor = self.evtInfo.node.getLinkPoint({
x: event.x,
y: event.y
});
self.drawEdge.currentLine = self.graph.addItem('edge', {
// 起始节点
source: self.evtInfo.node.getModel().id,
sourceAnchor: sourceAnchor ? sourceAnchor.anchorIndex : '',
// 终止节点/位置
target: {
x: event.x,
y: event.y
},
type: 'hvh',
});
self.drawEdge.isMoving = true;
}
},
move(event) {
const self = this;
if (self.drawEdge.isMoving && self.drawEdge.currentLine) {
self.graph.updateItem(self.drawEdge.currentLine, {
target: {
x: event.x,
y: event.y
}
});
}
},
stop(event) {
const self = this;
if (self.drawEdge.isMoving) {
if (self.drawEdge.currentLine === event.item) {
// 画线过程中点击则移除当前画线
self.graph.removeItem(event.item);
}
else if (event.item._cfg.model.label === '起点') {
self.graph.removeItem(self.drawEdge.currentLine);
} else {
const targetNode = event.item;
let targetAnchor = null;
// 锚点数据
// 处理线条目标点
if (targetNode.getAnchorPoints() && targetNode.getAnchorPoints().length) {
// 获取距离指定坐标最近的一个锚点
targetAnchor = targetNode.getLinkPoint({ x: event.x, y: event.y });
}
self.graph.updateItem(self.drawEdge.currentLine, {
target: targetNode.getModel().id,
targetAnchor: targetAnchor ? targetAnchor.anchorIndex : ''
});
}
// const { detectAllCycles } = Algorithm;
// if (detectDirectedCycle(this.graph)) {
// self.graph.removeItem(self.drawEdge.currentLine);
// }
}
self.drawEdge.currentLine = null;
self.drawEdge.isMoving = false;
self.evtInfo = null;
}
}
}
);
自定义节点样式
G6.registerNode('rectNode', {
draw: (cfg, group,) => {
const color = cfg.error ? '#5B8FF9' : '#9EC9FF';
const r = 2;
//最外面的那层
const shape = group.addShape('rect', {
draggable: true,
attrs: {
x: 0,
y: 0,
width: 250,
height: 90,
stroke: color,
radius: r,
},
name: 'main-box',
});
/* 右边边的小圆点 */
group.addShape('circle', {
attrs: {
x: 252,
y: 90 / 2,
r: 4,
fill: "#72CC4A",
},
name: 'left-dot-shape',
});
/* 左边的小圆点 */
group.addShape('circle', {
attrs: {
x: 0,
y: 90 / 2,
r: 4,
fill: "#72CC4A",
},
name: 'left-dot-shape',
});
//里面的那层
group.addShape('rect', {
draggable: true,
attrs: {
x: 0,
y: 0,
width: 250,
height: 30,
fill: color,
radius: [r, r, 0, 0],
},
name: 'title-box',
});
group.addShape('rect', {
draggable: true,
attrs: {
x: 0,
y: 30,
width: 250,
height: 60,
fill: '#fff',
radius: [r, r, 0, 0],
},
name: 'title-box',
});
// title text
group.addShape('text', {
attrs: {
textBaseline: 'top',
y: 5,
x: 30,
lineHeight: 50,
text: "[用例]:" + cfg.label,
fill: '#fff',
},
name: 'title',
});
cfg.panels.forEach((item, index) => {
// name text
group.addShape('text', {
attrs: {
textBaseline: 'top',
y: 40,
x: 24 + index * 140,
lineHeight: 30,
text: item.title,
fill: 'rgba(0,0,0, 0.4)',
},
name: `index-title-${index}`,
});
// value text
group.addShape('text', {
attrs: {
textBaseline: 'top',
y: 60,
x: 24 + index * 140,
lineHeight: 30,
text: item.value,
fill: '#595959',
},
name: `index-title-${index}`,
});
});
return shape;
},
});