Skip to content

Commit b15334d

Browse files
authored
refactor(ring): 环图中心文本统一结构 (#1590)
1 parent 51bcb18 commit b15334d

File tree

8 files changed

+82
-259
lines changed

8 files changed

+82
-259
lines changed

__tests__/unit/plots/pie/interaction-spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ describe('register interaction', () => {
4545

4646
const annotations = context.view.getComponents().filter((co) => co.type === 'annotation');
4747
expect(annotations[0].extra.content).toBe('item3');
48-
expect(annotations[1].extra.content).toBe(13);
48+
expect(annotations[1].extra.content).toBe('13');
4949
});
5050

5151
it('触发 pie-statistic:reset', async () => {

__tests__/unit/plots/pie/statistic-spec.ts

+31-93
Original file line numberDiff line numberDiff line change
@@ -87,16 +87,17 @@ describe('中心文本 - 指标卡', () => {
8787
});
8888

8989
it('自定义中心文本内容: title & content, 动态数据', () => {
90+
const totalValue = config.data.reduce((a, b) => a + b.value, 0);
9091
const pie = new Pie(createDiv(), {
9192
...config,
9293
innerRadius: 0.64,
9394
statistic: {
9495
title: {
95-
formatter: (item, data) => (Array.isArray(data) ? '总计' : data['type']),
96+
formatter: (datum) => (!datum ? '总计' : datum['type']),
9697
},
9798
content: {
98-
formatter: (item, data) => {
99-
return Array.isArray(data) ? 'test\ntest' : typeof data.value === 'number' ? `${data.value}` : '';
99+
formatter: (datum, data) => {
100+
return !datum ? `test\ntest ${data.reduce((a, b) => a + b.value, 0)}` : `${datum.value}`;
100101
},
101102
rotate: (30 / 180) * Math.PI,
102103
},
@@ -108,7 +109,7 @@ describe('中心文本 - 指标卡', () => {
108109
const annotations = getAnnotations(pie.chart);
109110
expect(annotations.length).toBeGreaterThan(0);
110111
expect(annotations[0].component.get('content')).toBe('总计');
111-
expect(annotations[1].component.get('content')).toBe('test\ntest');
112+
expect(annotations[1].component.get('content')).toBe(`test\ntest ${totalValue}`);
112113
});
113114

114115
it('自定义中心文本内容: update statistic title & content, 动态数据', async () => {
@@ -117,11 +118,11 @@ describe('中心文本 - 指标卡', () => {
117118
...pie.options,
118119
statistic: {
119120
title: {
120-
formatter: (item, data) => (Array.isArray(data) ? '总计' : data['type']),
121+
formatter: (datum) => (!datum ? '总计' : datum['type']),
121122
},
122123
content: {
123-
formatter: (item, data) => {
124-
return Array.isArray(data) ? 'test\ntest' : typeof data.value === 'number' ? `${data.value}` : '';
124+
formatter: (datum) => {
125+
return !datum ? 'test\ntest' : `${datum.value}`;
125126
},
126127
rotate: (30 / 180) * Math.PI,
127128
},
@@ -184,92 +185,29 @@ describe('中心文本 - 指标卡', () => {
184185
expect(annotations[1].extra.style).toMatchObject({ fill: 'pink' });
185186
});
186187

187-
// 暂时不提供 annotations 配置
188-
// it('append annotation', () => {
189-
// const pie = new Pie(createDiv(), {
190-
// ...config,
191-
// innerRadius: 0.64,
192-
// statistic: {
193-
// title: {
194-
// formatter: () => '',
195-
// },
196-
// content: {
197-
// formatter: () => '无数据',
198-
// },
199-
// },
200-
// annotations: [
201-
// {
202-
// type: 'text',
203-
// top: true,
204-
// position: ['50%', '20%'],
205-
// content: '达标区间',
206-
// style: {
207-
// fill: '#aaaaaa',
208-
// textAlign: 'end',
209-
// textBaseline: 'top',
210-
// fontWeight: 300,
211-
// },
212-
// offsetX: -10,
213-
// offsetY: 6,
214-
// },
215-
// ],
216-
// });
217-
218-
// pie.render();
219-
// const annotations = getAnnotations(pie.chart);
220-
// expect(annotations.length).toBe(3);
221-
// expect(annotations[0].component.get('type')).toBe('text');
222-
// expect(annotations[0].extra.content).toBe('达标区间');
223-
// expect(annotations[1].extra.content).toBe('');
224-
// });
225-
226-
// it('关闭 stastic,自定义 annotation', async () => {
227-
// const pie = new Pie(createDiv(), {
228-
// ...config,
229-
// innerRadius: 0.64,
230-
// statistic: null,
231-
// annotations: [
232-
// {
233-
// type: 'image',
234-
// position: ['50%', '50%'],
235-
// src: 'https://gw.alipayobjects.com/zos/antfincdn/FLrTNDvlna/antv.png',
236-
// offsetX: -28,
237-
// offsetY: 30,
238-
// style: {
239-
// width: 56,
240-
// height: 56,
241-
// },
242-
// },
243-
// ],
244-
// });
245-
246-
// pie.render();
247-
248-
// const annotations = getAnnotations(pie.chart);
249-
// expect(annotations.length).toBe(1);
250-
// expect(annotations[0].component.get('type')).toBe('image');
251-
252-
// await delay(500);
253-
// pie.update({
254-
// ...pie.options,
255-
// annotations: [
256-
// {
257-
// type: 'text',
258-
// position: ['50%', '50%'],
259-
// content: '自定义标注文本',
260-
// style: {
261-
// textAlign: 'center',
262-
// },
263-
// },
264-
// ],
265-
// });
266-
// pie.render();
267-
268-
// const newAnnotations = getAnnotations(pie.chart);
269-
// expect(newAnnotations.length).toBe(1);
270-
// expect(newAnnotations[0].component.get('type')).toBe('text');
271-
// expect(newAnnotations[0].component.get('content')).toBe('自定义标注文本');
272-
// });
188+
it('自定义中心文本样式: with callback', async () => {
189+
await delay(500);
190+
pie.update({
191+
...pie.options,
192+
statistic: {
193+
title: {
194+
formatter: () => '',
195+
style: { fill: 'red' },
196+
},
197+
content: {
198+
style: { fill: 'pink' },
199+
},
200+
},
201+
});
202+
203+
pie.render();
204+
const annotations = getAnnotations(pie.chart);
205+
expect(annotations.length).toBe(2);
206+
expect(annotations[0].component.get('content')).toBe('');
207+
expect(annotations[0].extra.key).toBe('statistic');
208+
expect(annotations[0].extra.style).toMatchObject({ fill: 'red' });
209+
expect(annotations[1].extra.style).toMatchObject({ fill: 'pink' });
210+
});
273211

274212
it('总计值为空', () => {
275213
const pie = new Pie(createDiv(), {

__tests__/unit/plots/pie/utils-spec.ts

+1-40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
import { Pie } from '../../../../src';
2-
import { createDiv } from '../../../utils/dom';
3-
import { getStatisticData, getTotalValue, parsePercentageToNumber } from '../../../../src/plots/pie/utils';
1+
import { getTotalValue, parsePercentageToNumber } from '../../../../src/plots/pie/utils';
42

53
describe('utils of pie plot', () => {
64
const data = [
@@ -49,43 +47,6 @@ describe('utils of pie plot', () => {
4947
).toBe(null);
5048
});
5149

52-
it('getStatisticData: 单色饼图', () => {
53-
const pie = new Pie(createDiv(), {
54-
width: 400,
55-
height: 300,
56-
data: [],
57-
angleField: 'value',
58-
radius: 0.8,
59-
});
60-
61-
pie.render();
62-
const angleScale = pie.chart.getScaleByField('value');
63-
const colorScale = pie.chart.getScaleByField('');
64-
expect(getStatisticData({ value: 20 }, angleScale, colorScale)).toEqual({ title: null, value: '20' });
65-
});
66-
67-
it('getStatisticData: 带 colorField', () => {
68-
const pie = new Pie(createDiv(), {
69-
width: 400,
70-
height: 300,
71-
data: [
72-
{ type: 'item1', value: 20 },
73-
{ type: 'item2', value: 20 },
74-
],
75-
angleField: 'value',
76-
colorField: 'type',
77-
radius: 0.8,
78-
});
79-
80-
pie.render();
81-
const angleScale = pie.chart.getScaleByField('value');
82-
const colorScale = pie.chart.getScaleByField('type');
83-
expect(getStatisticData({ type: 'item1', value: 20 }, angleScale, colorScale)).toEqual({
84-
title: 'item1',
85-
value: '20',
86-
});
87-
});
88-
8950
it('将 字符串百分比 转换为 数值型百分比', () => {
9051
// @ts-ignore 不合法的入参
9152
expect(parsePercentageToNumber(null)).toBe(null);

src/plots/pie/adaptor.ts

+30-71
Original file line numberDiff line numberDiff line change
@@ -168,13 +168,11 @@ function label(params: Params<PieOptions>): Params<PieOptions> {
168168
}
169169

170170
/**
171-
* annotation 配置
172-
* 内置标注:
173-
* 1. 中心文本
171+
* statistic 中心文本配置
174172
* @param params
175173
*/
176-
function pieAnnotation(params: Params<PieOptions>): Params<PieOptions> {
177-
const { options } = params;
174+
function statistic(params: Params<PieOptions>): Params<PieOptions> {
175+
const { chart, options } = params;
178176
const { innerRadius, statistic, angleField } = options;
179177

180178
const annotationOptions = [];
@@ -183,82 +181,41 @@ function pieAnnotation(params: Params<PieOptions>): Params<PieOptions> {
183181
if (innerRadius && statistic) {
184182
const { title, content } = statistic;
185183

186-
let statisticTitle: Annotation = {
187-
type: 'text',
188-
content: '',
189-
position: ['50%', '50%'],
190-
};
191-
let statisticContent: Annotation = {
192-
type: 'text',
193-
content: '',
194-
position: ['50%', '50%'],
195-
};
196-
197-
const getStatisticData = (data: Data) => ({
198-
title: '总计',
199-
value: getTotalValue(data, angleField),
200-
});
201-
202-
if (title !== false) {
203-
let titleLineHeight = get(title, 'style.lineHeight');
204-
if (!titleLineHeight) {
205-
titleLineHeight = get(title, 'style.fontSize', 20);
184+
[title, content].forEach((option, index) => {
185+
if (option === false) {
186+
return;
206187
}
207-
const titleFormatter = get(title, 'formatter');
188+
const { style, formatter, offsetX, offsetY, rotate } = option;
208189

209-
statisticTitle = {
210-
type: 'text',
211-
position: ['50%', '50%'],
212-
content: (filterData: Data) => {
213-
const statisticData = getStatisticData(filterData);
214-
return titleFormatter ? titleFormatter(statisticData, filterData) : statisticData.title;
215-
},
216-
...deepMix(
190+
const lineHeight = get(option, 'style.fontSize', 20);
191+
chart.annotation().text(
192+
deepMix(
217193
{},
218194
{
219-
offsetY: content === false ? 0 : -titleLineHeight,
220-
// append-info
221-
key: 'statistic',
222195
style: {
223196
textAlign: 'center',
224197
},
198+
offsetY: index === 0 ? (content === false ? 0 : -lineHeight) : title === false ? 0 : lineHeight,
225199
},
226-
title
227-
),
228-
};
229-
}
230-
231-
if (content !== false) {
232-
let valueLineHeight = get(content, 'style.lineHeight');
233-
if (!valueLineHeight) {
234-
valueLineHeight = get(content, 'style.fontSize', 20);
235-
}
236-
const contentFormatter = get(content, 'formatter');
237-
238-
statisticContent = {
239-
type: 'text',
240-
position: ['50%', '50%'],
241-
content: (filterData: Data) => {
242-
const statisticData = getStatisticData(filterData);
243-
return contentFormatter ? contentFormatter(statisticData, filterData) : statisticData.value;
244-
},
245-
...deepMix(
246-
{},
247200
{
248-
// 居中
249-
offsetY: title === false ? 0 : valueLineHeight,
201+
position: ['50%', '50%'],
202+
content: (filterData: Data) => {
203+
return formatter
204+
? formatter(null, filterData)
205+
: index === 0
206+
? '总计'
207+
: getTotalValue(filterData, angleField);
208+
},
209+
style,
210+
offsetX,
211+
offsetY,
212+
rotate,
250213
// append-info
251214
key: 'statistic',
252-
style: {
253-
textAlign: 'center',
254-
},
255-
},
256-
content
257-
),
258-
};
259-
}
260-
261-
annotationOptions.push(statisticTitle, statisticContent);
215+
}
216+
)
217+
);
218+
});
262219
}
263220

264221
return flow(annotation(annotationOptions))(params);
@@ -280,7 +237,9 @@ export function adaptor(params: Params<PieOptions>) {
280237
tooltip,
281238
label,
282239
state,
283-
pieAnnotation,
240+
annotation(),
241+
/** 指标卡中心文本 放在下层 */
242+
statistic,
284243
interaction,
285244
animation
286245
)(params);

src/plots/pie/interaction/pie-statistic-action.ts

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { Action } from '@antv/g2/lib/interaction';
22
import { ComponentOption } from '@antv/g2/lib/interface';
3-
import { each, get } from '@antv/util';
4-
import { getStatisticData } from '../utils';
3+
import { each, get, isFunction } from '@antv/util';
54

65
/**
76
* Pie 中心文本事件的 Action
@@ -43,13 +42,19 @@ export class StatisticAction extends Action {
4342

4443
const annotationOptions = annotations.filter((a) => get(a, 'extra.key') !== 'statistic').map((a) => a.extra);
4544
const statisticOptions = annotations.filter((a) => get(a, 'extra.key') === 'statistic').map((a) => a.extra || {});
46-
const statisticData = getStatisticData(data, angleScale, colorScale);
4745

4846
each(statisticOptions, (options, idx) => {
49-
const value = data[idx === 0 ? colorField : angleField];
47+
let value;
48+
if (idx === 0) {
49+
// title
50+
value = colorScale ? colorScale.getText(data[colorField]) : null;
51+
} else {
52+
value = angleScale ? angleScale.getText(data[angleField]) : data[angleField];
53+
}
54+
5055
annotationOptions.push({
5156
...options,
52-
content: options.formatter ? options.formatter(statisticData, data) : value,
57+
content: options.formatter ? options.formatter(data, view.getData()) : value,
5358
});
5459
});
5560
annotationOptions.forEach((opt) => {

0 commit comments

Comments
 (0)