大屏页面中绘制的统计图实现动态变换的效果
在项目中,有一个大屏页面,主要是对项目中的数据进行整体的展示,既然是大屏,那么就不会是“死页面”,就必然要有动态效果。其中有一个需求就是让 通过antv g2绘制出的环图动起来,主要是动态改变图标每一项的样式,以及中间的Annotation。
基本样式就是这样
主要是要让他动态的放大某项并且中间的annotation也要展示对应已经放大项的数据;
在官网中查阅,基本上都是通过鼠标hover到图表项或者图例项时会出现想要的联动样式效果,这里可以参考这个实例 饼图图例联动
通过研究这个实例发现,其本质就是通过修改图表项的一个state状态来实现联动效果,因此抱着试一试的想法,开始了探索之路。。。
1、首先把图表画出来
我这里还是先用官网的数据和绘图方式,就是我上面的拿个链接
import { Chart } from '@antv/g2';
const data = [
{ item: '事例一', count: 40, percent: 0.4 },
{ item: '事例二', count: 21, percent: 0.21 },
{ item: '事例三', count: 17, percent: 0.17 },
{ item: '事例四', count: 13, percent: 0.13 },
{ item: '事例五', count: 9, percent: 0.09 },
];
const chart = new Chart({
container: 'container',
autoFit: true,
height: 500,
});
chart.coordinate('theta', {
radius: 0.75,
innerRadius: 0.6,
});
chart.data(data);
chart.scale('percent', {
formatter: val => {
val = val * 100 + '%';
return val;
},
});
chart.tooltip(false);
// 这里记得要const一下 不然之后的方法中使用interval时会显示undefined
const interval = chart
.interval()
.adjust('stack')
.position('percent')
.color('item',['#5b8ff9','#5ad8a6','#5d7092','#f6bd16','#e86452'])
.style({
fillOpacity: 1,
})
// 定义active状态下的样式
.state({
active: {
style: element => {
const shape = element.shape;
return {
lineWidth: 10,
stroke: shape.attr('fill'),
strokeOpacity: shape.attr('fillOpacity'),
};
},
},
});
chart.render();
2、之后在官网实例的页面通过打印观察图表项的变化
通过这里可以看到,主要是通过修改图表中某项的state和stateStatus来修改选中与否的状态,从而实现后期的动态效果
通过打印可以看到ev中的数据
通过这里就能发现,实例中就是通过监听这个active状态修改图表中的Annotation内容以及图表项的active状态的样式,于是,可以通过定时器,定时修改某一项的active状态
/*
由于我这里是要实现五个部分循环动态切换active状态,所以在循环的时候指定了i的范围,后期大家可以根据自己的需求自行修改代码
*/
// 通过定时器定时修改active状态
let i = 0
setInterval(()=>{
if(i > 4){
i=0
}
changeStatus(i)
i++
},2000)
// 修改状态时不仅要修改当前项为active,也要记得清空其他项的active状态
function changeStatus(i){
if(i>=1){
// 这里一定要用自带的setState方法,而不要直接变成true
interval.elements[i].setState('active',true)
interval.elements[i].stateStatus = true
// 这里一定要用自带的clearStates方法,而不要直接变成false
interval.elements[(i-1)].clearStates()
interval.elements[(i-1)].stateStatus = false
const state = interval.elements[i].states[0]
const stateStatus = interval.elements[i].stateStatus
let eledata = interval.elements[i].data
if (state === 'active') {
if (stateStatus) {
// 更新 Annotation
updateAnnotation(eledata);
} else {
// 隐藏 Annotation
clearAnnotation();
}
}
}else {
// 临界情况单独考虑
interval.elements[i].setState('active',true)
interval.elements[i].stateStatus = true
interval.elements[4].clearStates()
interval.elements[4].stateStatus = false
const state = interval.elements[i].states[0]
const stateStatus = interval.elements[i].stateStatus
let eledata = interval.elements[i].data
if (state === 'active') {
if (stateStatus) {
// 更新 Annotation
updateAnnotation(eledata);
} else {
// 隐藏 Annotation
clearAnnotation();
}
}
}
}
3、之后就可以自定义Annotation内容样式,以及清空annotation的方法
// 绘制 annotation
let lastItem;
function updateAnnotation(data) {
if (data.item !== lastItem) {
chart.annotation().clear(true);
chart
.annotation()
.text({
position: ['50%', '50%'],
content: data.count+'%',
style: {
fontSize: 26,
fill: '#ffe200',
textAlign: 'center',
},
offsetY: -10,
})
.text({
position: ['50%', '50%'],
content: data.item,
style: {
fontSize: 14,
fill: '#000000',
textAlign: 'center',
},
offsetX: 0,
offsetY: 20,
})
chart.render(true);
lastItem = data.item;
}
}
// 清空 annotation
function clearAnnotation() {
chart.annotation().clear(true);
chart.render(true);
lastItem = null;
}
至此,随着整个过程中的各种“七拼八凑”,总算是实现了功能。不过也不是自己瞎凑,也是一直在查阅官方api的,由此得出结论,基础的api还是好东西,api吃透的,啥都不是事~
前端小菜鸡的第一篇博客,希望能帮助到看到的小伙伴们,如果各位大佬有什么更简单更高效的方法,也希望能收到您的私信分享,非常感谢~