Skip to content

Commit 17e8f08

Browse files
authored
fix(scatter): 散点图刷选交互之后的 scale 处理 (#2649)
1 parent ef79733 commit 17e8f08

File tree

6 files changed

+156
-29
lines changed

6 files changed

+156
-29
lines changed

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

+37
Original file line numberDiff line numberDiff line change
@@ -301,4 +301,41 @@ describe('scatter', () => {
301301

302302
scatter.destroy();
303303
});
304+
305+
it('all yValues or xValues of data is equal', () => {
306+
const data = [
307+
{ gender: 'female', height: 161.2, weight: 51.6 },
308+
{ gender: 'female', height: 111.2, weight: 51.6 },
309+
{ gender: 'female', height: 161.2, weight: 21.6 },
310+
];
311+
const scatter = new Scatter(createDiv(), {
312+
width: 400,
313+
height: 300,
314+
appendPadding: 10,
315+
data,
316+
xField: 'weight',
317+
yField: 'height',
318+
xAxis: {
319+
nice: false,
320+
},
321+
yAxis: {
322+
nice: false,
323+
},
324+
});
325+
326+
scatter.render();
327+
let yScale = scatter.chart.getScaleByField('height');
328+
expect(yScale.max).not.toBe(161.2 * 2);
329+
330+
scatter.changeData([data[0], data[2]]);
331+
yScale = scatter.chart.getScaleByField('height');
332+
expect(yScale.min).toBe(0);
333+
expect(yScale.max).toBe(161.2 * 2);
334+
335+
scatter.changeData([data[0], data[1]]);
336+
const xScale = scatter.chart.getScaleByField('weight');
337+
expect(xScale.max).toBe(51.6 * 2);
338+
339+
scatter.destroy();
340+
});
304341
});

__tests__/unit/plots/scatter/size-spec.ts

+42
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,48 @@ import { data } from '../../../data/gender';
33
import { createDiv } from '../../../utils/dom';
44

55
describe('scatter', () => {
6+
it('default', () => {
7+
const scatter = new Scatter(createDiv(), {
8+
width: 400,
9+
height: 300,
10+
appendPadding: 10,
11+
data,
12+
xField: 'weight',
13+
yField: 'height',
14+
sizeField: 'gender',
15+
xAxis: {
16+
nice: true,
17+
},
18+
});
19+
20+
scatter.render();
21+
22+
let geometry = scatter.chart.geometries[0];
23+
24+
// @ts-ignore
25+
expect(geometry.attributeOption.size.values.length).toBe(2);
26+
// @ts-ignore
27+
expect(geometry.attributeOption.size.values).toEqual([4, 4]);
28+
29+
// 不能设置 size 为 0(一定吗?可以后续斟酌下)
30+
scatter.update({ size: 0 });
31+
geometry = scatter.chart.geometries[0];
32+
// @ts-ignore
33+
expect(geometry.attributeOption.size.values).toEqual([2, 8]);
34+
35+
scatter.update({ size: [3, 9] });
36+
geometry = scatter.chart.geometries[0];
37+
// @ts-ignore
38+
expect(geometry.attributeOption.size.values).toEqual([3, 9]);
39+
40+
scatter.update({ size: null });
41+
geometry = scatter.chart.geometries[0];
42+
// @ts-ignore
43+
expect(geometry.attributeOption.size.values).toEqual([2, 8]);
44+
45+
scatter.destroy();
46+
});
47+
648
it('size: number options', () => {
749
const scatter = new Scatter(createDiv(), {
850
width: 400,

__tests__/unit/plots/scatter/style-spec.ts

+7-2
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,23 @@ describe('scatter', () => {
1313
yField: 'height',
1414
sizeField: 'weight',
1515
size: [5, 10],
16+
shape: 'cricle',
1617
xAxis: {
1718
nice: true,
1819
},
20+
});
21+
22+
scatter.render();
23+
expect(scatter.chart.geometries[0].elements[0].shape.attr('fill')).toBe('#FFFFFF');
24+
25+
scatter.update({
1926
pointStyle: {
2027
fill: 'red',
2128
stroke: 'yellow',
2229
opacity: 0.8,
2330
},
2431
});
2532

26-
scatter.render();
27-
2833
const geometry = scatter.chart.geometries[0];
2934
const elements = geometry.elements;
3035

src/plots/scatter/adaptor.ts

+28-15
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { isNumber } from '@antv/util';
1+
import { isNumber, min, max } from '@antv/util';
22
import { Params } from '../../core/adaptor';
33
import { flow, deepAssign } from '../../utils';
44
import { point } from '../../adaptor/geometries';
@@ -8,18 +8,36 @@ import { getQuadrantDefaultConfig, getPath, getMeta } from './util';
88
import { ScatterOptions } from './types';
99

1010
/**
11-
* 散点图 data.length === 1 时居中显示,
11+
* 散点图默认美观
12+
* ① data.length === 1 ② 所有数据 y 值相等 ③ 所有数据 x 值相等
1213
* @param params
1314
* @returns params
1415
*/
1516
export function transformOptions(options: ScatterOptions): ScatterOptions {
16-
const { data = [] } = options;
17-
// 仅对 data.length === 1 的情况进行处理
18-
if (data.length === 1) {
19-
return deepAssign({}, options, {
20-
meta: getMeta(options),
21-
});
17+
const { data = [], xField, yField } = options;
18+
19+
if (data.length) {
20+
const xValues = data.map((d) => d[xField]);
21+
const minX = min(xValues);
22+
const maxX = max(xValues);
23+
const yValues = data.map((d) => d[yField]);
24+
const minY = min(yValues);
25+
const maxY = max(yValues);
26+
if (minX === maxX && minY === maxY) {
27+
return deepAssign({}, options, {
28+
meta: getMeta(options, ['x', 'y']),
29+
});
30+
} else if (minX === maxX) {
31+
return deepAssign({}, options, {
32+
meta: getMeta(options, ['x']),
33+
});
34+
} else if (minY === maxY) {
35+
return deepAssign({}, options, {
36+
meta: getMeta(options, ['y']),
37+
});
38+
}
2239
}
40+
2341
return options;
2442
}
2543

@@ -84,14 +102,9 @@ function geometry(params: Params<ScatterOptions>): Params<ScatterOptions> {
84102
*/
85103
export function meta(params: Params<ScatterOptions>): Params<ScatterOptions> {
86104
const { options } = params;
87-
const { data, xAxis, yAxis, xField, yField } = options;
88-
89-
let newOptions = options;
90-
// 仅对 data.length === 1 的情况进行处理
91-
if (data.length === 1) {
92-
newOptions = transformOptions(deepAssign({}, options, { meta: getMeta(options) }));
93-
}
105+
const { xAxis, yAxis, xField, yField } = options;
94106

107+
const newOptions = transformOptions(options);
95108
return flow(
96109
scale({
97110
[xField]: xAxis,

src/plots/scatter/index.ts

+19
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { BRUSH_FILTER_EVENTS, VIEW_LIFE_CIRCLE } from '@antv/g2';
12
import { Plot } from '../../core/plot';
23
import { Adaptor } from '../../core/adaptor';
34
import { deepAssign } from '../../utils';
@@ -20,6 +21,24 @@ export class Scatter extends Plot<ScatterOptions> {
2021
/** 图表类型 */
2122
public type: string = 'point';
2223

24+
constructor(container: string | HTMLElement, options: ScatterOptions) {
25+
super(container, options);
26+
27+
// 监听 brush 事件,处理 meta
28+
this.on(VIEW_LIFE_CIRCLE.BEFORE_RENDER, (evt) => {
29+
// 运行时,读取 option
30+
const { options, chart } = this;
31+
if (evt.data?.source === BRUSH_FILTER_EVENTS.FILTER) {
32+
const filteredData = this.chart.filterData(this.chart.getData());
33+
meta({ chart, options: { ...options, data: filteredData } });
34+
}
35+
36+
if (evt.data?.source === BRUSH_FILTER_EVENTS.RESET) {
37+
meta({ chart, options });
38+
}
39+
});
40+
}
41+
2342
/**
2443
* @override
2544
* @param data

src/plots/scatter/util.ts

+23-12
Original file line numberDiff line numberDiff line change
@@ -162,8 +162,15 @@ export const getPath = (config: RenderOptions) => {
162162
return splinePath(pathData, config);
163163
};
164164

165-
// 散点图data.length === 1时调整 meta: {min, max}
166-
export const getMeta = (options: ScatterOptions): ScatterOptions['meta'] => {
165+
/**
166+
* 调整散点图 meta: { min, max } ① data.length === 1 ② 所有数据 y 值相等 ③ 所有数据 x 值相等
167+
* @param options
168+
* @returns
169+
*/
170+
export const getMeta = (
171+
options: Pick<ScatterOptions, 'meta' | 'xField' | 'yField' | 'data'>,
172+
dims: string[] = ['x', 'y']
173+
): ScatterOptions['meta'] => {
167174
const { meta = {}, xField, yField, data } = options;
168175
const xFieldValue = data[0][xField];
169176
const yFieldValue = data[0][yField];
@@ -190,15 +197,19 @@ export const getMeta = (options: ScatterOptions): ScatterOptions['meta'] => {
190197
};
191198
return {
192199
...meta,
193-
[xField]: {
194-
...meta[xField],
195-
min: getValue(xField, 'min', 'x'),
196-
max: getValue(xField, 'max', 'x'),
197-
},
198-
[yField]: {
199-
...meta[yField],
200-
min: getValue(yField, 'min', 'y'),
201-
max: getValue(yField, 'max', 'y'),
202-
},
200+
[xField]: dims.includes('x')
201+
? {
202+
...meta[xField],
203+
min: getValue(xField, 'min', 'x'),
204+
max: getValue(xField, 'max', 'x'),
205+
}
206+
: {},
207+
[yField]: dims.includes('y')
208+
? {
209+
...meta[yField],
210+
min: getValue(yField, 'min', 'y'),
211+
max: getValue(yField, 'max', 'y'),
212+
}
213+
: {},
203214
};
204215
};

0 commit comments

Comments
 (0)