课程链接
AntV G6:深入图形与图形分组、自定义节点、节点动画(上)_哔哩哔哩_bilibili
AntV G6:深入图形与图形分组、自定义节点、节点动画(中)_哔哩哔哩_bilibili
图形分组 Group | G6 (antgroup.com)
自定义元素 G6.registerX | G6 (antgroup.com)
图形样式属性 Shape Attr | G6 (antgroup.com)
通过G6.registerNode方法,绘制基于 rect 的自定义卡片,并且提到:
1. 如果要更新自定义node,需要注意重绘时 update方法 是否要重写,有2个方法可以解决
2. 更新节点时候需要注意位置变形的问题,通过设置相对的x,y解决
3. KeyShape的draggable属性,可以控制是否这部分可以被拖拽
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>05 深入图形与图形分组、自定义节点、节点动画</title>
<!-- 引入 G6 -->
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>
</head>
<body>
<div id="container"></div>
<script>
const ICON_MAP = {
a: 'https://ts2.cn.mm.bing.net/th?id=ODLS.70f7e605-0e03-4ed5-8935-b48cb3ee855f&w=32&h=32&o=6&pid=AdsPlus',
b: 'https://ts2.cn.mm.bing.net/th?id=OADD2.7353136438133_1J11L5COSQ5ZDZ3TDJ&w=32&h=32&o=6&pid=21.2'
}
const data = {
nodes: [
{
id: 'node2',
title: 'node2',
error: false,
nodeType: 'a',
nodeLevel: 0,
panels: [
{ title: '成功率', value: '11%' },
{ title: '耗时', value: '50s' },
{ title: '错误数', value: '12' },
],
x: 100,
y: 100
},
{
id: 'node3',
title: 'node3',
error: true,
nodeType: 'b',
nodeLevel: 0,
panels: [
{ title: '成功率', value: '19%' },
{ title: '耗时', value: '10s' },
{ title: '错误数', value: '8' },
],
x: 100,
y: 200
},
],
}
// 第1个参数,卡片节点的名字
// 第2个参数,options
// 第3个参数,继承的节点类型
G6.registerNode('card-node', {
// 复写 draw 方法
// 第1个参数,这个节点的配置
// 第2个参数,这个节点的图形分组,现在的目的是往这个图形分组中去增加图形
draw: (cfg, group) => {
const color = cfg.error ? '#F4664A' : '#30BF78';
const x = -200 / 2;
const y = -60 / 2;
const keyShape = group.addShape('rect', {
attrs: {
x,
y,
width: 200,
height: 60,
stroke: color,
fill: '#fff',
radius: 2
},
name: 'card-node-keyshape'
});
const titleRect = group.addShape('rect', {
attrs: {
x,
y,
width: 200,
height: 20,
stroke: color,
fill: color,
radius: 2
},
name: 'card-node-title-back',
draggable: true // G6为keyShape添加了draggable属性,为true时这部分图形才可以被拖拽
});
const image = group.addShape('image', {
attrs: {
x: x + 2,
y: y + 2,
width: 14,
height: 14,
img: ICON_MAP[cfg.nodeType],
cursor: 'pointer'
}
});
const title = group.addShape('text', {
attrs: {
text: cfg.title,
x: x + 30,
y: y + 4,
fill: '#fff',
textBaseline: 'top'
},
name: 'card-node-title'
});
let panelX = - x + 40; // 疑问点:视频里这里不需要负号
const subGroup = group.addGroup();
cfg.panels?.forEach((panel, i) => {
const panelTitle = subGroup.addShape('text', {
attrs: {
text: panel.title,
x: x + panelX,
y: y + 38,
fill: '#ccc',
textAlign: 'center'
},
name: `card-node-panel-title-${i}`
})
subGroup.addShape('text', {
attrs: {
text: panel.value,
x: x + panelX,
y: y + 54,
fill: '#111',
textAlign: 'center'
},
name: `card-node-panel-title-${i}`
})
// 根据前面图形的大小来放置后面的图形
const titleBBox = panelTitle.getBBox();
// console.log(titleBBox);
panelX = titleBBox.maxX + 40;
// panelX += 60;
})
return keyShape;
},
// update: undefined
// 如果重写了update方法,渲染层面就会走这个update方法,而不会清空整个节点去重新绘制
update: (cfg, item) => {
const group = item.getContainer(); // 获取图形容器
const titleShape = group.find(ele => ele.get('name') === 'card-node-title') // 通过name属性找到需要更新的图形
// titleShape.attr('text', cfg.title); // 更新title里的text字段,attr 用来更新某个绘图属性
// 批量更新
titleShape.attr({
text: cfg.title,
// ... 其他属性
})
}
}, 'rect')
// 如果要更新node,方法1:取消继承自 rect
// 如果要更新node,方法2:在继承自 rect 的前提下,设置update方法为undefined,重绘时就会走自定义的draw
const width = document.getElementById('container').scrollWidth
const height = document.getElementById('container').scrollHeight || 500
const graph = new G6.Graph({
container: 'container',
width,
height,
fitCenter: true,
// fitView: true,
// 模式
modes: {
// 拖拽画布 drag-canvas
// 拖拽节点 drag-node
// 缩放画布 zoom-canvas
default: ['drag-canvas', 'drag-node'],
},
defaultNode: {
type: 'card-node'
}
})
graph.data(data);
graph.render();
graph.updateItem(graph.getNodes()[0], {
// 如果要更新node,方法1:取消继承自 rect
// 如果要更新node,方法2:在继承自 rect 的前提下,设置update方法为undefined,重绘时就会走自定义的draw
title: 'new-title~~'
})
if(typeof window !== 'undefined')
window.onresize = () => {
if(!graph || graph.get('destroyed')) return;
if(!container || !container.scrollWidth || !container.scrollHeight)
graph.changeSize(container.scrollWidth, container.scrollHeight);
}
</script>
</body>
</html>