Skip to content

Commit 4c42f51

Browse files
authored
fix: pie tooltip (#2312)
* fix(issue-2220): 修复饼图 tooltip 配置问题 close: #2220 * test(pie-tooltip): 饼图 tooltip 添加单测 * test(pie-adaptor): 补充单测 Co-authored-by: kasmine <visiky>
1 parent 7692fcb commit 4c42f51

File tree

5 files changed

+152
-13
lines changed

5 files changed

+152
-13
lines changed

__tests__/bugs/issue-2220-spec.ts

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import { Pie } from '../../src/plots/pie';
2+
import { delay } from '../utils/delay';
3+
import { createDiv } from '../utils/dom';
4+
5+
describe('pie tooltip', () => {
6+
const div = createDiv();
7+
const data = [
8+
{ type: 'x', value: 0, city: 'HZ' },
9+
{ type: 'y', value: 0, city: 'SZ' },
10+
];
11+
const pie = new Pie(div, {
12+
data,
13+
angleField: 'value',
14+
colorField: 'type',
15+
});
16+
pie.render();
17+
18+
it('#2220, tooltip display not same as normal when data ara all zero', async () => {
19+
const box = pie.chart.geometries[0].elements[0].shape.getBBox();
20+
const point = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
21+
22+
await delay(100);
23+
pie.chart.showTooltip(point);
24+
await delay(100);
25+
const tooltipName = div.querySelector('.g2-tooltip .g2-tooltip-name');
26+
expect((tooltipName as HTMLElement).innerText).toBe('x');
27+
});
28+
29+
it('formatter works. before: when fields is empty, formatter not works', async () => {
30+
pie.update({ tooltip: { fields: [], formatter: () => ({ name: 'xxx', value: 'yyy' }) } });
31+
const tooltipController = pie.chart.getController('tooltip');
32+
const box = pie.chart.geometries[0].elements[0].shape.getBBox();
33+
const point = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
34+
35+
await delay(100);
36+
pie.chart.showTooltip(point);
37+
await delay(100);
38+
// @ts-ignore
39+
let items = tooltipController.getTooltipItems(point);
40+
expect(items[0].name).toBe('xxx');
41+
expect(items[0].value).toBe('yyy');
42+
43+
pie.update({ tooltip: { fields: null, formatter: () => ({ name: 'xxx', value: 'yyy' }) } });
44+
45+
pie.chart.showTooltip(point);
46+
await delay(100);
47+
// @ts-ignore
48+
items = tooltipController.getTooltipItems(point);
49+
expect(items[0].name).toBe('xxx');
50+
expect(items[0].value).toBe('yyy');
51+
});
52+
53+
afterEach(() => {
54+
pie.chart.clear();
55+
});
56+
57+
afterAll(() => {
58+
pie.destroy();
59+
});
60+
});

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@ describe('饼图 异常数据', () => {
4444
});
4545

4646
it('数据全部为 0, 设置 angleField meta', async () => {
47-
const pie = new Pie(createDiv(), {
47+
const div = createDiv();
48+
const pie = new Pie(div, {
4849
width: 400,
4950
height: 400,
5051
data,
@@ -70,10 +71,12 @@ describe('饼图 异常数据', () => {
7071
const labels = pie.chart.geometries[0].labelsContainer.getChildren();
7172
expect(every(labels, (label) => (label as IGroup).getChildren()[0].attr('text') === '0 个')).toBe(true);
7273

74+
// 数据全 0 的时候,tooltip-items 应该和正常保持一致,只有一条
7375
const positionFields = pie.chart.geometries[0].getAttribute('position').getFields();
7476
const point = pie.chart.getXY({ 1: data[0].type, [positionFields[1]]: 1 / data.length });
7577
const tooltipItems = pie.chart.getTooltipItems(point);
76-
expect(tooltipItems[1].value).toBe('0 个');
78+
expect(tooltipItems[0].name).toBe(data[0].type);
79+
expect(tooltipItems[0].value).toBe(0);
7780

7881
pie.destroy();
7982
});
@@ -120,7 +123,7 @@ describe('饼图 异常数据', () => {
120123
expect(every(labels, (label) => (label as IGroup).getChildren()[0].attr('text') === 1)).toBe(true);
121124
const point = pie.chart.getXY({ 1: '类型 1', value: 1 });
122125
const tooltipItems = pie.chart.getTooltipItems(point);
123-
expect(tooltipItems[0].value).toBe('1');
126+
expect(tooltipItems[0].value).toBe(1);
124127

125128
pie.destroy();
126129
});

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

+4
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ describe('中心文本 - 指标卡', () => {
7373
pie.update({ meta: { value: { formatter: (v) => `${v}¥` } }, statistic: { content: {} } });
7474
htmlAnnotations = document.querySelectorAll('.g2-html-annotation');
7575
expect((htmlAnnotations[1] as HTMLElement).innerText).toBe(`${data.reduce((a, b) => a + b.value, 0)}¥`);
76+
77+
pie.update({ meta: { value: { formatter: undefined } }, statistic: { content: {} } });
78+
htmlAnnotations = document.querySelectorAll('.g2-html-annotation');
79+
expect((htmlAnnotations[1] as HTMLElement).innerText).toBe(`${data.reduce((a, b) => a + b.value, 0)}`);
7680
});
7781

7882
it('自定义中心文本内容: update statistic title & content', () => {
+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { Pie } from '../../../../src/plots/pie';
2+
import { delay } from '../../../utils/delay';
3+
import { createDiv } from '../../../utils/dom';
4+
5+
describe('pie tooltip', () => {
6+
const div = createDiv();
7+
const data = [
8+
{ type: 'x', value: 0, city: 'HZ' },
9+
{ type: 'y', value: 0, city: 'SZ' },
10+
];
11+
const pie = new Pie(div, {
12+
data,
13+
angleField: 'value',
14+
colorField: 'type',
15+
});
16+
pie.render();
17+
18+
it('close tooltip', () => {
19+
// @ts-ignore
20+
expect(pie.chart.options.tooltip).not.toBe(false);
21+
// @ts-ignore
22+
expect(pie.chart.getController('tooltip').isVisible()).toBe(true);
23+
pie.update({ tooltip: false });
24+
// @ts-ignore
25+
expect(pie.chart.options.tooltip).toBe(false);
26+
// @ts-ignore
27+
expect(pie.chart.getController('tooltip').isVisible()).toBe(false);
28+
});
29+
30+
it('formatter work in normal cases', async () => {
31+
pie.update({
32+
tooltip: {
33+
fields: ['type', 'value', 'city'],
34+
formatter: (datum) => ({ name: `${datum.city}-${datum.type}`, value: `${datum.value}-xxxx` }),
35+
},
36+
});
37+
38+
const tooltipController = pie.chart.getController('tooltip');
39+
const box = pie.chart.geometries[0].elements[0].shape.getBBox();
40+
const point = { x: box.x + box.width / 2, y: box.y + box.height / 2 };
41+
42+
pie.chart.showTooltip(point);
43+
await delay(100);
44+
// @ts-ignore
45+
const items = tooltipController.getTooltipItems(point);
46+
expect(items[0].name).toBe(`${data[0].city}-${data[0].type}`);
47+
expect(items[0].value).toBe(`${data[0].value}-xxxx`);
48+
});
49+
50+
afterEach(() => {
51+
pie.chart.clear();
52+
});
53+
54+
afterAll(() => {
55+
pie.destroy();
56+
});
57+
});

src/plots/pie/adaptor.ts

+25-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { isFunction, isString, isNil, get, isArray, isNumber } from '@antv/util';
22
import { Params } from '../../core/adaptor';
3-
import { legend, tooltip, interaction, animation, theme, state, annotation } from '../../adaptor/common';
3+
import { legend, interaction, animation, theme, state, annotation } from '../../adaptor/common';
4+
import { getMappingFunction } from '../../adaptor/geometries/base';
45
import { interval } from '../../adaptor/geometries';
56
import { flow, template, transformLabel, deepAssign, renderStatistic } from '../../utils';
67
import { DEFAULT_OPTIONS } from './contants';
@@ -41,9 +42,6 @@ function geometry(params: Params<PieOptions>): Params<PieOptions> {
4142
});
4243

4344
interval(p);
44-
45-
// all zero 额外处理
46-
chart.geometries[0].tooltip(`${colorField}*${angleField}`);
4745
} else {
4846
chart.data(processData);
4947

@@ -208,13 +206,30 @@ export function pieAnnotation(params: Params<PieOptions>): Params<PieOptions> {
208206
}
209207

210208
/**
211-
* 饼图 tooltip 配置适配,强制 tooltip.shared 为 false
209+
* 饼图 tooltip 配置
210+
* 1. 强制 tooltip.shared 为 false
212211
* @param params
213212
*/
214-
function adaptorTooltipOptions(params: Params<PieOptions>): Params<PieOptions> {
215-
return get(params, ['options', 'tooltip']) !== false
216-
? deepAssign({}, params, { options: { tooltip: { shared: false } } })
217-
: params;
213+
function tooltip(params: Params<PieOptions>): Params<PieOptions> {
214+
const { chart, options } = params;
215+
const { tooltip, colorField, angleField } = options;
216+
217+
if (tooltip === false) {
218+
chart.tooltip(tooltip);
219+
} else {
220+
chart.tooltip(deepAssign({}, tooltip, { shared: false }));
221+
222+
const fields = get(tooltip, 'fields') || [colorField, angleField];
223+
let formatter = get(tooltip, 'formatter');
224+
225+
if (!formatter) {
226+
// 主要解决 all zero, 对于非 all zero 也适用
227+
formatter = (datum) => ({ name: datum[colorField], value: datum[angleField] });
228+
}
229+
chart.geometries[0].tooltip(fields.join('*'), getMappingFunction(fields, formatter));
230+
}
231+
232+
return params;
218233
}
219234

220235
/**
@@ -230,7 +245,7 @@ export function adaptor(params: Params<PieOptions>) {
230245
theme,
231246
coordinate,
232247
legend,
233-
(args) => tooltip(adaptorTooltipOptions(args)),
248+
tooltip,
234249
label,
235250
state,
236251
/** 指标卡中心文本 放在下层 */

0 commit comments

Comments
 (0)