Skip to content

Commit bec4bb1

Browse files
Angelii酥云
andauthored
fix(label): 处理venn图label遮挡问题 (#2861)
* fix(label): 处理venn图label遮挡问题 * refactor(lint): 处理lint的问题,删去多余变量 * fix(label): 修复标签文字呈现问题 * refactor(demo): 修改venn图的demo数据 * refactor(demo): 修改venn图的demo数据 * refactor: 调整包大小 * fix(label): 修复labelsContainer的单测问题 Co-authored-by: 酥云 <[email protected]>
1 parent 45c8a5f commit bec4bb1

File tree

10 files changed

+105
-61
lines changed

10 files changed

+105
-61
lines changed

__tests__/unit/plots/funnel/label-spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ describe('label', () => {
4242
},
4343
});
4444

45-
labelsContainer.cfg.children.forEach((item, index) => {
45+
funnel.chart.geometries[0].labelsContainer.cfg.children.forEach((item, index) => {
4646
expect(item.get('children')[0].attr('text')).toBe(`行为:${data[index].action}`);
4747
});
4848
// @ts-ignore

__tests__/unit/plots/venn/index-spec.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,9 @@ describe('venn', () => {
3131
expect((elements[0].getData() as any).size).toBe(10);
3232
// path: [['M', ...], ['A', rx ry 0 1 0 x y], ...]
3333
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path');
34-
const label = (elements[0].shape as IGroup).getChildren()[1];
35-
expect(label.get('name')).toBe('venn-label');
3634
expect(path[0][0]).toBe('M');
3735
expect(path[1][0]).toBe('A');
3836
expect(path[2][0]).toBe('A');
39-
expect((elements[0].getData() as any).radius).toBe(400 / 2);
4037
expect(path[1][1]).toBe(400 / 2);
4138
});
4239

@@ -53,8 +50,6 @@ describe('venn', () => {
5350
expect(elements[1].getModel().size).toBe(1);
5451
// path: [['M', ...], ['A', rx ry 0 1 0 x y], ...]
5552
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path');
56-
const label = (elements[0].shape as IGroup).getChildren()[1];
57-
expect(label.get('name')).toBe('venn-label');
5853
expect(path[0][0]).toBe('M');
5954
expect(path[1][0]).toBe('A');
6055
expect(path[2][0]).toBe('A');
@@ -85,8 +80,6 @@ describe('venn', () => {
8580
expect((elements[2].getData() as any).size).toBe(4);
8681
// path: [['M', ...], ['A', rx ry 0 1 0 x y], ...]
8782
const path = (elements[0].shape as IGroup).getChildren()[0].attr('path');
88-
const label = (elements[0].shape as IGroup).getChildren()[1];
89-
expect(label.get('name')).toBe('venn-label');
9083
expect(path[0][0]).toBe('M');
9184
expect(path[1][0]).toBe('A');
9285
expect(path[2][0]).toBe('A');
@@ -125,8 +118,8 @@ describe('venn', () => {
125118
// 中心点
126119
expect((elements[6].getData() as any).x).toBeCloseTo(200);
127120
// 元素对齐
128-
expect(elements[2].getData().x).toBeCloseTo((elements[6].getData() as any).x);
129-
expect(elements[0].getData().y).toBeCloseTo((elements[1].getData() as any).y);
121+
expect(elements[2].getData().x).toBeCloseTo((elements[6].getData() as any).x, 1);
122+
expect(elements[0].getData().y).toBeCloseTo((elements[1].getData() as any).y, 1);
130123
});
131124

132125
it('defaultOptions 保持从 constants 中获取', () => {

__tests__/unit/plots/venn/label-spec.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,23 @@ describe('venn: label', () => {
1919
});
2020
plot.render();
2121

22+
it('label', () => {
23+
const geometries = plot.chart.geometries[0];
24+
// @ts-ignore
25+
expect(geometries.labelOption.cfg).not.toBeUndefined();
26+
expect(geometries.labelsContainer.getChildren().length).toBe(6);
27+
});
28+
2229
it('label: offset', () => {
2330
plot.update({
2431
label: {
2532
offsetY: 6,
2633
},
2734
});
35+
36+
const geometries = plot.chart.geometries[0];
2837
// @ts-ignore
29-
expect(plot.chart.geometries[0].customOption.label.offsetY).toBe(6);
38+
expect(geometries.labelOption.cfg.offsetY).toBe(6);
3039
});
3140

3241
it('label: style', () => {
@@ -39,12 +48,14 @@ describe('venn: label', () => {
3948
},
4049
},
4150
});
51+
52+
const geometries = plot.chart.geometries[0];
4253
// @ts-ignore
43-
expect(plot.chart.geometries[0].customOption.label.style.textAlign).toBe('center');
54+
expect(geometries.labelOption.cfg.style.textAlign).toBe('center');
4455
// @ts-ignore
45-
expect(plot.chart.geometries[0].customOption.label.style.fill).toBe('red');
56+
expect(geometries.labelOption.cfg.style.fill).toBe('red');
4657
// @ts-ignore
47-
expect(plot.chart.geometries[0].customOption.label.style.lineHeight).toBe(18);
58+
expect(geometries.labelOption.cfg.style.lineHeight).toBe(18);
4859
});
4960

5061
it('label: formatter', () => {
@@ -60,16 +71,18 @@ describe('venn: label', () => {
6071
formatter,
6172
},
6273
});
74+
const geometries = plot.chart.geometries[0];
6375
// @ts-ignore
64-
expect(plot.chart.geometries[0].customOption.label.formatter).toEqual(formatter);
76+
expect(geometries.labelOption.cfg.formatter).toEqual(formatter);
6577
});
6678

6779
it('label: false', () => {
6880
plot.update({
6981
label: false,
7082
});
83+
const geometries = plot.chart.geometries[0];
7184
// @ts-ignore
72-
expect(plot.chart.geometries[0].customOption.label).toEqual(false);
85+
expect(geometries.labelOption).toEqual(false);
7386
});
7487

7588
afterAll(() => {

__tests__/unit/plots/venn/padding-spec.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,6 @@ describe('venn padding', () => {
133133
padding: 250,
134134
});
135135
plot.chart.geometries[0].data.forEach((datum) => {
136-
if (datum.sets.length === 1) {
137-
expect(datum.radius).toBe(0);
138-
}
139136
expect(datum.x).toBe(0);
140137
expect(datum.y).toBe(0);
141138
});
@@ -147,9 +144,6 @@ describe('venn padding', () => {
147144
padding: 200,
148145
});
149146
plot.chart.geometries[0].data.forEach((datum) => {
150-
if (datum.sets.length === 1) {
151-
expect(datum.radius).toBe(0);
152-
}
153147
expect(datum.x).toBe(200);
154148
expect(datum.y).toBe(0);
155149
});

examples/more-plots/venn/demo/customize.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Venn } from '@antv/g2plot';
22

3-
fetch('https://gw.alipayobjects.com/os/antfincdn/yzC3ZiBbhM/venn-data.json')
3+
fetch('https://gw.alipayobjects.com/os/bmw-prod/c4c17fe9-0a93-4255-bc1e-1ff84966d24a.json')
44
.then((data) => data.json())
55
.then((data) => {
66
const sum = data.reduce((a, b) => a + b.size, 0);

src/plots/venn/adaptor.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,22 @@ import { isArray, get, deepMix, isEqual } from '@antv/util';
33
import { interaction, animation, theme, tooltip, scale } from '../../adaptor/common';
44
import { Params } from '../../core/adaptor';
55
import { schema as schemaGeometry } from '../../adaptor/geometries';
6-
import { deepAssign, flow, getAdjustAppendPadding, normalPadding, resolveAllPadding } from '../../utils';
6+
import {
7+
deepAssign,
8+
flow,
9+
findGeometry,
10+
transformLabel,
11+
getAdjustAppendPadding,
12+
normalPadding,
13+
resolveAllPadding,
14+
} from '../../utils';
715
import { Datum } from '../../types';
816
import { log, LEVEL } from '../../../src/utils';
917
import { getColorMap, layoutVennData, islegalSets } from './utils';
1018
import { CustomInfo, VennData, VennOptions } from './types';
1119
import { ID_FIELD } from './constant';
1220
import './shape';
21+
import './label';
1322

1423
/** 图例默认预留空间 */
1524
export const LEGEND_SPACE = 40;
@@ -99,12 +108,12 @@ function data(params: Params<VennOptions>): Params<VennOptions> {
99108
*/
100109
function geometry(params: Params<VennOptions>): Params<VennOptions> {
101110
const { chart, options } = params;
102-
const { pointStyle, label, setsField, sizeField } = options;
111+
const { pointStyle, setsField, sizeField } = options;
103112

104113
// 获取容器大小
105114
const [t, r, b, l] = normalPadding(chart.appendPadding);
106115
// 处理 legend 的位置. 默认预留 40px, 业务上可以通过 appendPadding 增加
107-
const customInfo: CustomInfo = { offsetX: l, offsetY: t, label };
116+
const customInfo: CustomInfo = { offsetX: l, offsetY: t };
108117
// coordinateBBox + appendPadding = viewBBox, 不需要再计算 appendPadding 部分,因此直接使用 viewBBox
109118
const { width, height } = chart.viewBBox;
110119
// 处理padding输入不合理的情况, w 和 h 不能为负数
@@ -119,8 +128,6 @@ function geometry(params: Params<VennOptions>): Params<VennOptions> {
119128
sizeField: sizeField,
120129
seriesField: ID_FIELD,
121130
rawFields: [setsField, sizeField],
122-
// 不使用 G2 的label,直接在自定义 shape 中实现
123-
label: false,
124131
schema: {
125132
shape: 'venn',
126133
style: pointStyle,
@@ -136,6 +143,39 @@ function geometry(params: Params<VennOptions>): Params<VennOptions> {
136143
return params;
137144
}
138145

146+
/**
147+
* 处理 label
148+
* @param params
149+
*/
150+
function label(params: Params<VennOptions>): Params<VennOptions> {
151+
const { chart, options } = params;
152+
const { label } = options;
153+
154+
// 获取容器大小
155+
const [t, r, b, l] = normalPadding(chart.appendPadding);
156+
// 传入 label 布局函数所需的 自定义参数
157+
const customLabelInfo = { offsetX: l, offsetY: t };
158+
159+
const geometry = findGeometry(chart, 'schema');
160+
161+
if (!label) {
162+
geometry.label(false);
163+
} else {
164+
const { callback, ...cfg } = label;
165+
geometry.label({
166+
fields: ['id'],
167+
callback,
168+
cfg: deepMix({}, transformLabel(cfg), {
169+
// 使用 G2 的 自定义label 修改位置
170+
type: 'venn',
171+
customLabelInfo,
172+
}),
173+
});
174+
}
175+
176+
return params;
177+
}
178+
139179
/**
140180
* legend 配置
141181
* @param params
@@ -174,6 +214,7 @@ export function adaptor(params: Params<VennOptions>) {
174214
theme,
175215
data,
176216
geometry,
217+
label,
177218
scale({}),
178219
legend,
179220
axis,

src/plots/venn/constant.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ export const DEFAULT_OPTIONS: Partial<VennOptions> = {
2020
},
2121
legend: { position: 'top-left' },
2222
label: {
23-
offsetY: 6,
2423
style: {
2524
textAlign: 'center',
2625
fill: '#fff',

src/plots/venn/label.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { registerGeometryLabel, GeometryLabel } from '@antv/g2';
2+
3+
// Step 1
4+
// 自定义 Label 类
5+
// 需要继承 GeometryLabel 基类
6+
class VennLabel extends GeometryLabel {
7+
/**
8+
* 获取每个 label 的位置
9+
* @param labelCfg
10+
* @param mappingData
11+
* @param index
12+
* @returns label point
13+
*/
14+
protected getLabelPoint(labelCfg, mappingData, index: number) {
15+
const { x, y } = labelCfg.data;
16+
const { offsetX, offsetY } = labelCfg.customLabelInfo;
17+
return {
18+
content: labelCfg.content[index],
19+
x: x + offsetX,
20+
y: y + offsetY,
21+
};
22+
}
23+
}
24+
25+
// Step 2: 注册 CustomLabel
26+
registerGeometryLabel('venn', VennLabel);

src/plots/venn/shape.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { IGroup } from '@antv/g-base';
22
import { registerShape, Types, Util } from '@antv/g2';
33
import { parsePathString } from '@antv/path-util';
4-
import { get } from '@antv/util';
54
import { deepAssign } from '../../utils';
65
import { Datum, Point } from '../../types';
76
import { CustomInfo } from './types';
@@ -32,23 +31,7 @@ registerShape('schema', 'venn', {
3231
name: 'venn-path',
3332
});
3433

35-
const { offsetX, offsetY, label } = cfg.customInfo as CustomInfo;
36-
37-
if (label !== false) {
38-
const formatter = get(label, 'formatter');
39-
const offsetX = get(label, 'offsetX', 0);
40-
const offsetY = get(label, 'offsetY', 0);
41-
group.addShape('text', {
42-
attrs: {
43-
...label,
44-
...get(label, 'style', { textAlign: 'center', fill: '#fff' }),
45-
x: data.x + offsetX,
46-
y: data.y + offsetY,
47-
text: formatter ? formatter(data) : `${data.id}: ${data.size}`,
48-
},
49-
name: 'venn-label',
50-
});
51-
}
34+
const { offsetX, offsetY } = cfg.customInfo as CustomInfo;
5235

5336
const matrix = Util.transform(null, [['t', offsetX, offsetY]]);
5437
group.setMatrix(matrix);

src/plots/venn/utils.ts

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { assign, memoize } from '@antv/util';
22
import { blend } from '../../utils/color/blend';
33
import { log, LEVEL } from '../../../src/utils';
44
import { venn, scaleSolution } from './layout/layout';
5-
import { circlePath, intersectionAreaPath, computeTextCentres } from './layout/diagram';
5+
import { intersectionAreaPath, computeTextCentres } from './layout/diagram';
66
import { ID_FIELD, PATH_FIELD } from './constant';
77
import { VennData, VennOptions } from './types';
88

@@ -71,20 +71,15 @@ export function layoutVennData(options: VennOptions, width: number, height: numb
7171
const sets = row.sets;
7272
const id = sets.join(',');
7373
row[ID_FIELD] = id;
74-
if (sets.length === 1) {
75-
const circle = circles[id];
76-
row[PATH_FIELD] = circlePath(circle.x, circle.y, circle.radius);
77-
assign(row, circle);
78-
} else {
79-
const setCircles = sets.map((set) => circles[set]);
80-
let path = intersectionAreaPath(setCircles);
81-
if (!/[zZ]$/.test(path)) {
82-
path += ' Z';
83-
}
84-
row[PATH_FIELD] = path;
85-
const center = textCenters[id] || { x: 0, y: 0 };
86-
assign(row, center);
74+
// 保留 vennText 布局方法
75+
const setCircles = sets.map((set) => circles[set]);
76+
let path = intersectionAreaPath(setCircles);
77+
if (!/[zZ]$/.test(path)) {
78+
path += ' Z';
8779
}
80+
row[PATH_FIELD] = path;
81+
const center = textCenters[id] || { x: 0, y: 0 };
82+
assign(row, center);
8883
});
8984
return vennData;
9085
}

0 commit comments

Comments
 (0)