From a4618c024dbfaf3ba5a8b5b12bacb57a28279059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=AF=E5=8D=97?= <31396322+lxfu1@users.noreply.github.com> Date: Thu, 30 Jul 2020 08:30:38 +0800 Subject: [PATCH] feat: interaction (#1349) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 新增 type 类型和修复shpeField * feat: register interaction drag-move * fix: review modify * fix: 统一 log 英文 Co-authored-by: liufu.lf --- .../unit/plots/scatter/interaction-spec.ts | 33 +++++++++++++++++ __tests__/unit/plots/scatter/style-spec.ts | 37 +++++++++++++++++++ docs/demos/scatter.md | 18 ++++++++- src/plots/scatter/adaptor.ts | 28 +++++++++----- src/plots/scatter/index.ts | 1 + src/plots/scatter/interaction/index.ts | 13 +++++++ src/plots/scatter/types.ts | 4 +- 7 files changed, 121 insertions(+), 13 deletions(-) create mode 100644 __tests__/unit/plots/scatter/interaction-spec.ts create mode 100644 src/plots/scatter/interaction/index.ts diff --git a/__tests__/unit/plots/scatter/interaction-spec.ts b/__tests__/unit/plots/scatter/interaction-spec.ts new file mode 100644 index 0000000000..0ad20d5553 --- /dev/null +++ b/__tests__/unit/plots/scatter/interaction-spec.ts @@ -0,0 +1,33 @@ +import { getInteraction } from '@antv/g2'; +import { Scatter } from '../../../../src'; +import { createDiv } from '../../../utils/dom'; +import { data } from '../../../data/gender'; + +describe('scatter: register interaction', () => { + const scatter = new Scatter(createDiv(), { + width: 400, + height: 300, + appendPadding: 10, + data, + xField: 'weight', + yField: 'height', + sizeField: 'weight', + size: [5, 10], + colorField: 'gender', + xAxis: { + nice: true, + }, + interactions: [ + { + name: 'drag-move', + }, + ], + }); + + scatter.render(); + + it('define: drag-move', () => { + const statisticInteraction = getInteraction('drag-move'); + expect(statisticInteraction).toBeDefined(); + }); +}); diff --git a/__tests__/unit/plots/scatter/style-spec.ts b/__tests__/unit/plots/scatter/style-spec.ts index 0b022bdcaa..90566b9895 100644 --- a/__tests__/unit/plots/scatter/style-spec.ts +++ b/__tests__/unit/plots/scatter/style-spec.ts @@ -77,4 +77,41 @@ describe('scatter', () => { expect(elements[0].shape.attr('stroke')).toBe('yellow'); expect(elements[0].shape.attr('opacity')).toBe(0.8); }); + it('style: all options', () => { + const scatter = new Scatter(createDiv(), { + width: 400, + height: 300, + appendPadding: 10, + data, + xField: 'weight', + yField: 'height', + sizeField: 'weight', + size: [5, 10], + xAxis: { + nice: true, + }, + pointStyle: { + fill: 'red', + stroke: 'yellow', + lineWidth: 4, + lineDash: [2, 2], + opacity: 0.5, + fillOpacity: 0.5, + strokeOpacity: 0.5, + }, + }); + + scatter.render(); + + const geometry = scatter.chart.geometries[0]; + const elements = geometry.elements; + + expect(elements[0].shape.attr('fill')).toBe('red'); + expect(elements[0].shape.attr('stroke')).toBe('yellow'); + expect(elements[0].shape.attr('lineWidth')).toBe(4); + expect(elements[0].shape.attr('lineDash')).toEqual([2, 2]); + expect(elements[0].shape.attr('opacity')).toBe(0.5); + expect(elements[0].shape.attr('fillOpacity')).toBe(0.5); + expect(elements[0].shape.attr('strokeOpacity')).toBe(0.5); + }); }); diff --git a/docs/demos/scatter.md b/docs/demos/scatter.md index 356ddf1cac..c43d312a3d 100644 --- a/docs/demos/scatter.md +++ b/docs/demos/scatter.md @@ -31,9 +31,25 @@ const Page: React.FC = () => { data: data.slice(0, 50), xField: 'weight', yField: 'height', + shapeField: 'gender', shape: ['circle', 'square'], + colorField: 'gender', color: ['green', 'red'], - size: 'weight', + sizeField: 'weight', + interactions: [ + { + name: 'drag-move', + }, + ], + label: { + offsetX: 6, + offsetY: 6, + style: { + fill: 'rgba(0, 0, 0, 0.65)', + stroke: '#ffffff', + lineWidth: 2, + }, + }, tooltip: { showCrosshairs: true, crosshairs: { diff --git a/src/plots/scatter/adaptor.ts b/src/plots/scatter/adaptor.ts index e87eb3365b..d809401ceb 100644 --- a/src/plots/scatter/adaptor.ts +++ b/src/plots/scatter/adaptor.ts @@ -1,8 +1,8 @@ import { deepMix, isFunction } from '@antv/util'; import { Params } from '../../core/adaptor'; -import { flow, pick } from '../../utils'; +import { flow, pick, log, LEVEL } from '../../utils'; import { ScatterOptions } from './types'; -import { tooltip } from '../../common/adaptor'; +import { tooltip, interaction, animation, theme } from '../../common/adaptor'; import { findGeometry } from '../../common/helper'; import { AXIS_META_CONFIG_KEYS } from '../../constant'; import { REFLECTS } from './reflect'; @@ -13,16 +13,21 @@ import { REFLECTS } from './reflect'; */ function field(params: Params): Params { const { chart, options } = params; - const { data, xField, yField, seriesField } = options; + const { data, xField, yField, type } = options; // 散点图操作逻辑 chart.data(data); const geometry = chart.point().position(`${xField}*${yField}`); + // 数据调整 + if (type) { + geometry.adjust(type); + } + // 统一处理 color、 size、 shape const reflectKeys = Object.keys(REFLECTS); reflectKeys.forEach((key: string) => { - if (options[key]) { + if (options[key] || options[REFLECTS[key].field]) { let validateRules = false; (REFLECTS[key].rules || []).forEach((fn: (arg: any) => boolean) => { // 满足任一规则即可 @@ -31,9 +36,12 @@ function field(params: Params): Params { } }); if (validateRules) { - geometry[REFLECTS[key].action](options[REFLECTS[key].field] || seriesField || xField, options[key]); + if (!options[REFLECTS[key].field]) { + log(LEVEL.WARN, false, '*** For accurate mapping, specify %s please. ***', REFLECTS[key].field); + } + geometry[REFLECTS[key].action](options[REFLECTS[key].field] || xField, options[key]); } else { - geometry[REFLECTS[key].action](options[key]); + geometry[REFLECTS[key].action](options[key] || options[REFLECTS[key].field]); } } }); @@ -80,10 +88,10 @@ function axis(params: Params): Params { */ function legend(params: Params): Params { const { chart, options } = params; - const { legend, seriesField } = options; + const { legend, colorField } = options; - if (legend && seriesField) { - chart.legend(seriesField, legend); + if (legend && colorField) { + chart.legend(colorField, legend); } return params; @@ -142,5 +150,5 @@ function label(params: Params): Params { */ export function adaptor(params: Params) { // flow 的方式处理所有的配置到 G2 API - flow(field, meta, axis, legend, tooltip, style, label)(params); + flow(field, meta, axis, legend, tooltip, style, label, interaction, animation, theme)(params); } diff --git a/src/plots/scatter/index.ts b/src/plots/scatter/index.ts index 78c3b5badb..4eee27dde0 100644 --- a/src/plots/scatter/index.ts +++ b/src/plots/scatter/index.ts @@ -2,6 +2,7 @@ import { Plot } from '../../core/plot'; import { ScatterOptions } from './types'; import { adaptor } from './adaptor'; import { Adaptor } from '../../core/adaptor'; +import './interaction'; export { ScatterOptions }; diff --git a/src/plots/scatter/interaction/index.ts b/src/plots/scatter/interaction/index.ts new file mode 100644 index 0000000000..b201001e04 --- /dev/null +++ b/src/plots/scatter/interaction/index.ts @@ -0,0 +1,13 @@ +import { registerInteraction } from '@antv/g2'; + +registerInteraction('drag-move', { + start: [{ trigger: 'plot:mousedown', action: 'scale-translate:start' }], + processing: [ + { + trigger: 'plot:mousemove', + action: 'scale-translate:translate', + throttle: { wait: 100, leading: true, trailing: false }, + }, + ], + end: [{ trigger: 'plot:mouseup', action: 'scale-translate:end' }], +}); diff --git a/src/plots/scatter/types.ts b/src/plots/scatter/types.ts index f4e864cb07..5e1273a6e7 100644 --- a/src/plots/scatter/types.ts +++ b/src/plots/scatter/types.ts @@ -59,8 +59,8 @@ export interface ScatterOptions extends Options { readonly xField: string; /** y 轴字段 */ readonly yField: string; - /** 分组字段 */ - readonly seriesField?: string; + /** 数据调整类型 */ + readonly type?: 'jitter' | 'stack' | 'symmetric' | 'dodge'; /** 点大小映射对应的数据字段名 */ readonly sizeField?: string; /** 散点图大小 */