饼图(Pie Chart)作为最常见的统计图表之一,用于可视化数据中不同分类的占比情况。使用 G2,在不进行任何定制的情况下,用户可以得到如下饼图:除去基本的图形元素外,还提供了 label 文本标注以及图例的绘制能力。同时还提供了 tooltip 提示信息、图例筛选等交互行为。
但是通常,用户更倾向于以下饼图的设计及交互:
在定制之前,我们可以看看这两种饼图可视化方式的区别在哪里:
绘制层
- 使用空心环代替实心扇形;
- 图例的个性化定制,将原本 label 的内容同图例内容合并。
交互层
- 图形元素响应鼠标的状态发生改变:从默认的描边变为图形的放大突出;
- 图例的点击筛选变为点击突出图形元素
下面就让我们来看下,如何基于默认的饼图代码,一步一步快速、简单得定制吧!
默认饼图代码:
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, }); chart.data(data); chart.scale('percent', { formatter: (val) => { val = val * 100 + '%'; return val; }, }); chart.tooltip({ showTitle: false, showMarkers: false, }); chart .interval() .position('percent') .color('item') .label('percent', { content: (data) => { return `${data.item}: ${data.percent * 100}%`; }, }) .adjust('stack'); chart.interaction('element-active'); chart.render();
线上示例链接:https://g2.antv.vision/zh/examples/pie/basic
定制坐标系
扇形变圆环,只需一步!
定制图例
我们可以使用 G2 的自定义图例来实现预期的图例样式,在 G2 4.0 的图例中,我们开放了 itemName
和 itemName
属性,用于图例内容及样式的配置。
图例属性对应关系
具体的定制代码如下:
// 声明需要进行自定义图例字段: 'item' chart.legend('item', { position: 'right', // 配置图例显示位置 custom: true, // 关键字段,告诉 G2,要使用自定义的图例 items: data.map((obj, index) => { return { name: obj.item, // 对应 itemName value: obj.percent, // 对应 itemValue marker: { symbol: 'square', // marker 的形状 style: { r: 5, // marker 图形半径 fill: chart.getTheme().colors10[index], // marker 颜色,使用默认颜色,同图形对应 }, }, // marker 配置 }; }), itemValue: { style: { fill: '#999', }, // 配置 itemValue 样式 formatter: val => `${val * 100}%` // 格式化 itemValue 内容 }, });
同时我们将 label()
方法移除,就得到了下图:
定制交互
在 G2 V3 版本,自定义图例的交互需要用户操作图形/数据进行实现,而在 G2 4.0 版本,如果无意改变图形元素的响应样式,我们只需要声明需要的交互即可:
chart.removeInteraction('legend-filter'); // 图例过滤操作默认内置,如不需要可以移除 chart.interaction('element-active'); // 添加 element-active 交互:鼠标 hover 激活图形 active 状态
但是我们需要的是图形元素方法效果,所以我们需要配置下图形元素 active 状态的样式:
chart .interval() .state({ active: { style: element => { const shape = element.shape; return { lineWidth: 10, stroke: shape.attr('fill'), strokeOpacity: shape.attr('fillOpacity'), }; }, // 配置 active 样式,通过加粗边框实现放大效果 }, });
至此,三个步骤,个性化饼图的定制就结束了!
扩展
基于以上定制,我们还可以作进一步扩展,利用圆环空心部分的面积显示鼠标击中图形元素的详细信息,以代替 tooltip。当然这也并不麻烦,我们只需要:
关闭 Tooltip
chart.tooltip(false);
在现有交互行为的基础上,添加 callback
,更新 annotation 内容
// 绘制 annotation let lastItem; function updateAnnotation(data) { if (data.item !== lastItem) { chart.annotation().clear(true); chart .annotation() .text({ position: ['50%', '50%'], content: data.item, style: { fontSize: 20, fill: '#8c8c8c', textAlign: 'center', }, offsetY: -20, }) .text({ position: ['50%', '50%'], content: data.count, style: { fontSize: 28, fill: '#8c8c8c', textAlign: 'center', }, offsetX: -10, offsetY: 20, }) .text({ position: ['50%', '50%'], content: '台', style: { fontSize: 20, fill: '#8c8c8c', textAlign: 'center', }, offsetY: 20, offsetX: 20, }); chart.render(true); lastItem = data.item; } } // 清空 annotation function clearAnnotation() { chart.annotation().clear(true); chart.render(true); lastItem = null; } // 在现有 'element-active' 交互行为的基础上加上 callback 配置,用于动态更新 Annotation // 'element-active' 定义:https://github.com/antvis/G2/blob/fdf485ce218f905b5416cb91e0e421b85a1b6925/src/index.ts#L264 chart.interaction('element-active', { start: [{ trigger: 'element:mouseenter', action: 'element-active:active', callback(context) { if (context.event.data) { updateAnnotation(context.event.data.data); } }, }], end: [{ trigger: 'element:mouseleave', action: 'element-active:reset', callback() { clearAnnotation(); } }], }); // 在现有 'legend-active' 交互行为的基础上加上 callback 配置,用于动态更新 Annotation // 'legend-active' 定义:https://github.com/antvis/G2/blob/fdf485ce218f905b5416cb91e0e421b85a1b6925/src/index.ts#L293 chart.interaction('legend-active', { showEnable: [ { trigger: 'legend-item:mouseenter', action: 'cursor:pointer' }, { trigger: 'legend-item:mouseleave', action: 'cursor:default' }, ], start: [{ trigger: 'legend-item:mouseenter', action: ['list-active:active', 'element-active:active'], callback(context) { const delegateObject = context.event.gEvent.shape.get('delegateObject'); const targetData = data.filter(obj => obj.item === delegateObject.item.name); if (targetData.length) { updateAnnotation(targetData[0]); } } }], end: [{ trigger: 'legend-item:mouseleave', action: ['list-active:reset', 'element-active:reset'], callback(context) { clearAnnotation(); } }], });
完整代码传送门: 链接
网址
G2 官网: https://g2.antv.vision/zh/
github:https://github.com/antvis/g2
来源:oschina
链接:https://my.oschina.net/antv/blog/3196656