饼图(Pie Chart)做为最多见的统计图表之一,用于可视化数据中不一样分类的占比状况。使用 G2,在不进行任何定制的状况下,用户能够获得以下饼图:除去基本的图形元素外,还提供了 label 文本标注以及图例的绘制能力。同时还提供了 tooltip 提示信息、图例筛选等交互行为。
git
可是一般,用户更倾向于如下饼图的设计及交互:
github
交互层typescript
下面就让咱们来看下,如何基于默认的饼图代码,一步一步快速、简单得定制吧!markdown
默认饼图代码:oop
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(); 复制代码
线上示例连接:g2.antv.vision/zh/examples…spa
扇形变圆环,只需一步!设计
咱们可使用 G2 的自定义图例来实现预期的图例样式,在 G2 4.0 的图例中,咱们开放了 itemName
和 itemName
属性,用于图例内容及样式的配置。
code
具体的定制代码以下:orm
// 声明须要进行自定义图例字段: '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()
方法移除,就获得了下图:
ip
在 G2 V3 版本,自定义图例的交互须要用户操做图形/数据进行实现,而在 G2 4.0 版本,若是无心改变图形元素的响应样式,咱们只须要声明须要的交互便可:
chart.removeInteraction('legend-filter'); // 图例过滤操做默认内置,如不须要能够移除 chart.interaction('element-active'); // 添加 element-active 交互:鼠标 hover 激活图形 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 官网: g2.antv.vision/zh/
github:github.com/antvis/g2