Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(scatter): 散点图刷选交互之后的 scale 处理 #2649

Merged
merged 3 commits into from
Jun 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions __tests__/unit/plots/scatter/data-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -301,4 +301,41 @@ describe('scatter', () => {

scatter.destroy();
});

it('all yValues or xValues of data is equal', () => {
const data = [
{ gender: 'female', height: 161.2, weight: 51.6 },
{ gender: 'female', height: 111.2, weight: 51.6 },
{ gender: 'female', height: 161.2, weight: 21.6 },
];
const scatter = new Scatter(createDiv(), {
width: 400,
height: 300,
appendPadding: 10,
data,
xField: 'weight',
yField: 'height',
xAxis: {
nice: false,
},
yAxis: {
nice: false,
},
});

scatter.render();
let yScale = scatter.chart.getScaleByField('height');
expect(yScale.max).not.toBe(161.2 * 2);

scatter.changeData([data[0], data[2]]);
yScale = scatter.chart.getScaleByField('height');
expect(yScale.min).toBe(0);
expect(yScale.max).toBe(161.2 * 2);

scatter.changeData([data[0], data[1]]);
const xScale = scatter.chart.getScaleByField('weight');
expect(xScale.max).toBe(51.6 * 2);

scatter.destroy();
});
});
42 changes: 42 additions & 0 deletions __tests__/unit/plots/scatter/size-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,48 @@ import { data } from '../../../data/gender';
import { createDiv } from '../../../utils/dom';

describe('scatter', () => {
it('default', () => {
const scatter = new Scatter(createDiv(), {
width: 400,
height: 300,
appendPadding: 10,
data,
xField: 'weight',
yField: 'height',
sizeField: 'gender',
xAxis: {
nice: true,
},
});

scatter.render();

let geometry = scatter.chart.geometries[0];

// @ts-ignore
expect(geometry.attributeOption.size.values.length).toBe(2);
// @ts-ignore
expect(geometry.attributeOption.size.values).toEqual([4, 4]);

// 不能设置 size 为 0(一定吗?可以后续斟酌下)
scatter.update({ size: 0 });
geometry = scatter.chart.geometries[0];
// @ts-ignore
expect(geometry.attributeOption.size.values).toEqual([2, 8]);

scatter.update({ size: [3, 9] });
geometry = scatter.chart.geometries[0];
// @ts-ignore
expect(geometry.attributeOption.size.values).toEqual([3, 9]);

scatter.update({ size: null });
geometry = scatter.chart.geometries[0];
// @ts-ignore
expect(geometry.attributeOption.size.values).toEqual([2, 8]);

scatter.destroy();
});

it('size: number options', () => {
const scatter = new Scatter(createDiv(), {
width: 400,
Expand Down
9 changes: 7 additions & 2 deletions __tests__/unit/plots/scatter/style-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,23 @@ describe('scatter', () => {
yField: 'height',
sizeField: 'weight',
size: [5, 10],
shape: 'cricle',
xAxis: {
nice: true,
},
});

scatter.render();
expect(scatter.chart.geometries[0].elements[0].shape.attr('fill')).toBe('#FFFFFF');

scatter.update({
pointStyle: {
fill: 'red',
stroke: 'yellow',
opacity: 0.8,
},
});

scatter.render();

const geometry = scatter.chart.geometries[0];
const elements = geometry.elements;

Expand Down
43 changes: 28 additions & 15 deletions src/plots/scatter/adaptor.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isNumber } from '@antv/util';
import { isNumber, min, max } from '@antv/util';
import { Params } from '../../core/adaptor';
import { flow, deepAssign } from '../../utils';
import { point } from '../../adaptor/geometries';
Expand All @@ -8,18 +8,36 @@ import { getQuadrantDefaultConfig, getPath, getMeta } from './util';
import { ScatterOptions } from './types';

/**
* 散点图 data.length === 1 时居中显示,
* 散点图默认美观
* ① data.length === 1 ② 所有数据 y 值相等 ③ 所有数据 x 值相等
* @param params
* @returns params
*/
export function transformOptions(options: ScatterOptions): ScatterOptions {
const { data = [] } = options;
// 仅对 data.length === 1 的情况进行处理
if (data.length === 1) {
return deepAssign({}, options, {
meta: getMeta(options),
});
const { data = [], xField, yField } = options;

if (data.length) {
const xValues = data.map((d) => d[xField]);
const minX = min(xValues);
const maxX = max(xValues);
const yValues = data.map((d) => d[yField]);
const minY = min(yValues);
const maxY = max(yValues);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里要做性能提升。其实只需要判断 isSameXValue,isSameYValue。

if (minX === maxX && minY === maxY) {
return deepAssign({}, options, {
meta: getMeta(options, ['x', 'y']),
});
} else if (minX === maxX) {
return deepAssign({}, options, {
meta: getMeta(options, ['x']),
});
} else if (minY === maxY) {
return deepAssign({}, options, {
meta: getMeta(options, ['y']),
});
}
}

return options;
}

Expand Down Expand Up @@ -84,14 +102,9 @@ function geometry(params: Params<ScatterOptions>): Params<ScatterOptions> {
*/
export function meta(params: Params<ScatterOptions>): Params<ScatterOptions> {
const { options } = params;
const { data, xAxis, yAxis, xField, yField } = options;

let newOptions = options;
// 仅对 data.length === 1 的情况进行处理
if (data.length === 1) {
newOptions = transformOptions(deepAssign({}, options, { meta: getMeta(options) }));
}
const { xAxis, yAxis, xField, yField } = options;

const newOptions = transformOptions(options);
return flow(
scale({
[xField]: xAxis,
Expand Down
19 changes: 19 additions & 0 deletions src/plots/scatter/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { BRUSH_FILTER_EVENTS, VIEW_LIFE_CIRCLE } from '@antv/g2';
import { Plot } from '../../core/plot';
import { Adaptor } from '../../core/adaptor';
import { deepAssign } from '../../utils';
Expand All @@ -20,6 +21,24 @@ export class Scatter extends Plot<ScatterOptions> {
/** 图表类型 */
public type: string = 'point';

constructor(container: string | HTMLElement, options: ScatterOptions) {
super(container, options);

// 监听 brush 事件,处理 meta
this.on(VIEW_LIFE_CIRCLE.BEFORE_RENDER, (evt) => {
// 运行时,读取 option
const { options, chart } = this;
if (evt.data?.source === BRUSH_FILTER_EVENTS.FILTER) {
const filteredData = this.chart.filterData(this.chart.getData());
meta({ chart, options: { ...options, data: filteredData } });
}

if (evt.data?.source === BRUSH_FILTER_EVENTS.RESET) {
meta({ chart, options });
}
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可以放到 changeData 函数中,用 this.once 更节省。


/**
* @override
* @param data
Expand Down
35 changes: 23 additions & 12 deletions src/plots/scatter/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,15 @@ export const getPath = (config: RenderOptions) => {
return splinePath(pathData, config);
};

// 散点图data.length === 1时调整 meta: {min, max}
export const getMeta = (options: ScatterOptions): ScatterOptions['meta'] => {
/**
* 调整散点图 meta: { min, max } ① data.length === 1 ② 所有数据 y 值相等 ③ 所有数据 x 值相等
* @param options
* @returns
*/
export const getMeta = (
options: Pick<ScatterOptions, 'meta' | 'xField' | 'yField' | 'data'>,
dims: string[] = ['x', 'y']
): ScatterOptions['meta'] => {
const { meta = {}, xField, yField, data } = options;
const xFieldValue = data[0][xField];
const yFieldValue = data[0][yField];
Expand All @@ -190,15 +197,19 @@ export const getMeta = (options: ScatterOptions): ScatterOptions['meta'] => {
};
return {
...meta,
[xField]: {
...meta[xField],
min: getValue(xField, 'min', 'x'),
max: getValue(xField, 'max', 'x'),
},
[yField]: {
...meta[yField],
min: getValue(yField, 'min', 'y'),
max: getValue(yField, 'max', 'y'),
},
[xField]: dims.includes('x')
? {
...meta[xField],
min: getValue(xField, 'min', 'x'),
max: getValue(xField, 'max', 'x'),
}
: {},
[yField]: dims.includes('y')
? {
...meta[yField],
min: getValue(yField, 'min', 'y'),
max: getValue(yField, 'max', 'y'),
}
: {},
};
};