【课程链接】
AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili
本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>06 深入图形与图形分组、自定义节点、节点动画</title>
<!-- 引入 G6 -->
<script src="https://gw.alipayobjects.com/os/lib/antv/g6/4.3.11/dist/g6.min.js"></script>
<!-- <script src="https://gw.alipayobjects.com/os/lib/antv/g6/3.7.1/dist/g6.min.js"></script> -->
</head>
<body>
<div id="container"></div>
<script>
G6.registerNode('lineNode', {
// 复写draw方法
draw: (cfg, group) => {
const keyShape = group.addShape('circle', {
attrs: {
r: 70,
x: 0,
y: 0,
opacity: 0
}
});
// 画5条虚线做极坐标的对齐线
const rGap = 10;
let currentR = 30;
for (let i = 0; i < 5; i++) {
group.addShape('circle', {
attrs: {
r: currentR,
x: 0,
y: 0,
lineWidth: 1,
stroke: '#bae7ff',
lineDash: [5, 5]
}
})
currentR += rGap;
}
// 中心的圆点和文本
group.addShape('circle', {
attrs: {
fill: cfg.centerColor,
x: 0,
y: 0,
r: 20
}
})
group.addShape('text', {
attrs: {
text: cfg.label,
fill: '#111',
x: 0,
y: 0,
textAlign: 'center',
textBaseline: 'middle',
fontWeight: 500
},
// 给text一个name,为动画animate检索做准备
name: 'line-chart-label'
});
// 绘制折线和它们的坐标点
const alphaGap = Math.PI * 2 / 25;
let pointCount = 0;
cfg.details.forEach(detail => {
const { color, values } = detail;
const positions = []
values.forEach(value => {
const r = value + 20;
const alpha = alphaGap * pointCount;
pointCount++;
const x = r * Math.cos(alpha);
const y = r * Math.sin(alpha);
const point = group.addShape('circle', {
attrs: {
fill: color,
x,
y,
r: 2,
},
// 给圆点起名字name,为圆点添加hover效果做准备
name: 'line-chart-point'
})
positions.push({ x, y });
});
// 绘制各个detail数据的路径
group.addShape('path', {
attrs: {
path: positions.map((pos, i) => [i === 0 ? 'M' : 'L', pos.x, pos.y]),
stroke: color,
lineWidth: 1
}
})
})
return keyShape;
},
// 中间文本不断缩放的动画
afterDraw: (cfg, group) => {
const textShape = group.find(ele => ele.get('name') === 'line-chart-label')
const rate = 1.01;
// 动画的另一种写法,onFrame,onFrame的参数ratio是一次动画执行的比例
textShape.animate(ratio => {
const currentFontSize = textShape.attr('fontSize') || 12;
const scale = ratio < 0.5 ? rate : (1 / rate);
const targetFontSize = currentFontSize * scale;
// console.log('ratio', ratio); 0 < ratio < 1
// console.log('currentFontSize', currentFontSize);
// console.log('scale', scale);
return { fontSize: targetFontSize }
}, {
duration: 1000,
repeat: true
})
}
}, 'circle');
const width = document.getElementById('container').scrollWidth
const height = document.getElementById('container').scrollHeight || 500
const graph = new G6.Graph({
container: 'container',
width,
height,
fitCenter: true,
defaultNode: {
type: 'lineNode'
}
})
const data = {
nodes: [
{
id: 'node1',
label: 'Node1',
x: 150,
y: 150,
centerColor: "#bae7ff", // 中心圆形的颜色
details: [
{ cat: 'pv', values: [20, 30, 40, 30, 30], color: '#5B8FF9' },
{ cat: 'dal', values: [40, 30, 20, 30, 50], color: '#5AD8A6' },
{ cat: 'uv', values: [40, 30, 30, 40, 40], color: '#5D7092' },
{ cat: 'sal', values: [20, 30, 50, 20, 20], color: '#F6BD16' },
{ cat: 'cal', values: [10, 10, 20, 20, 20], color: '#E8684A' },
],
},
{
id: 'node2',
label: 'Node2',
x: 400,
y: 150,
centerColor: "#5b8ff9",
details: [
{ cat: 'pv', values: [10, 10, 50, 20, 10], color: '#5B8FF9' },
{ cat: 'dal', values: [20, 30, 10, 50, 40], color: '#5AD8A6' },
{ cat: 'uv', values: [10, 50, 30, 20, 30], color: '#5D7092' },
{ cat: 'sal', values: [50, 30, 20, 20, 20], color: '#F6BD16' },
{ cat: 'cal', values: [50, 10, 20, 50, 30], color: '#E8684A' },
],
},
],
edges: [
{
source: 'node1',
target: 'node2',
},
]
}
graph.data(data);
graph.render();
// 为数据的圆点添加hover后变大的动画
graph.on('line-chart-point:mouseenter', e => {
const { target } = e
target.animate(
{ r: 5 },
{ duration: 100, repeat: false }
)
})
graph.on('line-chart-point:mouseleave', e => {
const { target } = e
target.animate(
{ r: 2 },
{ duration: 100, repeat: false }
)
})
// 为数据的圆点添加hover后变大的动画 END
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>