From 8bb1b466622a251ce46d8952b845cb0badccab04 Mon Sep 17 00:00:00 2001 From: wb-xcf804241 Date: Tue, 5 Mar 2024 15:48:02 +0800 Subject: [PATCH 1/5] feat(interaction): add elementpointmove interaction --- .../static/flareElementPointMoveInterval.svg | 1407 +++++++++++++++ ...lareElementPointMoveIntervalNormalizeY.svg | 1529 ++++++++++++++++ ...ntPointMoveIntervalNormalizeYTranspose.svg | 1527 ++++++++++++++++ ...flareElementPointMoveIntervalTranspose.svg | 1403 +++++++++++++++ .../static/flareElementPointMoveLine.svg | 1560 +++++++++++++++++ ...oint-move-interval-normalizeY-transpose.ts | 44 + ...-element-point-move-interval-normalizeY.ts | 43 + ...e-element-point-move-interval-transpose.ts | 40 + .../flare-element-point-move-interval.ts | 39 + .../static/flare-element-point-move-line.ts | 41 + __tests__/plots/static/index.ts | 5 + __tests__/unit/lib/core.spec.ts | 2 + __tests__/unit/lib/std.spec.ts | 2 + .../data/demo/bar-element-point-move.ts | 50 + .../demo/bar-normalizeY-element-point-move.ts | 52 + .../data/demo/column-element-point-move.ts | 49 + .../column-normalizeY-element-point-move.ts | 51 + .../data/demo/line-element-point-move.ts | 65 + site/examples/interaction/data/demo/meta.json | 48 + site/examples/interaction/data/index.en.md | 4 + site/examples/interaction/data/index.zh.md | 4 + src/interaction/elementPointMove.ts | 508 ++++++ src/interaction/index.ts | 1 + src/lib/core.ts | 2 + 24 files changed, 8476 insertions(+) create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveInterval.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeY.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeYTranspose.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveIntervalTranspose.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveLine.svg create mode 100644 __tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts create mode 100644 __tests__/plots/static/flare-element-point-move-interval-normalizeY.ts create mode 100644 __tests__/plots/static/flare-element-point-move-interval-transpose.ts create mode 100644 __tests__/plots/static/flare-element-point-move-interval.ts create mode 100644 __tests__/plots/static/flare-element-point-move-line.ts create mode 100644 site/examples/interaction/data/demo/bar-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/column-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/line-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/meta.json create mode 100644 site/examples/interaction/data/index.en.md create mode 100644 site/examples/interaction/data/index.zh.md create mode 100644 src/interaction/elementPointMove.ts diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveInterval.svg b/__tests__/integration/snapshots/static/flareElementPointMoveInterval.svg new file mode 100644 index 0000000000..7bd5b58052 --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveInterval.svg @@ -0,0 +1,1407 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + London + + + + + + + + + + + + + + + + + + + + Berlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jan. + + + + + + + Feb. + + + + + + + Mar. + + + + + + + Apr. + + + + + + + May + + + + + + + Jun. + + + + + + + Jul. + + + + + + + Aug. + + + + + + + + + 月份 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 50 + + + + + + + 100 + + + + + + + 150 + + + + + + + + + 月均降雨量 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeY.svg b/__tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeY.svg new file mode 100644 index 0000000000..67dc454117 --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeY.svg @@ -0,0 +1,1529 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + London + + + + + + + + + + + + + + + + + + + + Berlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + May + + + + + + + Mar. + + + + + + + Jun. + + + + + + + Jul. + + + + + + + Jan. + + + + + + + Feb. + + + + + + + Aug. + + + + + + + Apr. + + + + + + + + + 月份 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 0.2 + + + + + + + 0.4 + + + + + + + 0.6 + + + + + + + 0.8 + + + + + + + 1 + + + + + + + + + 月均降雨量 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeYTranspose.svg b/__tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeYTranspose.svg new file mode 100644 index 0000000000..2b723e7a7b --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveIntervalNormalizeYTranspose.svg @@ -0,0 +1,1527 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + London + + + + + + + + + + + + + + + + + + + + Berlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + May + + + + + + + Mar. + + + + + + + Jun. + + + + + + + Jul. + + + + + + + Jan. + + + + + + + Feb. + + + + + + + Aug. + + + + + + + Apr. + + + + + + + + + 月份 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 0.2 + + + + + + + 0.4 + + + + + + + 0.6 + + + + + + + 0.8 + + + + + + + 1 + + + + + + + + + 月均降雨量 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveIntervalTranspose.svg b/__tests__/integration/snapshots/static/flareElementPointMoveIntervalTranspose.svg new file mode 100644 index 0000000000..5638f6056e --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveIntervalTranspose.svg @@ -0,0 +1,1403 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + London + + + + + + + + + + + + + + + + + + + + Berlin + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Jan. + + + + + + + Feb. + + + + + + + Mar. + + + + + + + Apr. + + + + + + + May + + + + + + + Jun. + + + + + + + Jul. + + + + + + + Aug. + + + + + + + + + 月份 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 50 + + + + + + + 100 + + + + + + + 150 + + + + + + + + + 月均降雨量 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg b/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg new file mode 100644 index 0000000000..b213f11017 --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg @@ -0,0 +1,1560 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + type1 + + + + + + + + + + + + + + + + + + + + type2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1991 + + + + + + + 1992 + + + + + + + 1993 + + + + + + + 1994 + + + + + + + 1995 + + + + + + + 1996 + + + + + + + 1997 + + + + + + + 1998 + + + + + + + 1999 + + + + + + + + + year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + + + + + + 4 + + + + + + + 6 + + + + + + + 8 + + + + + + + 10 + + + + + + + 12 + + + + + + + 14 + + + + + + + + + value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts b/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts new file mode 100644 index 0000000000..65f8a9b2be --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts @@ -0,0 +1,44 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveIntervalNormalizeYTranspose(): G2Spec { + return { + type: 'interval', + width: 600, + height: 400, + coordinate: { transform: [{ type: 'transpose' }] }, + data: [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, + ], + encode: { + x: '月份', + y: '月均降雨量', + color: 'name', + key: (d) => d['name'] + d['月份'], + }, + transform: [ + { type: 'stackY' }, + { type: 'normalizeY' }, + { type: 'sortX', by: 'y', reverse: true }, + ], + interaction: { + elementPointMove: { + selected: [6], + }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts b/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts new file mode 100644 index 0000000000..5bb7c4687d --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts @@ -0,0 +1,43 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveIntervalNormalizeY(): G2Spec { + return { + type: 'interval', + width: 600, + height: 400, + data: [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, + ], + encode: { + x: '月份', + y: '月均降雨量', + color: 'name', + key: (d) => d['name'] + d['月份'], + }, + transform: [ + { type: 'stackY' }, + { type: 'normalizeY' }, + { type: 'sortX', by: 'y', reverse: true }, + ], + interaction: { + elementPointMove: { + selected: [6], + }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-interval-transpose.ts b/__tests__/plots/static/flare-element-point-move-interval-transpose.ts new file mode 100644 index 0000000000..a7f03fbaf6 --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-interval-transpose.ts @@ -0,0 +1,40 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveIntervalTranspose(): G2Spec { + return { + type: 'interval', + width: 600, + height: 400, + coordinate: { transform: [{ type: 'transpose' }] }, + data: [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, + ], + encode: { + x: '月份', + y: '月均降雨量', + color: 'name', + key: (d) => d['name'] + d['月份'], + }, + transform: [{ type: 'stackY' }], + interaction: { + elementPointMove: { + selected: [6], + }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-interval.ts b/__tests__/plots/static/flare-element-point-move-interval.ts new file mode 100644 index 0000000000..d43bda5697 --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-interval.ts @@ -0,0 +1,39 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveInterval(): G2Spec { + return { + type: 'interval', + width: 600, + height: 400, + data: [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, + ], + encode: { + x: '月份', + y: '月均降雨量', + color: 'name', + key: (d) => d['name'] + d['月份'], + }, + transform: [{ type: 'stackY' }], + interaction: { + elementPointMove: { + selected: [6], + }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-line.ts b/__tests__/plots/static/flare-element-point-move-line.ts new file mode 100644 index 0000000000..757ba1036e --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-line.ts @@ -0,0 +1,41 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveLine(): G2Spec { + return { + type: 'line', + width: 600, + height: 400, + data: [ + { year: '1991', value: 3, type: 'type1' }, + { year: '1992', value: 4, type: 'type1' }, + { year: '1993', value: 3.5, type: 'type1' }, + { year: '1994', value: 5, type: 'type1' }, + { year: '1995', value: 4.9, type: 'type1' }, + { year: '1996', value: 2, type: 'type1' }, + { year: '1997', value: 7, type: 'type1' }, + { year: '1998', value: 11, type: 'type1' }, + { year: '1999', value: 13, type: 'type1' }, + { year: '1991', value: 6, type: 'type2' }, + { year: '1992', value: 1, type: 'type2' }, + { year: '1993', value: 4, type: 'type2' }, + { year: '1994', value: 9, type: 'type2' }, + { year: '1995', value: 1.9, type: 'type2' }, + { year: '1996', value: 5, type: 'type2' }, + { year: '1997', value: 4, type: 'type2' }, + { year: '1998', value: 6, type: 'type2' }, + { year: '1999', value: 15, type: 'type2' }, + ], + encode: { + x: 'year', + y: 'value', + color: 'type', + key: 'type', + }, + interaction: { + elementPointMove: { + precision: 4, + selected: [1, 4], + }, + }, + }; +} diff --git a/__tests__/plots/static/index.ts b/__tests__/plots/static/index.ts index cb15d80681..4fdccdf000 100644 --- a/__tests__/plots/static/index.ts +++ b/__tests__/plots/static/index.ts @@ -322,3 +322,8 @@ export { mockComplexRadar } from './mock-complex-radar'; export { aaplLineIllegalDataSlider } from './aapl-line-illegal-data-slider'; export { mockSquareRadar } from './mock-square-radar'; export { aaplLineSliderValues } from './aapl-line-slider-values'; +export { flareElementPointMoveLine } from './flare-element-point-move-line'; +export { flareElementPointMoveInterval } from './flare-element-point-move-interval'; +export { flareElementPointMoveIntervalTranspose } from './flare-element-point-move-interval-transpose'; +export { flareElementPointMoveIntervalNormalizeY } from './flare-element-point-move-interval-normalizeY'; +export { flareElementPointMoveIntervalNormalizeYTranspose } from './flare-element-point-move-interval-normalizeY-transpose'; diff --git a/__tests__/unit/lib/core.spec.ts b/__tests__/unit/lib/core.spec.ts index 6869e4b3f5..bd96bdf056 100644 --- a/__tests__/unit/lib/core.spec.ts +++ b/__tests__/unit/lib/core.spec.ts @@ -85,6 +85,7 @@ import { ElementHighlightByX, ElementSelect, ElementSelectByColor, + ElementPointMove, ElementSelectByX, Fisheye as ChartFisheye, ChartIndex, @@ -287,6 +288,7 @@ describe('corelib', () => { 'interaction.elementSelect': ElementSelect, 'interaction.elementSelectByX': ElementSelectByX, 'interaction.elementSelectByColor': ElementSelectByColor, + 'interaction.elementPointMove': ElementPointMove, 'interaction.fisheye': ChartFisheye, 'interaction.chartIndex': ChartIndex, 'interaction.tooltip': Tooltip, diff --git a/__tests__/unit/lib/std.spec.ts b/__tests__/unit/lib/std.spec.ts index b8ebf9c8da..8619f8ae0e 100644 --- a/__tests__/unit/lib/std.spec.ts +++ b/__tests__/unit/lib/std.spec.ts @@ -96,6 +96,7 @@ import { ElementSelect, ElementSelectByColor, ElementSelectByX, + ElementPointMove, Fisheye as ChartFisheye, ChartIndex, Tooltip, @@ -315,6 +316,7 @@ describe('stdlib', () => { 'interaction.elementSelect': ElementSelect, 'interaction.elementSelectByX': ElementSelectByX, 'interaction.elementSelectByColor': ElementSelectByColor, + 'interaction.elementPointMove': ElementPointMove, 'interaction.fisheye': ChartFisheye, 'interaction.chartIndex': ChartIndex, 'interaction.tooltip': Tooltip, diff --git a/site/examples/interaction/data/demo/bar-element-point-move.ts b/site/examples/interaction/data/demo/bar-element-point-move.ts new file mode 100644 index 0000000000..5bb376714c --- /dev/null +++ b/site/examples/interaction/data/demo/bar-element-point-move.ts @@ -0,0 +1,50 @@ +import { Chart } from '@antv/g2'; + +const data = [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, +]; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .interval() + .data(data) + .encode('x', '月份') + .encode('y', '月均降雨量') + .encode('color', 'name') + .encode('key', (d) => d['name'] + d['月份']) + .interaction({ + legendFilter: false, + elementPointMove: { + precision: 3, + selected: [5], + selectedChange: (newSelected) => { + console.log(newSelected); + }, + dataChange: (newChangeData, newData) => { + console.log(newChangeData, newData); + }, + }, + }) + .transform({ type: 'stackY' }) + .coordinate({ transform: [{ type: 'transpose' }] }); + +chart.render(); diff --git a/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts b/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts new file mode 100644 index 0000000000..0c39d9a8ae --- /dev/null +++ b/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts @@ -0,0 +1,52 @@ +import { Chart } from '@antv/g2'; + +const data = [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, +]; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .interval() + .data(data) + .transform({ type: 'stackY' }) + .transform({ type: 'normalizeY' }) + .transform({ type: 'sortX', by: 'y', reverse: true }) + .encode('x', '月份') + .encode('y', '月均降雨量') + .encode('color', 'name') + .encode('key', (d) => d['name'] + d['月份']) + .interaction({ + legendFilter: false, + elementPointMove: { + precision: 3, + selected: [5], + selectedChange: (newSelected) => { + console.log(newSelected); + }, + dataChange: (newChangeData, newData) => { + console.log(newChangeData, newData); + }, + }, + }) + .coordinate({ transform: [{ type: 'transpose' }] }); + +chart.render(); diff --git a/site/examples/interaction/data/demo/column-element-point-move.ts b/site/examples/interaction/data/demo/column-element-point-move.ts new file mode 100644 index 0000000000..0cad220b72 --- /dev/null +++ b/site/examples/interaction/data/demo/column-element-point-move.ts @@ -0,0 +1,49 @@ +import { Chart } from '@antv/g2'; + +const data = [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, +]; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .interval() + .data(data) + .encode('x', '月份') + .encode('y', '月均降雨量') + .encode('color', 'name') + .encode('key', (d) => d['name'] + d['月份']) + .interaction({ + legendFilter: false, + elementPointMove: { + precision: 3, + selected: [5], + selectedChange: (newSelected) => { + console.log(newSelected); + }, + dataChange: (newChangeData, newData) => { + console.log(newChangeData, newData); + }, + }, + }) + .transform({ type: 'stackY' }); + +chart.render(); diff --git a/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts b/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts new file mode 100644 index 0000000000..b63f018912 --- /dev/null +++ b/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts @@ -0,0 +1,51 @@ +import { Chart } from '@antv/g2'; + +const data = [ + { name: 'London', 月份: 'Jan.', 月均降雨量: 18.9 }, + { name: 'London', 月份: 'Feb.', 月均降雨量: 28.8 }, + { name: 'London', 月份: 'Mar.', 月均降雨量: 39.3 }, + { name: 'London', 月份: 'Apr.', 月均降雨量: 81.4 }, + { name: 'London', 月份: 'May', 月均降雨量: 47 }, + { name: 'London', 月份: 'Jun.', 月均降雨量: 20.3 }, + { name: 'London', 月份: 'Jul.', 月均降雨量: 24 }, + { name: 'London', 月份: 'Aug.', 月均降雨量: 35.6 }, + { name: 'Berlin', 月份: 'Jan.', 月均降雨量: 12.4 }, + { name: 'Berlin', 月份: 'Feb.', 月均降雨量: 23.2 }, + { name: 'Berlin', 月份: 'Mar.', 月均降雨量: 34.5 }, + { name: 'Berlin', 月份: 'Apr.', 月均降雨量: 99.7 }, + { name: 'Berlin', 月份: 'May', 月均降雨量: 52.6 }, + { name: 'Berlin', 月份: 'Jun.', 月均降雨量: 35.5 }, + { name: 'Berlin', 月份: 'Jul.', 月均降雨量: 37.4 }, + { name: 'Berlin', 月份: 'Aug.', 月均降雨量: 42.4 }, +]; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .interval() + .data(data) + .transform({ type: 'stackY' }) + .transform({ type: 'normalizeY' }) + .transform({ type: 'sortX', by: 'y', reverse: true }) + .encode('x', '月份') + .encode('y', '月均降雨量') + .encode('color', 'name') + .encode('key', (d) => d['name'] + d['月份']) + .interaction({ + legendFilter: false, + elementPointMove: { + precision: 3, + selected: [5], + selectedChange: (newSelected) => { + console.log(newSelected); + }, + dataChange: (newChangeData, newData) => { + console.log(newChangeData, newData); + }, + }, + }); + +chart.render(); diff --git a/site/examples/interaction/data/demo/line-element-point-move.ts b/site/examples/interaction/data/demo/line-element-point-move.ts new file mode 100644 index 0000000000..150f213bb6 --- /dev/null +++ b/site/examples/interaction/data/demo/line-element-point-move.ts @@ -0,0 +1,65 @@ +/** + * A recreation of this demo: https://observablehq.com/@d3/line-chart + */ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .line() + .data([ + { year: '1991', value: 3, type: 'type1' }, + { year: '1992', value: 4, type: 'type1' }, + { year: '1993', value: 3.5, type: 'type1' }, + { year: '1994', value: 5, type: 'type1' }, + { year: '1995', value: 4.9, type: 'type1' }, + { year: '1996', value: 2, type: 'type1' }, + { year: '1997', value: 7, type: 'type1' }, + { year: '1998', value: 11, type: 'type1' }, + { year: '1999', value: 13, type: 'type1' }, + { year: '1991', value: 6, type: 'type2' }, + { year: '1992', value: 1, type: 'type2' }, + { year: '1993', value: 4, type: 'type2' }, + { year: '1994', value: 9, type: 'type2' }, + { year: '1995', value: 1.9, type: 'type2' }, + { year: '1996', value: 5, type: 'type2' }, + { year: '1997', value: 4, type: 'type2' }, + { year: '1998', value: 6, type: 'type2' }, + { year: '1999', value: 15, type: 'type2' }, + ]) + .interaction({ + legendFilter: false, + elementPointMove: { + precision: 4, + selected: [1, 4], + pointStyle: { + r: 8, + strokeWidth: 2, + activeStroke: '#fff', + }, + lineDashPathStyle: { + lineDash: [2, 4], + stroke: 'red', + }, + labelStyle: { + fontSize: 14, + y: 24, + }, + selectedChange: (newSelected) => { + console.log(newSelected); + }, + dataChange: (newChangeData, newData) => { + console.log(newChangeData, newData); + }, + }, + }) + // .tooltip(false) + .encode('x', 'year') + .encode('y', 'value') + .encode('key', 'type') + .encode('color', 'type'); + +chart.render(); diff --git a/site/examples/interaction/data/demo/meta.json b/site/examples/interaction/data/demo/meta.json new file mode 100644 index 0000000000..af2b04279c --- /dev/null +++ b/site/examples/interaction/data/demo/meta.json @@ -0,0 +1,48 @@ +{ + "title": { + "zh": "中文分类", + "en": "Category" + }, + "demos": [ + { + "filename": "line-element-point-move.ts", + "title": { + "zh": "折线图-数形交互", + "en": "Line Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*XO4yQqSSeSoAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "column-element-point-move.ts", + "title": { + "zh": "柱形图-数形交互", + "en": "Column Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*fZn9TYPR2mcAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "column-normalizeY-element-point-move.ts", + "title": { + "zh": "柱形图-百分比堆叠-数形交互", + "en": "Column NormalizeY Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*G5a8T7lP0ZEAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "bar-element-point-move.ts", + "title": { + "zh": "条形图-数形交互", + "en": "Bar Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*WQnwTJ-gJq0AAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "bar-normalizeY-element-point-move.ts", + "title": { + "zh": "条形图-百分比堆叠-数形交互", + "en": "Bar NormalizeY Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*SDtmQrDx7cAAAAAAAAAAAAAADmJ7AQ/original" + } + ] +} diff --git a/site/examples/interaction/data/index.en.md b/site/examples/interaction/data/index.en.md new file mode 100644 index 0000000000..ca057c69cc --- /dev/null +++ b/site/examples/interaction/data/index.en.md @@ -0,0 +1,4 @@ +--- +title: Numerical Interaction +order: 4 +--- \ No newline at end of file diff --git a/site/examples/interaction/data/index.zh.md b/site/examples/interaction/data/index.zh.md new file mode 100644 index 0000000000..2b81c30219 --- /dev/null +++ b/site/examples/interaction/data/index.zh.md @@ -0,0 +1,4 @@ +--- +title: 数形交互 +order: 4 +--- diff --git a/src/interaction/elementPointMove.ts b/src/interaction/elementPointMove.ts new file mode 100644 index 0000000000..408c80eaf5 --- /dev/null +++ b/src/interaction/elementPointMove.ts @@ -0,0 +1,508 @@ +import { Text, Group, Circle, Path } from '@antv/g'; +import { deepMix, isUndefined, find, get, filter } from '@antv/util'; + +import type { PathArray } from '@antv/util'; +import type { CircleStyleProps, TextStyleProps, PathStyleProps } from '@antv/g'; +import { selectPlotArea } from './utils'; + +// Get element. +const getElements = (plot) => { + return plot.querySelectorAll('.element'); +}; + +export type ElementPointMoveOptions = { + selected?: number[]; + selectedChange?: (selected) => void; + dataChange?: (newChangeData, newData) => void; + labelStyle?: TextStyleProps; + lineDashPathStyle?: PathStyleProps; + pointStyle?: CircleStyleProps; + precision?: number; + [key: string]: any; +}; + +const DEFAULT_STYLE = { + pointStyle: { + r: 6, + strokeWidth: 1, + stroke: '#333', + activeStroke: '#f5f5f5', + } as CircleStyleProps, + lineDashPathStyle: { + stroke: '#888', + lineDash: [3, 4], + }, + labelStyle: { + fontSize: 12, + fill: '#888', + stroke: '#fff', + lineWidth: 1, + y: -6, + x: 2, + } as TextStyleProps, +}; + +// point shape name. +const MOVE_POINT_NAME = 'movePoint'; + +// Element mouseenter change style. +const elementMouseenter = (e) => { + const element = e.target; + const { markType } = element; + // Mark line. + if (markType === 'line') { + element.attr('_lineWidth', element.attr('lineWidth') || 1); + element.attr('lineWidth', element.attr('_lineWidth') + 3); + } + // Mark interval. + if (markType === 'interval') { + element.attr('_opacity', element.attr('opacity') || 1); + element.attr('opacity', 0.7 * element.attr('_opacity')); + } +}; + +// Element mouseleave change style. +const elementMouseleave = (e) => { + const element = e.target; + const { markType } = element; + // Mark line. + if (markType === 'line') { + element.attr('lineWidth', element.attr('_lineWidth')); + } + // Mark interval. + if (markType === 'interval') { + element.attr('opacity', element.attr('_opacity')); + } +}; + +// Points create path. +const getPointsPath = (points: number[][], isClose = false) => { + const path = filter(points, (d) => !!d).map((d, i) => { + return [i === 0 ? 'M' : 'L', ...d]; + }) as PathArray; + + if (isClose) { + path.push(['Z']); + } + return path; +}; + +// Get the latest overall data based on the individual data changes. +const getNewData = (newChangeData, data, encode) => { + return data.map((d) => { + if (encode.x && d[encode.x] === newChangeData[encode.x]) { + if (encode.color) { + return d[encode.color] === newChangeData[encode.color] + ? newChangeData + : d; + } else { + return newChangeData; + } + } + + return d; + }); +}; + +// Find origin element data. +const getElementDataRatioTransformFn = (element) => { + const v = get(element, ['__data__', 'items', '0', 'value']); + const { + __data__: { data, encode, transform }, + childNodes, + } = element.parentNode; + const isNormalizeY = find(transform, ({ type }) => type === 'normalizeY'); + const yField = get(encode, ['y', 'field']); + const value = data[childNodes.indexOf(element)][yField]; + + return (newValue) => { + if (isNormalizeY) { + return (newValue / (1 - newValue) / (v / (1 - v))) * value; + } + + return newValue; + }; +}; + +// Point shape select change style. +const selectedPointsStyle = (pointsShape, selected, defaultStyle) => { + pointsShape.forEach((shape, index) => { + shape.attr( + 'stroke', + selected[1] === index + ? defaultStyle['activeStroke'] + : defaultStyle['stroke'], + ); + }); +}; + +// Create help show message shape. +const createHelpShape = ( + group, + circle, + pathStyle, + labelStyle, +): [Path, Text] => { + const pathShape = new Path({ + style: pathStyle, + }); + + const labelShape = new Text({ + style: labelStyle, + }); + + circle.appendChild(labelShape); + group.appendChild(pathShape); + return [pathShape, labelShape]; +}; + +// Get color scale type. +const getColorType = (scaleColor, color) => { + const indexOf = get(scaleColor, ['options', 'range', 'indexOf']); + if (!indexOf) return; + const i = scaleColor.options.range.indexOf(color); + return scaleColor.sortedDomain[i]; +}; + +/** + * ElementPointMove interaction. + */ +export function ElementPointMove( + elementPointMoveOptions: ElementPointMoveOptions = {}, +) { + const { + pointStyle = {}, + lineDashPathStyle = {}, + labelStyle = {}, + selected = [0], + selectedChange = () => {}, + dataChange = () => {}, + precision = 2, + } = elementPointMoveOptions; + + // Shape default style. + const pathDefaultStyle = { + ...DEFAULT_STYLE.lineDashPathStyle, + ...lineDashPathStyle, + }; + + const labelDefaultStyle = { + ...DEFAULT_STYLE.labelStyle, + ...labelStyle, + }; + + const pointDefaultStyle = { + ...DEFAULT_STYLE.pointStyle, + ...pointStyle, + }; + + return (context) => { + const { + update, + setState, + container, + view, + options: { marks, coordinate: coordinateOptions }, + } = context; + const plotArea = selectPlotArea(container); + const elements = getElements(plotArea); + let newState; + let newSelected = selected; + + const { transform = [] } = coordinateOptions; + const isTranspose = !!find(transform, ({ type }) => type === 'transpose'); + + // Create points + const pointsGroup = new Group({ + style: { + // Tooltip point need down. + zIndex: 2, + }, + }); + plotArea.appendChild(pointsGroup); + + // Element click change style. + const elementClick = (e) => { + const element = e.target; + newSelected = [element.parentNode.childNodes.indexOf(element)]; + selectedChange(newSelected); + createPoints(element); + }; + + // Create select element points. + const createPoints = (element) => { + const { attributes, markType, __data__: data } = element; + const { stroke: fill } = attributes; + const { points, seriesTitle, color, title } = data; + + // Transpose Currently only do mark interval; + if (isTranspose && markType !== 'interval') return; + + pointsGroup.removeChildren(); + let downPointHeight = 0; + + const updateView = async (x, y, color, markType) => { + setState('elementPointMove', (viewOptions) => { + // Update marks. + const newMarks = (newState?.options?.marks || marks).map((mark) => { + if (mark.type !== markType) return mark; + const { data, encode } = mark; + const encodeKeys = Object.keys(encode); + + // Get change new one element data. + const newChangeData = encodeKeys.reduce((value, key) => { + const dataKey = encode[key]; + if (key === 'x') { + value[dataKey] = x; + } + if (key === 'y') { + value[dataKey] = y; + } + if (key === 'color') { + value[dataKey] = color; + } + return value; + }, {} as any); + + // Get change new all data. + const newData = getNewData(newChangeData, data, encode); + dataChange(newChangeData, newData); + + return deepMix({}, mark, { + data: newData, + // No need animate + animate: false, + }); + }); + + return { ...viewOptions, marks: newMarks }; + }); + + return await update('elementPointMove'); + }; + + if (markType === 'line') { + points.forEach((p, index) => { + const circle = new Circle({ + name: MOVE_POINT_NAME, + style: { + cx: p[0], + cy: p[1], + fill, + ...pointDefaultStyle, + }, + }); + + circle.addEventListener('mousedown', (e) => { + const { scale, coordinate } = newState?.view || view; + const { color: scaleColor, y: scaleY } = scale; + + container.attr('cursor', 'move'); + + newSelected[1] = index; + selectedPointsStyle( + pointsGroup.childNodes, + newSelected, + pointDefaultStyle, + ); + selectedChange(newSelected); + + const [pathShape, labelShape] = createHelpShape( + pointsGroup, + circle, + pathDefaultStyle, + labelDefaultStyle, + ); + + // Point move change text + const pointMousemove = (e) => { + const newCy = p[1] + e.clientY - downPointHeight; + const [, y] = coordinate.invert([p[0], newCy]); + const newPath = getPointsPath([ + points[index - 1], + [p[0], newCy], + points[index + 1], + ]); + labelShape.attr('text', scaleY.invert(y).toFixed(precision)); + pathShape.attr('path', newPath); + circle.attr('cy', newCy); + }; + + downPointHeight = e.clientY; + window.addEventListener('mousemove', pointMousemove); + + const mouseupFn = async () => { + container.attr('cursor', 'default'); + window.removeEventListener('mousemove', pointMousemove); + container.removeEventListener('mouseup', mouseupFn); + + if (isUndefined(labelShape.attr('text'))) return; + + const x = seriesTitle[index]; + const y = Number(labelShape.attr('text')); + const colorType = getColorType(scaleColor, color); + + newState = await updateView(x, y, colorType, 'line'); + + labelShape.remove(); + pathShape.remove(); + createPoints(element); + }; + + container.addEventListener('mouseup', mouseupFn); + }); + + pointsGroup.appendChild(circle); + }); + + selectedPointsStyle( + pointsGroup.childNodes, + newSelected, + pointDefaultStyle, + ); + } else if (markType === 'interval') { + const circlePoint = isTranspose + ? [points[0][0], (points[0][1] + points[1][1]) / 2] + : [(points[0][0] + points[1][0]) / 2, points[0][1]]; + const ratioTransform = getElementDataRatioTransformFn(element); + + const circle = new Circle({ + name: MOVE_POINT_NAME, + style: { + cx: circlePoint[0], + cy: circlePoint[1], + fill, + ...pointDefaultStyle, + stroke: pointDefaultStyle['activeStroke'], + }, + }); + + circle.addEventListener('mousedown', (e) => { + const { scale, coordinate } = newState?.view || view; + const { color: scaleColor, y: scaleY } = scale; + container.attr('cursor', 'move'); + + const colorType = getColorType(scaleColor, color); + + const [pathShape, labelShape] = createHelpShape( + pointsGroup, + circle, + pathDefaultStyle, + labelDefaultStyle, + ); + + // Point move change text + const pointMousemove = (e) => { + if (isTranspose) { + const newCx = circlePoint[0] + e.clientX - downPointHeight; + const [initX] = coordinate.output([ + scaleY.output(0), + scaleY.output(0), + ]); + + const [, x] = coordinate.invert([ + initX + (newCx - points[2][0]), + circlePoint[1], + ]); + const newPath = getPointsPath( + [ + [newCx, points[0][1]], + [newCx, points[1][1]], + points[2], + points[3], + ], + true, + ); + + labelShape.attr( + 'text', + ratioTransform(scaleY.invert(x)).toFixed(precision), + ); + pathShape.attr('path', newPath); + circle.attr('cx', newCx); + } else { + const newCy = circlePoint[1] + e.clientY - downPointHeight; + const [, initY] = coordinate.output([1, scaleY.output(0)]); + + const [, y] = coordinate.invert([ + circlePoint[0], + initY - (points[2][1] - newCy), + ]); + const newPath = getPointsPath( + [ + [points[0][0], newCy], + [points[1][0], newCy], + points[2], + points[3], + ], + true, + ); + + labelShape.attr( + 'text', + ratioTransform(scaleY.invert(y)).toFixed(precision), + ); + pathShape.attr('path', newPath); + circle.attr('cy', newCy); + } + }; + + downPointHeight = isTranspose ? e.clientX : e.clientY; + window.addEventListener('mousemove', pointMousemove); + + // Change mosueup change data and update 、clear shape. + const mouseupFn = async () => { + container.attr('cursor', 'default'); + container.removeEventListener('mouseup', mouseupFn); + window.removeEventListener('mousemove', pointMousemove); + + if (isUndefined(labelShape.attr('text'))) return; + + const y = Number(labelShape.attr('text')); + + newState = await updateView(title, y, colorType, 'interval'); + + labelShape.remove(); + pathShape.remove(); + createPoints(element); + }; + + container.addEventListener('mouseup', mouseupFn); + }); + + pointsGroup.appendChild(circle); + } + }; + + // Add EventListener. + elements.forEach((element, index) => { + if (index === newSelected[0]) { + createPoints(element); + } + element.addEventListener('click', elementClick); + element.addEventListener('mouseenter', elementMouseenter); + element.addEventListener('mouseleave', elementMouseleave); + }); + + const rootClick = (e) => { + const element = e.target; + if (element.name !== MOVE_POINT_NAME && !elements.includes(element)) { + newSelected[1] = null; + pointsGroup.removeChildren(); + } + }; + + container.addEventListener('mousedown', rootClick); + + // Remove EventListener. + return () => { + pointsGroup.remove(); + container.removeEventListener('mousedown', rootClick); + elements.forEach((element) => { + element.removeEventListener('click', elementClick); + element.removeEventListener('mouseenter', elementMouseenter); + element.removeEventListener('mouseleave', elementMouseleave); + }); + }; + }; +} diff --git a/src/interaction/index.ts b/src/interaction/index.ts index 43b4631cc8..f7db826c3f 100644 --- a/src/interaction/index.ts +++ b/src/interaction/index.ts @@ -21,3 +21,4 @@ export { ScrollbarFilter } from './scrollbarFilter'; export { Poptip } from './poptip'; export { Event } from './event'; export { TreemapDrillDown } from './treemapDrillDown'; +export { ElementPointMove } from './elementPointMove'; diff --git a/src/lib/core.ts b/src/lib/core.ts index afb9bba9e0..0c95f073d8 100644 --- a/src/lib/core.ts +++ b/src/lib/core.ts @@ -101,6 +101,7 @@ import { Poptip, ScrollbarFilter, TreemapDrillDown, + ElementPointMove, } from '../interaction'; import { SpaceLayer, @@ -301,6 +302,7 @@ export function corelib() { 'interaction.scrollbarFilter': ScrollbarFilter, 'interaction.poptip': Poptip, 'interaction.treemapDrillDown': TreemapDrillDown, + 'interaction.elementPointMove': ElementPointMove, 'composition.spaceLayer': SpaceLayer, 'composition.spaceFlex': SpaceFlex, 'composition.facetRect': FacetRect, From 68ddca1989a813ab53cc2f41d208ba235145e0f0 Mon Sep 17 00:00:00 2001 From: wb-xcf804241 Date: Thu, 7 Mar 2024 21:10:04 +0800 Subject: [PATCH 2/5] feat(interaction): add elementpointmove interaction --- .../static/flareElementPointMoveArea.svg | 1619 +++++++++++++++++ .../flareElementPointMoveAreaNormalizeY.svg | 1586 ++++++++++++++++ .../static/flareElementPointMoveLine.svg | 16 +- .../static/flareElementPointMovePie.svg | 642 +++++++ .../static/flareElementPointMoveRadar.svg | 1273 +++++++++++++ ...lare-element-point-move-area-normalizeY.ts | 44 + .../static/flare-element-point-move-area.ts | 34 + .../static/flare-element-point-move-pie.ts | 34 + .../static/flare-element-point-move-radar.ts | 64 + __tests__/plots/static/index.ts | 4 + .../data/demo/area-element-point-move.ts | 41 + .../area-normalizeY-element-point-move.ts | 52 + .../demo/line-element-point-move-polar.ts | 81 + .../data/demo/line-element-point-move.ts | 5 - site/examples/interaction/data/demo/meta.json | 32 + .../data/demo/pie-element-point-move.ts | 41 + src/interaction/elementPointMove.ts | 271 ++- src/interaction/treemapDrillDown.ts | 6 +- src/interaction/utils.ts | 52 + 19 files changed, 5810 insertions(+), 87 deletions(-) create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveArea.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveAreaNormalizeY.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMovePie.svg create mode 100644 __tests__/integration/snapshots/static/flareElementPointMoveRadar.svg create mode 100644 __tests__/plots/static/flare-element-point-move-area-normalizeY.ts create mode 100644 __tests__/plots/static/flare-element-point-move-area.ts create mode 100644 __tests__/plots/static/flare-element-point-move-pie.ts create mode 100644 __tests__/plots/static/flare-element-point-move-radar.ts create mode 100644 site/examples/interaction/data/demo/area-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts create mode 100644 site/examples/interaction/data/demo/line-element-point-move-polar.ts create mode 100644 site/examples/interaction/data/demo/pie-element-point-move.ts diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveArea.svg b/__tests__/integration/snapshots/static/flareElementPointMoveArea.svg new file mode 100644 index 0000000000..dbc78a9fbf --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveArea.svg @@ -0,0 +1,1619 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + type1 + + + + + + + + + + + + + + + + + + + + type2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1991 + + + + + + + 1992 + + + + + + + 1993 + + + + + + + 1994 + + + + + + + 1995 + + + + + + + 1996 + + + + + + + 1997 + + + + + + + 1998 + + + + + + + 1999 + + + + + + + + + year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 2 + + + + + + + 4 + + + + + + + 6 + + + + + + + 8 + + + + + + + 10 + + + + + + + 12 + + + + + + + 14 + + + + + + + + + value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveAreaNormalizeY.svg b/__tests__/integration/snapshots/static/flareElementPointMoveAreaNormalizeY.svg new file mode 100644 index 0000000000..d0012c8ad7 --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveAreaNormalizeY.svg @@ -0,0 +1,1586 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + type1 + + + + + + + + + + + + + + + + + + + + type2 + + + + + + + + + + + + + + + + + + + + type3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1991 + + + + + + + 1992 + + + + + + + 1993 + + + + + + + 1994 + + + + + + + 1995 + + + + + + + 1996 + + + + + + + 1997 + + + + + + + 1998 + + + + + + + 1999 + + + + + + + + + year + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 0.2 + + + + + + + 0.4 + + + + + + + 0.6 + + + + + + + 0.8 + + + + + + + 1 + + + + + + + + + value + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg b/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg index b213f11017..b3b2d488c4 100644 --- a/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg +++ b/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg @@ -1445,7 +1445,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1458,7 +1458,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1471,7 +1471,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1484,7 +1484,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1510,7 +1510,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1523,7 +1523,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1536,7 +1536,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> @@ -1549,7 +1549,7 @@ cy="6" r="6" stroke-width="1" - stroke="rgba(51,51,51,1)" + stroke="rgba(136,136,136,1)" /> diff --git a/__tests__/integration/snapshots/static/flareElementPointMovePie.svg b/__tests__/integration/snapshots/static/flareElementPointMovePie.svg new file mode 100644 index 0000000000..1b08bc0f58 --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMovePie.svg @@ -0,0 +1,642 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 事例一 + + + + + + + + + + + + + + + + + + + + 事例二 + + + + + + + + + + + + + + + + + + + + 事例三 + + + + + + + + + + + + + + + + + + + + 事例四 + + + + + + + + + + + + + + + + + + + + 事例五 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/integration/snapshots/static/flareElementPointMoveRadar.svg b/__tests__/integration/snapshots/static/flareElementPointMoveRadar.svg new file mode 100644 index 0000000000..912beb33b2 --- /dev/null +++ b/__tests__/integration/snapshots/static/flareElementPointMoveRadar.svg @@ -0,0 +1,1273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + + + + + + + + + + + + + + + + + + + + b + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Design + + + + + + + Development + + + + + + + Marketing + + + + + + + Users + + + + + + + Test + + + + + + + Language + + + + + + + Technology + + + + + + + Support + + + + + + + Sales + + + + + + + UX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + 20 + + + + + + + 40 + + + + + + + 60 + + + + + + + 80 + + + + + + + + + + + + \ No newline at end of file diff --git a/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts b/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts new file mode 100644 index 0000000000..4d956f14a9 --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts @@ -0,0 +1,44 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveAreaNormalizeY(): G2Spec { + return { + type: 'area', + width: 600, + height: 400, + data: [ + { year: '1991', value: 3, type: 'type1' }, + { year: '1992', value: 4, type: 'type1' }, + { year: '1993', value: 3.5, type: 'type1' }, + { year: '1994', value: 5, type: 'type1' }, + { year: '1995', value: 4.9, type: 'type1' }, + { year: '1996', value: 2, type: 'type1' }, + { year: '1997', value: 7, type: 'type1' }, + { year: '1998', value: 11, type: 'type1' }, + { year: '1999', value: 13, type: 'type1' }, + { year: '1991', value: 6, type: 'type2' }, + { year: '1992', value: 1, type: 'type2' }, + { year: '1993', value: 4, type: 'type2' }, + { year: '1994', value: 9, type: 'type2' }, + { year: '1995', value: 1.9, type: 'type2' }, + { year: '1996', value: 5, type: 'type2' }, + { year: '1997', value: 4, type: 'type2' }, + { year: '1998', value: 6, type: 'type2' }, + { year: '1999', value: 15, type: 'type2' }, + { year: '1991', value: 6, type: 'type3' }, + { year: '1992', value: 1, type: 'type3' }, + { year: '1993', value: 4, type: 'type3' }, + { year: '1994', value: 9, type: 'type3' }, + { year: '1995', value: 1.9, type: 'type3' }, + { year: '1996', value: 5, type: 'type3' }, + { year: '1997', value: 4, type: 'type3' }, + { year: '1998', value: 6, type: 'type3' }, + { year: '1999', value: 15, type: 'type3' }, + ], + encode: { x: 'year', y: 'value', key: 'type', color: 'type' }, + transform: [{ type: 'stackY' }, { type: 'normalizeY' }], + interaction: { + legendFilter: false, + elementPointMove: { selected: [1, 4] }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-area.ts b/__tests__/plots/static/flare-element-point-move-area.ts new file mode 100644 index 0000000000..cbbc75efa3 --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-area.ts @@ -0,0 +1,34 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveArea(): G2Spec { + return { + type: 'area', + width: 600, + height: 400, + data: [ + { year: '1991', value: 3, type: 'type1' }, + { year: '1992', value: 4, type: 'type1' }, + { year: '1993', value: 3.5, type: 'type1' }, + { year: '1994', value: 5, type: 'type1' }, + { year: '1995', value: 4.9, type: 'type1' }, + { year: '1996', value: 2, type: 'type1' }, + { year: '1997', value: 7, type: 'type1' }, + { year: '1998', value: 11, type: 'type1' }, + { year: '1999', value: 13, type: 'type1' }, + { year: '1991', value: 6, type: 'type2' }, + { year: '1992', value: 1, type: 'type2' }, + { year: '1993', value: 4, type: 'type2' }, + { year: '1994', value: 9, type: 'type2' }, + { year: '1995', value: 1.9, type: 'type2' }, + { year: '1996', value: 5, type: 'type2' }, + { year: '1997', value: 4, type: 'type2' }, + { year: '1998', value: 6, type: 'type2' }, + { year: '1999', value: 15, type: 'type2' }, + ], + encode: { x: 'year', y: 'value', key: 'type', color: 'type' }, + interaction: { + legendFilter: false, + elementPointMove: { selected: [1, 4] }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-pie.ts b/__tests__/plots/static/flare-element-point-move-pie.ts new file mode 100644 index 0000000000..ea7acd7d42 --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-pie.ts @@ -0,0 +1,34 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMovePie(): G2Spec { + return { + type: 'interval', + width: 600, + height: 400, + data: [ + { item: '事例一', count: 40, percent: 0.4 }, + { item: '事例二', count: 21, percent: 0.21 }, + { item: '事例三', count: 17, percent: 0.17 }, + { item: '事例四', count: 13, percent: 0.13 }, + { item: '事例五', count: 9, percent: 0.09 }, + ], + encode: { y: 'count', color: 'item', key: 'item' }, + transform: [{ type: 'stackY' }], + coordinate: { type: 'theta', outerRadius: 0.8 }, + tooltip: { + items: [ + (data) => ({ + name: data.item, + value: `${data.percent * 100}%`, + }), + ], + }, + interaction: { + legendFilter: false, + elementPointMove: { + selected: [2], + lineDashPathStyle: { lineDash: [2, 4], stroke: '#fff', lineWidth: 2 }, + }, + }, + }; +} diff --git a/__tests__/plots/static/flare-element-point-move-radar.ts b/__tests__/plots/static/flare-element-point-move-radar.ts new file mode 100644 index 0000000000..3be9784d8a --- /dev/null +++ b/__tests__/plots/static/flare-element-point-move-radar.ts @@ -0,0 +1,64 @@ +import { G2Spec } from '../../../src'; + +export function flareElementPointMoveRadar(): G2Spec { + return { + type: 'view', + width: 600, + height: 400, + data: [ + { item: 'Design', type: 'a', score: 70 }, + { item: 'Design', type: 'b', score: 30 }, + { item: 'Development', type: 'a', score: 60 }, + { item: 'Development', type: 'b', score: 70 }, + { item: 'Marketing', type: 'a', score: 50 }, + { item: 'Marketing', type: 'b', score: 60 }, + { item: 'Users', type: 'a', score: 40 }, + { item: 'Users', type: 'b', score: 50 }, + { item: 'Test', type: 'a', score: 60 }, + { item: 'Test', type: 'b', score: 70 }, + { item: 'Language', type: 'a', score: 70 }, + { item: 'Language', type: 'b', score: 50 }, + { item: 'Technology', type: 'a', score: 50 }, + { item: 'Technology', type: 'b', score: 40 }, + { item: 'Support', type: 'a', score: 30 }, + { item: 'Support', type: 'b', score: 40 }, + { item: 'Sales', type: 'a', score: 60 }, + { item: 'Sales', type: 'b', score: 40 }, + { item: 'UX', type: 'a', score: 50 }, + { item: 'UX', type: 'b', score: 60 }, + ], + coordinate: { type: 'polar' }, + scale: { + x: { padding: 0.5, align: 0 }, + y: { tickCount: 5, domainMax: 80 }, + }, + axis: { + x: { grid: true, gridStrokeWidth: 1, tick: false, gridLineDash: [0, 0] }, + y: { + zIndex: 1, + title: false, + gridConnect: 'line', + gridStrokeWidth: 1, + gridLineDash: [0, 0], + }, + }, + children: [ + { + type: 'area', + encode: { x: 'item', y: 'score', color: 'type', key: 'type' }, + style: { fillOpacity: 0.5 }, + }, + { + type: 'line', + encode: { x: 'item', y: 'score', color: 'type', key: 'type' }, + style: { lineWidth: 2 }, + }, + ], + interaction: { + elementPointMove: { + precision: 4, + selected: [1, 4], + }, + }, + }; +} diff --git a/__tests__/plots/static/index.ts b/__tests__/plots/static/index.ts index 4fdccdf000..956912b23c 100644 --- a/__tests__/plots/static/index.ts +++ b/__tests__/plots/static/index.ts @@ -327,3 +327,7 @@ export { flareElementPointMoveInterval } from './flare-element-point-move-interv export { flareElementPointMoveIntervalTranspose } from './flare-element-point-move-interval-transpose'; export { flareElementPointMoveIntervalNormalizeY } from './flare-element-point-move-interval-normalizeY'; export { flareElementPointMoveIntervalNormalizeYTranspose } from './flare-element-point-move-interval-normalizeY-transpose'; +export { flareElementPointMoveRadar } from './flare-element-point-move-radar'; +export { flareElementPointMovePie } from './flare-element-point-move-pie'; +export { flareElementPointMoveArea } from './flare-element-point-move-area'; +export { flareElementPointMoveAreaNormalizeY } from './flare-element-point-move-area-normalizeY'; diff --git a/site/examples/interaction/data/demo/area-element-point-move.ts b/site/examples/interaction/data/demo/area-element-point-move.ts new file mode 100644 index 0000000000..6aeae9cc9e --- /dev/null +++ b/site/examples/interaction/data/demo/area-element-point-move.ts @@ -0,0 +1,41 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .area() + .data([ + { year: '1991', value: 3, type: 'type1' }, + { year: '1992', value: 4, type: 'type1' }, + { year: '1993', value: 3.5, type: 'type1' }, + { year: '1994', value: 5, type: 'type1' }, + { year: '1995', value: 4.9, type: 'type1' }, + { year: '1996', value: 2, type: 'type1' }, + { year: '1997', value: 7, type: 'type1' }, + { year: '1998', value: 11, type: 'type1' }, + { year: '1999', value: 13, type: 'type1' }, + { year: '1991', value: 6, type: 'type2' }, + { year: '1992', value: 1, type: 'type2' }, + { year: '1993', value: 4, type: 'type2' }, + { year: '1994', value: 9, type: 'type2' }, + { year: '1995', value: 1.9, type: 'type2' }, + { year: '1996', value: 5, type: 'type2' }, + { year: '1997', value: 4, type: 'type2' }, + { year: '1998', value: 6, type: 'type2' }, + { year: '1999', value: 15, type: 'type2' }, + ]) + .interaction({ + legendFilter: false, + elementPointMove: { + selected: [1, 4], + }, + }) + .encode('x', 'year') + .encode('y', 'value') + .encode('key', 'type') + .encode('color', 'type'); + +chart.render(); diff --git a/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts b/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts new file mode 100644 index 0000000000..c3d49ef4d8 --- /dev/null +++ b/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts @@ -0,0 +1,52 @@ +import { Chart } from '@antv/g2'; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart + .area() + .data([ + { year: '1991', value: 3, type: 'type1' }, + { year: '1992', value: 4, type: 'type1' }, + { year: '1993', value: 3.5, type: 'type1' }, + { year: '1994', value: 5, type: 'type1' }, + { year: '1995', value: 4.9, type: 'type1' }, + { year: '1996', value: 2, type: 'type1' }, + { year: '1997', value: 7, type: 'type1' }, + { year: '1998', value: 11, type: 'type1' }, + { year: '1999', value: 13, type: 'type1' }, + { year: '1991', value: 6, type: 'type2' }, + { year: '1992', value: 1, type: 'type2' }, + { year: '1993', value: 4, type: 'type2' }, + { year: '1994', value: 9, type: 'type2' }, + { year: '1995', value: 1.9, type: 'type2' }, + { year: '1996', value: 5, type: 'type2' }, + { year: '1997', value: 4, type: 'type2' }, + { year: '1998', value: 6, type: 'type2' }, + { year: '1999', value: 15, type: 'type2' }, + { year: '1991', value: 6, type: 'type3' }, + { year: '1992', value: 1, type: 'type3' }, + { year: '1993', value: 4, type: 'type3' }, + { year: '1994', value: 9, type: 'type3' }, + { year: '1995', value: 1.9, type: 'type3' }, + { year: '1996', value: 5, type: 'type3' }, + { year: '1997', value: 4, type: 'type3' }, + { year: '1998', value: 6, type: 'type3' }, + { year: '1999', value: 15, type: 'type3' }, + ]) + .interaction({ + legendFilter: false, + elementPointMove: { + selected: [1, 4], + }, + }) + .transform({ type: 'stackY' }) + .transform({ type: 'normalizeY' }) + .encode('x', 'year') + .encode('y', 'value') + .encode('key', 'type') + .encode('color', 'type'); + +chart.render(); diff --git a/site/examples/interaction/data/demo/line-element-point-move-polar.ts b/site/examples/interaction/data/demo/line-element-point-move-polar.ts new file mode 100644 index 0000000000..1d85ae21e7 --- /dev/null +++ b/site/examples/interaction/data/demo/line-element-point-move-polar.ts @@ -0,0 +1,81 @@ +import { Chart } from '@antv/g2'; + +const data = [ + { item: 'Design', type: 'a', score: 70 }, + { item: 'Design', type: 'b', score: 30 }, + { item: 'Development', type: 'a', score: 60 }, + { item: 'Development', type: 'b', score: 70 }, + { item: 'Marketing', type: 'a', score: 50 }, + { item: 'Marketing', type: 'b', score: 60 }, + { item: 'Users', type: 'a', score: 40 }, + { item: 'Users', type: 'b', score: 50 }, + { item: 'Test', type: 'a', score: 60 }, + { item: 'Test', type: 'b', score: 70 }, + { item: 'Language', type: 'a', score: 70 }, + { item: 'Language', type: 'b', score: 50 }, + { item: 'Technology', type: 'a', score: 50 }, + { item: 'Technology', type: 'b', score: 40 }, + { item: 'Support', type: 'a', score: 30 }, + { item: 'Support', type: 'b', score: 40 }, + { item: 'Sales', type: 'a', score: 60 }, + { item: 'Sales', type: 'b', score: 40 }, + { item: 'UX', type: 'a', score: 50 }, + { item: 'UX', type: 'b', score: 60 }, +]; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart.coordinate({ type: 'polar' }); + +chart + .data(data) + .scale('x', { padding: 0.5, align: 0 }) + .scale('y', { tickCount: 5, domainMax: 80 }) + .interaction({ + legendFilter: false, + elementPointMove: { + selected: [1, 3], + selectedChange: (newSelected) => { + console.log(newSelected); + }, + dataChange: (newChangeData, newData) => { + console.log(newChangeData, newData); + }, + }, + }) + .axis('x', { + grid: true, + gridStrokeWidth: 1, + tick: false, + gridLineDash: [0, 0], + }) + .axis('y', { + zIndex: 1, + title: false, + gridConnect: 'line', + gridStrokeWidth: 1, + gridLineDash: [0, 0], + }); + +chart + .area() + .encode('x', 'item') + .encode('y', 'score') + .encode('color', 'type') + .encode('key', 'type') + .style('fillOpacity', 0.5); + +chart + .line() + .encode('x', 'item') + .encode('y', 'score') + .encode('color', 'type') + .encode('key', 'type') + .style('lineWidth', 2); + +chart.interaction('tooltip', { crosshairsLineDash: [4, 4] }); + +chart.render(); diff --git a/site/examples/interaction/data/demo/line-element-point-move.ts b/site/examples/interaction/data/demo/line-element-point-move.ts index 150f213bb6..6c6bd49fda 100644 --- a/site/examples/interaction/data/demo/line-element-point-move.ts +++ b/site/examples/interaction/data/demo/line-element-point-move.ts @@ -1,6 +1,3 @@ -/** - * A recreation of this demo: https://observablehq.com/@d3/line-chart - */ import { Chart } from '@antv/g2'; const chart = new Chart({ @@ -33,7 +30,6 @@ chart .interaction({ legendFilter: false, elementPointMove: { - precision: 4, selected: [1, 4], pointStyle: { r: 8, @@ -56,7 +52,6 @@ chart }, }, }) - // .tooltip(false) .encode('x', 'year') .encode('y', 'value') .encode('key', 'type') diff --git a/site/examples/interaction/data/demo/meta.json b/site/examples/interaction/data/demo/meta.json index af2b04279c..d2e35b173f 100644 --- a/site/examples/interaction/data/demo/meta.json +++ b/site/examples/interaction/data/demo/meta.json @@ -12,6 +12,22 @@ }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*XO4yQqSSeSoAAAAAAAAAAAAADmJ7AQ/original" }, + { + "filename": "area-element-point-move.ts", + "title": { + "zh": "面积图-数形交互", + "en": "Area Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*FTm7T5CfHsUAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "area-normalizeY-element-point-move.ts", + "title": { + "zh": "面积图-百分比堆叠-数形交互", + "en": "Area NormalizeY Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*xWt3R5fzwH4AAAAAAAAAAAAADmJ7AQ/original" + }, { "filename": "column-element-point-move.ts", "title": { @@ -43,6 +59,22 @@ "en": "Bar NormalizeY Numerical Interaction" }, "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*SDtmQrDx7cAAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "line-element-point-move-polar.ts", + "title": { + "zh": "雷达图-数形交互", + "en": "Radar Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*ifgPT565BPkAAAAAAAAAAAAADmJ7AQ/original" + }, + { + "filename": "pie-element-point-move.ts", + "title": { + "zh": "饼图-数形交互", + "en": "Pie Numerical Interaction" + }, + "screenshot": "https://mdn.alipayobjects.com/huamei_qa8qxu/afts/img/A*Hm0PR5262sgAAAAAAAAAAAAADmJ7AQ/original" } ] } diff --git a/site/examples/interaction/data/demo/pie-element-point-move.ts b/site/examples/interaction/data/demo/pie-element-point-move.ts new file mode 100644 index 0000000000..d5b20a771b --- /dev/null +++ b/site/examples/interaction/data/demo/pie-element-point-move.ts @@ -0,0 +1,41 @@ +import { Chart } from '@antv/g2'; + +const data = [ + { item: '事例一', count: 40, percent: 0.4 }, + { item: '事例二', count: 21, percent: 0.21 }, + { item: '事例三', count: 17, percent: 0.17 }, + { item: '事例四', count: 13, percent: 0.13 }, + { item: '事例五', count: 9, percent: 0.09 }, +]; + +const chart = new Chart({ + container: 'container', + autoFit: true, +}); + +chart.coordinate({ type: 'theta', outerRadius: 0.8 }); + +chart + .interval() + .data(data) + .transform({ type: 'stackY' }) + .interaction({ + legendFilter: false, + elementPointMove: { + selected: [1], + lineDashPathStyle: { + lineDash: [2, 4], + stroke: '#fff', + lineWidth: 2, + }, + }, + }) + .encode('y', 'count') + .encode('color', 'item') + .encode('key', 'item') + .tooltip((data) => ({ + name: data.item, + value: `${data.percent * 100}%`, + })); + +chart.render(); diff --git a/src/interaction/elementPointMove.ts b/src/interaction/elementPointMove.ts index 408c80eaf5..a15e63ad9f 100644 --- a/src/interaction/elementPointMove.ts +++ b/src/interaction/elementPointMove.ts @@ -1,14 +1,14 @@ import { Text, Group, Circle, Path } from '@antv/g'; -import { deepMix, isUndefined, find, get, filter } from '@antv/util'; +import { deepMix, isUndefined, find, get } from '@antv/util'; -import type { PathArray } from '@antv/util'; import type { CircleStyleProps, TextStyleProps, PathStyleProps } from '@antv/g'; -import { selectPlotArea } from './utils'; - -// Get element. -const getElements = (plot) => { - return plot.querySelectorAll('.element'); -}; +import { + selectPlotArea, + getPointsR, + getPointsPath, + getElements, + getThetaPath, +} from './utils'; export type ElementPointMoveOptions = { selected?: number[]; @@ -25,7 +25,7 @@ const DEFAULT_STYLE = { pointStyle: { r: 6, strokeWidth: 1, - stroke: '#333', + stroke: '#888', activeStroke: '#f5f5f5', } as CircleStyleProps, lineDashPathStyle: { @@ -75,38 +75,28 @@ const elementMouseleave = (e) => { } }; -// Points create path. -const getPointsPath = (points: number[][], isClose = false) => { - const path = filter(points, (d) => !!d).map((d, i) => { - return [i === 0 ? 'M' : 'L', ...d]; - }) as PathArray; - - if (isClose) { - path.push(['Z']); - } - return path; -}; - // Get the latest overall data based on the individual data changes. const getNewData = (newChangeData, data, encode) => { return data.map((d) => { - if (encode.x && d[encode.x] === newChangeData[encode.x]) { - if (encode.color) { - return d[encode.color] === newChangeData[encode.color] - ? newChangeData - : d; - } else { - return newChangeData; - } - } + const isUpdate = ['x', 'color'].reduce((v, key) => { + const field = encode[key]; + if (!field) return v; + + if (d[field] !== newChangeData[field]) return false; - return d; + return v; + }, true); + + return isUpdate ? { ...d, ...newChangeData } : d; }); }; -// Find origin element data. -const getElementDataRatioTransformFn = (element) => { - const v = get(element, ['__data__', 'items', '0', 'value']); +// Find mark interval origin element data. +const getIntervalDataRatioTransformFn = (element) => { + const y = get(element, ['__data__', 'y']); + const y1 = get(element, ['__data__', 'y1']); + const v = y1 - y; + const { __data__: { data, encode, transform }, childNodes, @@ -115,8 +105,32 @@ const getElementDataRatioTransformFn = (element) => { const yField = get(encode, ['y', 'field']); const value = data[childNodes.indexOf(element)][yField]; + return (newValue, isTheta = false) => { + if (isNormalizeY || isTheta) { + return (newValue / (1 - newValue) / (v / (1 - v))) * value; + } + + return newValue; + }; +}; + +// Find origin path data. +const getPathDataRatioTransformFn = (element, index) => { + const v = get(element, ['__data__', 'seriesItems', index, '0', 'value']); + const i = get(element, ['__data__', 'seriesIndex', index]); + + const { + __data__: { data, encode, transform }, + } = element.parentNode; + const isNormalizeY = find(transform, ({ type }) => type === 'normalizeY'); + const yField = get(encode, ['y', 'field']); + const value = data[i][yField]; + return (newValue) => { if (isNormalizeY) { + if (v === 1) { + return newValue; + } return (newValue / (1 - newValue) / (v / (1 - v))) * value; } @@ -164,6 +178,16 @@ const getColorType = (scaleColor, color) => { return scaleColor.sortedDomain[i]; }; +// Get the same direction new point. +const getSamePointPosition = (center, point, target) => { + const oldR = getPointsR(center, point); + const newR = getPointsR(center, target); + const ratio = newR / oldR; + const newX = center[0] + (point[0] - center[0]) * ratio; + const newY = center[1] + (point[1] - center[1]) * ratio; + return [newX, newY]; +}; + /** * ElementPointMove interaction. */ @@ -205,12 +229,19 @@ export function ElementPointMove( options: { marks, coordinate: coordinateOptions }, } = context; const plotArea = selectPlotArea(container); - const elements = getElements(plotArea); + let elements = getElements(plotArea); let newState; let newSelected = selected; - const { transform = [] } = coordinateOptions; + const { transform = [], type: coordinateType } = coordinateOptions; const isTranspose = !!find(transform, ({ type }) => type === 'transpose'); + const isPolar = coordinateType === 'polar'; + const isTheta = coordinateType === 'theta'; + const isArea = !!find(elements, ({ markType }) => markType === 'area'); + + if (isArea) { + elements = elements.filter(({ markType }) => markType === 'area'); + } // Create points const pointsGroup = new Group({ @@ -233,19 +264,22 @@ export function ElementPointMove( const createPoints = (element) => { const { attributes, markType, __data__: data } = element; const { stroke: fill } = attributes; - const { points, seriesTitle, color, title } = data; - + const { points, seriesTitle, color, title, seriesX } = data; // Transpose Currently only do mark interval; if (isTranspose && markType !== 'interval') return; + const { scale, coordinate } = newState?.view || view; + const { color: scaleColor, y: scaleY } = scale; + const center = coordinate.getCenter(); + pointsGroup.removeChildren(); - let downPointHeight = 0; + let downPoint; - const updateView = async (x, y, color, markType) => { + const updateView = async (x, y, color, markTypes) => { setState('elementPointMove', (viewOptions) => { // Update marks. const newMarks = (newState?.options?.marks || marks).map((mark) => { - if (mark.type !== markType) return mark; + if (!markTypes.includes(mark.type)) return mark; const { data, encode } = mark; const encodeKeys = Object.keys(encode); @@ -263,7 +297,6 @@ export function ElementPointMove( } return value; }, {} as any); - // Get change new all data. const newData = getNewData(newChangeData, data, encode); dataChange(newChangeData, newData); @@ -281,8 +314,12 @@ export function ElementPointMove( return await update('elementPointMove'); }; - if (markType === 'line') { + if (['line', 'area'].includes(markType)) { points.forEach((p, index) => { + const title = seriesTitle[index]; + // Area points have bottom point. + if (!title) return; + const circle = new Circle({ name: MOVE_POINT_NAME, style: { @@ -293,9 +330,11 @@ export function ElementPointMove( }, }); + const ratioTransform = getPathDataRatioTransformFn(element, index); + circle.addEventListener('mousedown', (e) => { - const { scale, coordinate } = newState?.view || view; - const { color: scaleColor, y: scaleY } = scale; + const oldPoint = coordinate.output([seriesX[index], 0]); + const pathLength = seriesTitle?.length; container.attr('cursor', 'move'); @@ -316,19 +355,72 @@ export function ElementPointMove( // Point move change text const pointMousemove = (e) => { - const newCy = p[1] + e.clientY - downPointHeight; - const [, y] = coordinate.invert([p[0], newCy]); - const newPath = getPointsPath([ - points[index - 1], - [p[0], newCy], - points[index + 1], - ]); - labelShape.attr('text', scaleY.invert(y).toFixed(precision)); - pathShape.attr('path', newPath); - circle.attr('cy', newCy); + const newCy = p[1] + e.clientY - downPoint[1]; + // Area/Radar chart. + if (isArea) { + // Radar chart. + if (isPolar) { + const newCx = p[0] + e.clientX - downPoint[0]; + + const [newX, newY] = getSamePointPosition(center, oldPoint, [ + newCx, + newCy, + ]); + + const [, initY] = coordinate.output([1, scaleY.output(0)]); + const [, y] = coordinate.invert([ + newX, + initY - (points[index + pathLength][1] - newY), + ]); + + const nextIndex = (index + 1) % pathLength; + const lastIndex = (index - 1 + pathLength) % pathLength; + const newPath = getPointsPath([ + points[lastIndex], + [newX, newY], + seriesTitle[nextIndex] && points[nextIndex], + ]); + labelShape.attr( + 'text', + ratioTransform(scaleY.invert(y)).toFixed(precision), + ); + pathShape.attr('path', newPath); + circle.attr('cx', newX); + circle.attr('cy', newY); + } else { + // Area chart. + const [, initY] = coordinate.output([1, scaleY.output(0)]); + const [, y] = coordinate.invert([ + p[0], + initY - (points[index + pathLength][1] - newCy), + ]); + const newPath = getPointsPath([ + points[index - 1], + [p[0], newCy], + seriesTitle[index + 1] && points[index + 1], + ]); + labelShape.attr( + 'text', + ratioTransform(scaleY.invert(y)).toFixed(precision), + ); + pathShape.attr('path', newPath); + circle.attr('cy', newCy); + } + } else { + // Line chart. + const [, y] = coordinate.invert([p[0], newCy]); + const newPath = getPointsPath([ + points[index - 1], + [p[0], newCy], + points[index + 1], + ]); + labelShape.attr('text', scaleY.invert(y).toFixed(precision)); + pathShape.attr('path', newPath); + circle.attr('cy', newCy); + } }; - downPointHeight = e.clientY; + downPoint = [e.clientX, e.clientY]; window.addEventListener('mousemove', pointMousemove); const mouseupFn = async () => { @@ -338,11 +430,12 @@ export function ElementPointMove( if (isUndefined(labelShape.attr('text'))) return; - const x = seriesTitle[index]; const y = Number(labelShape.attr('text')); const colorType = getColorType(scaleColor, color); - - newState = await updateView(x, y, colorType, 'line'); + newState = await updateView(title, y, colorType, [ + 'line', + 'area', + ]); labelShape.remove(); pathShape.remove(); @@ -361,10 +454,17 @@ export function ElementPointMove( pointDefaultStyle, ); } else if (markType === 'interval') { - const circlePoint = isTranspose - ? [points[0][0], (points[0][1] + points[1][1]) / 2] - : [(points[0][0] + points[1][0]) / 2, points[0][1]]; - const ratioTransform = getElementDataRatioTransformFn(element); + // Column chart point. + let circlePoint = [(points[0][0] + points[1][0]) / 2, points[0][1]]; + // Bar chart point. + if (isTranspose) { + circlePoint = [points[0][0], (points[0][1] + points[1][1]) / 2]; + } else if (isTheta) { + // Pie chart point. + circlePoint = points[0]; + } + + const ratioTransform = getIntervalDataRatioTransformFn(element); const circle = new Circle({ name: MOVE_POINT_NAME, @@ -378,8 +478,6 @@ export function ElementPointMove( }); circle.addEventListener('mousedown', (e) => { - const { scale, coordinate } = newState?.view || view; - const { color: scaleColor, y: scaleY } = scale; container.attr('cursor', 'move'); const colorType = getColorType(scaleColor, color); @@ -394,7 +492,8 @@ export function ElementPointMove( // Point move change text const pointMousemove = (e) => { if (isTranspose) { - const newCx = circlePoint[0] + e.clientX - downPointHeight; + // Bar chart. + const newCx = circlePoint[0] + e.clientX - downPoint[0]; const [initX] = coordinate.output([ scaleY.output(0), scaleY.output(0), @@ -420,8 +519,42 @@ export function ElementPointMove( ); pathShape.attr('path', newPath); circle.attr('cx', newCx); + } else if (isTheta) { + // Pie chart. + const newCy = circlePoint[1] + e.clientY - downPoint[1]; + const newCx = circlePoint[0] + e.clientX - downPoint[0]; + + const [newXOut, newYOut] = getSamePointPosition( + center, + [newCx, newCy], + circlePoint, + ); + const [newXIn, newYIn] = getSamePointPosition( + center, + [newCx, newCy], + points[1], + ); + const lastPercent = coordinate.invert([newXOut, newYOut])[1]; + const nextPercent = coordinate.invert(points[3])[1]; + const percent = nextPercent - lastPercent; + + if (percent < 0) return; + const newPath = getThetaPath( + center, + [[newXOut, newYOut], [newXIn, newYIn], points[2], points[3]], + percent > 0.5 ? 1 : 0, + ); + + labelShape.attr( + 'text', + ratioTransform(percent, true).toFixed(precision), + ); + pathShape.attr('path', newPath); + circle.attr('cx', newXOut); + circle.attr('cy', newYOut); } else { - const newCy = circlePoint[1] + e.clientY - downPointHeight; + // Column chart. + const newCy = circlePoint[1] + e.clientY - downPoint[1]; const [, initY] = coordinate.output([1, scaleY.output(0)]); const [, y] = coordinate.invert([ @@ -447,7 +580,7 @@ export function ElementPointMove( } }; - downPointHeight = isTranspose ? e.clientX : e.clientY; + downPoint = [e.clientX, e.clientY]; window.addEventListener('mousemove', pointMousemove); // Change mosueup change data and update 、clear shape. @@ -460,7 +593,7 @@ export function ElementPointMove( const y = Number(labelShape.attr('text')); - newState = await updateView(title, y, colorType, 'interval'); + newState = await updateView(title, y, colorType, [markType]); labelShape.remove(); pathShape.remove(); diff --git a/src/interaction/treemapDrillDown.ts b/src/interaction/treemapDrillDown.ts index 7812183a99..57a5fc630c 100644 --- a/src/interaction/treemapDrillDown.ts +++ b/src/interaction/treemapDrillDown.ts @@ -7,11 +7,7 @@ import { PLOT_CLASS_NAME } from '../runtime'; import { select } from '../utils/selection'; import { treeDataTransform } from '../utils/treeDataTransform'; import { legendClearSetState } from './legendFilter'; - -// Get element. -const getElements = (plot) => { - return plot.querySelectorAll('.element'); -}; +import { getElements } from './utils'; function selectPlotArea(root: DisplayObject): DisplayObject { return select(root).select(`.${PLOT_CLASS_NAME}`).node(); diff --git a/src/interaction/utils.ts b/src/interaction/utils.ts index 189d4c13e8..dd3428fcd1 100644 --- a/src/interaction/utils.ts +++ b/src/interaction/utils.ts @@ -2,6 +2,8 @@ import { DisplayObject, Path } from '@antv/g'; import { path as d3Path } from 'd3-path'; import { sort } from 'd3-array'; import { Vector2 } from '@antv/coord'; +import { filter } from '@antv/util'; +import type { PathArray } from '@antv/util'; import { G2Element, select } from '../utils/selection'; import { mapObject } from '../utils/array'; import { @@ -468,3 +470,53 @@ export function selectElementByData(elements, data, datum) { Object.entries(data).every(([key, value]) => datum(d)[key] === value), ); } + +export function getPointsR(point: number[], nextPoint: number[]) { + return Math.sqrt( + Math.pow(point[0] - nextPoint[0], 2) + Math.pow(point[1] - nextPoint[1], 2), + ); +} + +// Points create path. +export function getPointsPath(points: number[][], isClose = false) { + const path = filter(points, (d) => !!d).map((d, i) => { + return [i === 0 ? 'M' : 'L', ...d]; + }) as PathArray; + + if (isClose) { + path.push(['Z']); + } + return path; +} + +// Get element. +export function getElements(plot) { + return plot.querySelectorAll('.element'); +} + +// Get Theta coordinate round path. +export function getThetaPath( + center: number[], + points: number[][], + isBig = 0, +): PathArray { + const path = [['M', ...points[1]]]; + const innerRadius = getPointsR(center, points[1]); + const outerRadius = getPointsR(center, points[0]); + + if (innerRadius === 0) { + path.push( + ['L', ...points[3]], + ['A', outerRadius, outerRadius, 0, isBig, 1, ...points[0]], + ['Z'], + ); + } else { + path.push( + ['A', innerRadius, innerRadius, 0, isBig, 0, ...points[2]], + ['L', ...points[3]], + ['A', outerRadius, outerRadius, 0, isBig, 1, ...points[0]], + ['Z'], + ); + } + return path as PathArray; +} From 8c0d18aca1a2a511b73007f13bd65f9d1e3e70da Mon Sep 17 00:00:00 2001 From: wb-xcf804241 Date: Mon, 11 Mar 2024 11:29:44 +0800 Subject: [PATCH 3/5] feat(interaction): add elementpointmove interaction --- ...lare-element-point-move-area-normalizeY.ts | 2 +- .../static/flare-element-point-move-area.ts | 2 +- ...oint-move-interval-normalizeY-transpose.ts | 2 +- ...-element-point-move-interval-normalizeY.ts | 2 +- ...e-element-point-move-interval-transpose.ts | 2 +- .../flare-element-point-move-interval.ts | 2 +- .../static/flare-element-point-move-line.ts | 2 +- .../static/flare-element-point-move-pie.ts | 2 +- .../static/flare-element-point-move-radar.ts | 2 +- .../data/demo/area-element-point-move.ts | 2 +- .../area-normalizeY-element-point-move.ts | 4 +- .../data/demo/bar-element-point-move.ts | 7 -- .../demo/bar-normalizeY-element-point-move.ts | 7 -- .../data/demo/column-element-point-move.ts | 8 +- .../column-normalizeY-element-point-move.ts | 7 -- .../demo/line-element-point-move-polar.ts | 10 +-- .../data/demo/line-element-point-move.ts | 32 ++++++-- .../data/demo/pie-element-point-move.ts | 1 - src/interaction/elementPointMove.ts | 80 ++++++++++++++----- 19 files changed, 96 insertions(+), 80 deletions(-) diff --git a/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts b/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts index 4d956f14a9..35aad2f185 100644 --- a/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts +++ b/__tests__/plots/static/flare-element-point-move-area-normalizeY.ts @@ -38,7 +38,7 @@ export function flareElementPointMoveAreaNormalizeY(): G2Spec { transform: [{ type: 'stackY' }, { type: 'normalizeY' }], interaction: { legendFilter: false, - elementPointMove: { selected: [1, 4] }, + elementPointMove: { selection: [1, 4] }, }, }; } diff --git a/__tests__/plots/static/flare-element-point-move-area.ts b/__tests__/plots/static/flare-element-point-move-area.ts index cbbc75efa3..85dfee6701 100644 --- a/__tests__/plots/static/flare-element-point-move-area.ts +++ b/__tests__/plots/static/flare-element-point-move-area.ts @@ -28,7 +28,7 @@ export function flareElementPointMoveArea(): G2Spec { encode: { x: 'year', y: 'value', key: 'type', color: 'type' }, interaction: { legendFilter: false, - elementPointMove: { selected: [1, 4] }, + elementPointMove: { selection: [1, 4] }, }, }; } diff --git a/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts b/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts index 65f8a9b2be..efc7e8934c 100644 --- a/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts +++ b/__tests__/plots/static/flare-element-point-move-interval-normalizeY-transpose.ts @@ -37,7 +37,7 @@ export function flareElementPointMoveIntervalNormalizeYTranspose(): G2Spec { ], interaction: { elementPointMove: { - selected: [6], + selection: [6], }, }, }; diff --git a/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts b/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts index 5bb7c4687d..3a7cf40eb0 100644 --- a/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts +++ b/__tests__/plots/static/flare-element-point-move-interval-normalizeY.ts @@ -36,7 +36,7 @@ export function flareElementPointMoveIntervalNormalizeY(): G2Spec { ], interaction: { elementPointMove: { - selected: [6], + selection: [6], }, }, }; diff --git a/__tests__/plots/static/flare-element-point-move-interval-transpose.ts b/__tests__/plots/static/flare-element-point-move-interval-transpose.ts index a7f03fbaf6..d34903e269 100644 --- a/__tests__/plots/static/flare-element-point-move-interval-transpose.ts +++ b/__tests__/plots/static/flare-element-point-move-interval-transpose.ts @@ -33,7 +33,7 @@ export function flareElementPointMoveIntervalTranspose(): G2Spec { transform: [{ type: 'stackY' }], interaction: { elementPointMove: { - selected: [6], + selection: [6], }, }, }; diff --git a/__tests__/plots/static/flare-element-point-move-interval.ts b/__tests__/plots/static/flare-element-point-move-interval.ts index d43bda5697..7d3812fd5f 100644 --- a/__tests__/plots/static/flare-element-point-move-interval.ts +++ b/__tests__/plots/static/flare-element-point-move-interval.ts @@ -32,7 +32,7 @@ export function flareElementPointMoveInterval(): G2Spec { transform: [{ type: 'stackY' }], interaction: { elementPointMove: { - selected: [6], + selection: [6], }, }, }; diff --git a/__tests__/plots/static/flare-element-point-move-line.ts b/__tests__/plots/static/flare-element-point-move-line.ts index 757ba1036e..d9283336f2 100644 --- a/__tests__/plots/static/flare-element-point-move-line.ts +++ b/__tests__/plots/static/flare-element-point-move-line.ts @@ -34,7 +34,7 @@ export function flareElementPointMoveLine(): G2Spec { interaction: { elementPointMove: { precision: 4, - selected: [1, 4], + selection: [1, 4], }, }, }; diff --git a/__tests__/plots/static/flare-element-point-move-pie.ts b/__tests__/plots/static/flare-element-point-move-pie.ts index ea7acd7d42..8a032c9436 100644 --- a/__tests__/plots/static/flare-element-point-move-pie.ts +++ b/__tests__/plots/static/flare-element-point-move-pie.ts @@ -26,7 +26,7 @@ export function flareElementPointMovePie(): G2Spec { interaction: { legendFilter: false, elementPointMove: { - selected: [2], + selection: [2], lineDashPathStyle: { lineDash: [2, 4], stroke: '#fff', lineWidth: 2 }, }, }, diff --git a/__tests__/plots/static/flare-element-point-move-radar.ts b/__tests__/plots/static/flare-element-point-move-radar.ts index 3be9784d8a..2330a514c9 100644 --- a/__tests__/plots/static/flare-element-point-move-radar.ts +++ b/__tests__/plots/static/flare-element-point-move-radar.ts @@ -57,7 +57,7 @@ export function flareElementPointMoveRadar(): G2Spec { interaction: { elementPointMove: { precision: 4, - selected: [1, 4], + selection: [1, 4], }, }, }; diff --git a/site/examples/interaction/data/demo/area-element-point-move.ts b/site/examples/interaction/data/demo/area-element-point-move.ts index 6aeae9cc9e..361ef47b1c 100644 --- a/site/examples/interaction/data/demo/area-element-point-move.ts +++ b/site/examples/interaction/data/demo/area-element-point-move.ts @@ -30,7 +30,7 @@ chart .interaction({ legendFilter: false, elementPointMove: { - selected: [1, 4], + selection: [1, 4], }, }) .encode('x', 'year') diff --git a/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts b/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts index c3d49ef4d8..b1bb0e2a64 100644 --- a/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts +++ b/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts @@ -38,9 +38,7 @@ chart ]) .interaction({ legendFilter: false, - elementPointMove: { - selected: [1, 4], - }, + elementPointMove: true, }) .transform({ type: 'stackY' }) .transform({ type: 'normalizeY' }) diff --git a/site/examples/interaction/data/demo/bar-element-point-move.ts b/site/examples/interaction/data/demo/bar-element-point-move.ts index 5bb376714c..933efb8325 100644 --- a/site/examples/interaction/data/demo/bar-element-point-move.ts +++ b/site/examples/interaction/data/demo/bar-element-point-move.ts @@ -35,13 +35,6 @@ chart legendFilter: false, elementPointMove: { precision: 3, - selected: [5], - selectedChange: (newSelected) => { - console.log(newSelected); - }, - dataChange: (newChangeData, newData) => { - console.log(newChangeData, newData); - }, }, }) .transform({ type: 'stackY' }) diff --git a/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts b/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts index 0c39d9a8ae..d35d717cbb 100644 --- a/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts +++ b/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts @@ -38,13 +38,6 @@ chart legendFilter: false, elementPointMove: { precision: 3, - selected: [5], - selectedChange: (newSelected) => { - console.log(newSelected); - }, - dataChange: (newChangeData, newData) => { - console.log(newChangeData, newData); - }, }, }) .coordinate({ transform: [{ type: 'transpose' }] }); diff --git a/site/examples/interaction/data/demo/column-element-point-move.ts b/site/examples/interaction/data/demo/column-element-point-move.ts index 0cad220b72..855e6aa9e8 100644 --- a/site/examples/interaction/data/demo/column-element-point-move.ts +++ b/site/examples/interaction/data/demo/column-element-point-move.ts @@ -35,13 +35,7 @@ chart legendFilter: false, elementPointMove: { precision: 3, - selected: [5], - selectedChange: (newSelected) => { - console.log(newSelected); - }, - dataChange: (newChangeData, newData) => { - console.log(newChangeData, newData); - }, + selection: [5], }, }) .transform({ type: 'stackY' }); diff --git a/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts b/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts index b63f018912..e90b39209e 100644 --- a/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts +++ b/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts @@ -38,13 +38,6 @@ chart legendFilter: false, elementPointMove: { precision: 3, - selected: [5], - selectedChange: (newSelected) => { - console.log(newSelected); - }, - dataChange: (newChangeData, newData) => { - console.log(newChangeData, newData); - }, }, }); diff --git a/site/examples/interaction/data/demo/line-element-point-move-polar.ts b/site/examples/interaction/data/demo/line-element-point-move-polar.ts index 1d85ae21e7..521bd0a72e 100644 --- a/site/examples/interaction/data/demo/line-element-point-move-polar.ts +++ b/site/examples/interaction/data/demo/line-element-point-move-polar.ts @@ -36,15 +36,7 @@ chart .scale('y', { tickCount: 5, domainMax: 80 }) .interaction({ legendFilter: false, - elementPointMove: { - selected: [1, 3], - selectedChange: (newSelected) => { - console.log(newSelected); - }, - dataChange: (newChangeData, newData) => { - console.log(newChangeData, newData); - }, - }, + elementPointMove: true, }) .axis('x', { grid: true, diff --git a/site/examples/interaction/data/demo/line-element-point-move.ts b/site/examples/interaction/data/demo/line-element-point-move.ts index 6c6bd49fda..fa4dd13a04 100644 --- a/site/examples/interaction/data/demo/line-element-point-move.ts +++ b/site/examples/interaction/data/demo/line-element-point-move.ts @@ -30,7 +30,6 @@ chart .interaction({ legendFilter: false, elementPointMove: { - selected: [1, 4], pointStyle: { r: 8, strokeWidth: 2, @@ -44,12 +43,6 @@ chart fontSize: 14, y: 24, }, - selectedChange: (newSelected) => { - console.log(newSelected); - }, - dataChange: (newChangeData, newData) => { - console.log(newChangeData, newData); - }, }, }) .encode('x', 'year') @@ -57,4 +50,27 @@ chart .encode('key', 'type') .encode('color', 'type'); -chart.render(); +chart.render().then(() => { + chart.on('element:select', (v) => { + const { + data: { selection }, + } = v; + console.log(selection, 'selection'); + }); + + chart.on('point:moveend', (v) => { + const { + data: { changeData, data }, + } = v; + console.log(changeData, 'changeData'); + console.log(data, 'data'); + }); +}); + +chart.on('afterrender', () => { + chart.emit('element:select', { + data: { + selection: [1, 2], + }, + }); +}); diff --git a/site/examples/interaction/data/demo/pie-element-point-move.ts b/site/examples/interaction/data/demo/pie-element-point-move.ts index d5b20a771b..22b512d0d0 100644 --- a/site/examples/interaction/data/demo/pie-element-point-move.ts +++ b/site/examples/interaction/data/demo/pie-element-point-move.ts @@ -22,7 +22,6 @@ chart .interaction({ legendFilter: false, elementPointMove: { - selected: [1], lineDashPathStyle: { lineDash: [2, 4], stroke: '#fff', diff --git a/src/interaction/elementPointMove.ts b/src/interaction/elementPointMove.ts index a15e63ad9f..d44b6756c2 100644 --- a/src/interaction/elementPointMove.ts +++ b/src/interaction/elementPointMove.ts @@ -1,5 +1,5 @@ import { Text, Group, Circle, Path } from '@antv/g'; -import { deepMix, isUndefined, find, get } from '@antv/util'; +import { deepMix, isUndefined, find, get, isNumber } from '@antv/util'; import type { CircleStyleProps, TextStyleProps, PathStyleProps } from '@antv/g'; import { @@ -11,9 +11,7 @@ import { } from './utils'; export type ElementPointMoveOptions = { - selected?: number[]; - selectedChange?: (selected) => void; - dataChange?: (newChangeData, newData) => void; + selection?: number[]; labelStyle?: TextStyleProps; lineDashPathStyle?: PathStyleProps; pointStyle?: CircleStyleProps; @@ -139,11 +137,11 @@ const getPathDataRatioTransformFn = (element, index) => { }; // Point shape select change style. -const selectedPointsStyle = (pointsShape, selected, defaultStyle) => { +const selectedPointsStyle = (pointsShape, selection, defaultStyle) => { pointsShape.forEach((shape, index) => { shape.attr( 'stroke', - selected[1] === index + selection[1] === index ? defaultStyle['activeStroke'] : defaultStyle['stroke'], ); @@ -195,12 +193,10 @@ export function ElementPointMove( elementPointMoveOptions: ElementPointMoveOptions = {}, ) { const { + selection = [], pointStyle = {}, lineDashPathStyle = {}, labelStyle = {}, - selected = [0], - selectedChange = () => {}, - dataChange = () => {}, precision = 2, } = elementPointMoveOptions; @@ -220,7 +216,7 @@ export function ElementPointMove( ...pointStyle, }; - return (context) => { + return (context, _, emitter) => { const { update, setState, @@ -231,7 +227,7 @@ export function ElementPointMove( const plotArea = selectPlotArea(container); let elements = getElements(plotArea); let newState; - let newSelected = selected; + let newSelection = selection; const { transform = [], type: coordinateType } = coordinateOptions; const isTranspose = !!find(transform, ({ type }) => type === 'transpose'); @@ -252,14 +248,46 @@ export function ElementPointMove( }); plotArea.appendChild(pointsGroup); + const selectedChange = () => { + emitter.emit('element:select', { + nativeEvent: true, + data: { + selection: newSelection, + }, + }); + }; + + const dataChange = (changeData, data) => { + emitter.emit('point:moveend', { + nativeEvent: true, + data: { + changeData, + data, + }, + }); + }; + // Element click change style. const elementClick = (e) => { const element = e.target; - newSelected = [element.parentNode.childNodes.indexOf(element)]; - selectedChange(newSelected); + newSelection = [element.parentNode.childNodes.indexOf(element)]; + selectedChange(); createPoints(element); }; + const elementSelect = (d) => { + const { + data: { selection }, + nativeEvent, + } = d; + if (nativeEvent) return; + newSelection = selection; + const element = get(elements, [newSelection?.[0]]); + if (element) { + createPoints(element); + } + }; + // Create select element points. const createPoints = (element) => { const { attributes, markType, __data__: data } = element; @@ -338,13 +366,15 @@ export function ElementPointMove( container.attr('cursor', 'move'); - newSelected[1] = index; + if (newSelection[1] !== index) { + newSelection[1] = index; + selectedChange(); + } selectedPointsStyle( pointsGroup.childNodes, - newSelected, + newSelection, pointDefaultStyle, ); - selectedChange(newSelected); const [pathShape, labelShape] = createHelpShape( pointsGroup, @@ -450,7 +480,7 @@ export function ElementPointMove( selectedPointsStyle( pointsGroup.childNodes, - newSelected, + newSelection, pointDefaultStyle, ); } else if (markType === 'interval') { @@ -609,7 +639,7 @@ export function ElementPointMove( // Add EventListener. elements.forEach((element, index) => { - if (index === newSelected[0]) { + if (newSelection[0] === index) { createPoints(element); } element.addEventListener('click', elementClick); @@ -618,18 +648,26 @@ export function ElementPointMove( }); const rootClick = (e) => { - const element = e.target; - if (element.name !== MOVE_POINT_NAME && !elements.includes(element)) { - newSelected[1] = null; + const element = e?.target; + if ( + !element || + (element.name !== MOVE_POINT_NAME && !elements.includes(element)) + ) { + newSelection = []; + selectedChange(); pointsGroup.removeChildren(); } }; + emitter.on('element:select', elementSelect); + emitter.on('element:unselect', rootClick); container.addEventListener('mousedown', rootClick); // Remove EventListener. return () => { pointsGroup.remove(); + emitter.off('element:select', elementSelect); + emitter.off('element:unselect', rootClick); container.removeEventListener('mousedown', rootClick); elements.forEach((element) => { element.removeEventListener('click', elementClick); From 8aed000c688c37ffd089e165bdc1dac0168e28d3 Mon Sep 17 00:00:00 2001 From: wb-xcf804241 Date: Thu, 14 Mar 2024 16:14:27 +0800 Subject: [PATCH 4/5] feat(interaction): add elementpointmove interaction --- .../static/flare-element-point-move-pie.ts | 2 +- .../data/demo/line-element-point-move.ts | 28 ++++--- .../data/demo/pie-element-point-move.ts | 8 +- src/interaction/elementPointMove.ts | 78 +++++++------------ 4 files changed, 48 insertions(+), 68 deletions(-) diff --git a/__tests__/plots/static/flare-element-point-move-pie.ts b/__tests__/plots/static/flare-element-point-move-pie.ts index 8a032c9436..8d4ec24bef 100644 --- a/__tests__/plots/static/flare-element-point-move-pie.ts +++ b/__tests__/plots/static/flare-element-point-move-pie.ts @@ -27,7 +27,7 @@ export function flareElementPointMovePie(): G2Spec { legendFilter: false, elementPointMove: { selection: [2], - lineDashPathStyle: { lineDash: [2, 4], stroke: '#fff', lineWidth: 2 }, + style: { pathLineDash: [2, 4], pathStroke: '#fff', pathLineWidth: 2 }, }, }, }; diff --git a/site/examples/interaction/data/demo/line-element-point-move.ts b/site/examples/interaction/data/demo/line-element-point-move.ts index fa4dd13a04..1d87665f96 100644 --- a/site/examples/interaction/data/demo/line-element-point-move.ts +++ b/site/examples/interaction/data/demo/line-element-point-move.ts @@ -30,18 +30,14 @@ chart .interaction({ legendFilter: false, elementPointMove: { - pointStyle: { - r: 8, - strokeWidth: 2, - activeStroke: '#fff', - }, - lineDashPathStyle: { - lineDash: [2, 4], - stroke: 'red', - }, - labelStyle: { - fontSize: 14, - y: 24, + style: { + pointR: 8, + pointStrokeWidth: 2, + pointActiveStroke: '#fff', + pathLineDash: [2, 4], + pathStroke: 'red', + labelFontSize: 14, + labelY: 24, }, }, }) @@ -51,14 +47,14 @@ chart .encode('color', 'type'); chart.render().then(() => { - chart.on('element:select', (v) => { + chart.on('element-point:select', (v) => { const { data: { selection }, } = v; console.log(selection, 'selection'); }); - chart.on('point:moveend', (v) => { + chart.on('element-point:moved', (v) => { const { data: { changeData, data }, } = v; @@ -68,9 +64,11 @@ chart.render().then(() => { }); chart.on('afterrender', () => { - chart.emit('element:select', { + chart.emit('element-point:select', { data: { selection: [1, 2], }, }); + // Clear select. + // chart.emit('element-point:unselect'); }); diff --git a/site/examples/interaction/data/demo/pie-element-point-move.ts b/site/examples/interaction/data/demo/pie-element-point-move.ts index 22b512d0d0..8b12e8eacd 100644 --- a/site/examples/interaction/data/demo/pie-element-point-move.ts +++ b/site/examples/interaction/data/demo/pie-element-point-move.ts @@ -22,10 +22,10 @@ chart .interaction({ legendFilter: false, elementPointMove: { - lineDashPathStyle: { - lineDash: [2, 4], - stroke: '#fff', - lineWidth: 2, + style: { + pathLineDash: [2, 4], + pathStroke: '#fff', + pathLineWidth: 2, }, }, }) diff --git a/src/interaction/elementPointMove.ts b/src/interaction/elementPointMove.ts index d44b6756c2..e8807a5328 100644 --- a/src/interaction/elementPointMove.ts +++ b/src/interaction/elementPointMove.ts @@ -1,7 +1,8 @@ import { Text, Group, Circle, Path } from '@antv/g'; -import { deepMix, isUndefined, find, get, isNumber } from '@antv/util'; - +import { deepMix, isUndefined, find, get } from '@antv/util'; import type { CircleStyleProps, TextStyleProps, PathStyleProps } from '@antv/g'; +import { subObject } from '../utils/helper'; + import { selectPlotArea, getPointsR, @@ -20,24 +21,18 @@ export type ElementPointMoveOptions = { }; const DEFAULT_STYLE = { - pointStyle: { - r: 6, - strokeWidth: 1, - stroke: '#888', - activeStroke: '#f5f5f5', - } as CircleStyleProps, - lineDashPathStyle: { - stroke: '#888', - lineDash: [3, 4], - }, - labelStyle: { - fontSize: 12, - fill: '#888', - stroke: '#fff', - lineWidth: 1, - y: -6, - x: 2, - } as TextStyleProps, + pointR: 6, + pointStrokeWidth: 1, + pointStroke: '#888', + pointActiveStroke: '#f5f5f5', + pathStroke: '#888', + pathLineDash: [3, 4], + labelFontSize: 12, + labelFill: '#888', + labelStroke: '#fff', + labelLineWidth: 1, + labelY: -6, + labelX: 2, }; // point shape name. @@ -192,29 +187,17 @@ const getSamePointPosition = (center, point, target) => { export function ElementPointMove( elementPointMoveOptions: ElementPointMoveOptions = {}, ) { - const { - selection = [], - pointStyle = {}, - lineDashPathStyle = {}, - labelStyle = {}, - precision = 2, - } = elementPointMoveOptions; - - // Shape default style. - const pathDefaultStyle = { - ...DEFAULT_STYLE.lineDashPathStyle, - ...lineDashPathStyle, - }; + const { selection = [], style = {}, precision = 2 } = elementPointMoveOptions; - const labelDefaultStyle = { - ...DEFAULT_STYLE.labelStyle, - ...labelStyle, - }; + const defaultStyle = { ...DEFAULT_STYLE, ...style }; - const pointDefaultStyle = { - ...DEFAULT_STYLE.pointStyle, - ...pointStyle, - }; + // Shape default style. + const pathDefaultStyle = subObject(defaultStyle, 'path') as PathStyleProps; + const labelDefaultStyle = subObject(defaultStyle, 'label') as TextStyleProps; + const pointDefaultStyle = subObject( + defaultStyle, + 'point', + ) as CircleStyleProps; return (context, _, emitter) => { const { @@ -249,7 +232,7 @@ export function ElementPointMove( plotArea.appendChild(pointsGroup); const selectedChange = () => { - emitter.emit('element:select', { + emitter.emit('element-point:select', { nativeEvent: true, data: { selection: newSelection, @@ -258,7 +241,7 @@ export function ElementPointMove( }; const dataChange = (changeData, data) => { - emitter.emit('point:moveend', { + emitter.emit('element-point:moved', { nativeEvent: true, data: { changeData, @@ -567,7 +550,6 @@ export function ElementPointMove( const lastPercent = coordinate.invert([newXOut, newYOut])[1]; const nextPercent = coordinate.invert(points[3])[1]; const percent = nextPercent - lastPercent; - if (percent < 0) return; const newPath = getThetaPath( center, @@ -659,15 +641,15 @@ export function ElementPointMove( } }; - emitter.on('element:select', elementSelect); - emitter.on('element:unselect', rootClick); + emitter.on('element-point:select', elementSelect); + emitter.on('element-point:unselect', rootClick); container.addEventListener('mousedown', rootClick); // Remove EventListener. return () => { pointsGroup.remove(); - emitter.off('element:select', elementSelect); - emitter.off('element:unselect', rootClick); + emitter.off('element-point:select', elementSelect); + emitter.off('element-point:unselect', rootClick); container.removeEventListener('mousedown', rootClick); elements.forEach((element) => { element.removeEventListener('click', elementClick); From a6a9f861aca6cfaed23074b9482a88809b316ae8 Mon Sep 17 00:00:00 2001 From: wb-xcf804241 Date: Thu, 14 Mar 2024 17:39:05 +0800 Subject: [PATCH 5/5] feat(interaction): add elementpointmove interaction --- .../plots/static/flare-element-point-move-pie.ts | 4 +++- .../data/demo/line-element-point-move.ts | 16 +++++++--------- .../data/demo/pie-element-point-move.ts | 8 +++----- src/interaction/elementPointMove.ts | 7 ++----- 4 files changed, 15 insertions(+), 20 deletions(-) diff --git a/__tests__/plots/static/flare-element-point-move-pie.ts b/__tests__/plots/static/flare-element-point-move-pie.ts index 8d4ec24bef..12e1826593 100644 --- a/__tests__/plots/static/flare-element-point-move-pie.ts +++ b/__tests__/plots/static/flare-element-point-move-pie.ts @@ -27,7 +27,9 @@ export function flareElementPointMovePie(): G2Spec { legendFilter: false, elementPointMove: { selection: [2], - style: { pathLineDash: [2, 4], pathStroke: '#fff', pathLineWidth: 2 }, + pathLineDash: [2, 4], + pathStroke: '#fff', + pathLineWidth: 2, }, }, }; diff --git a/site/examples/interaction/data/demo/line-element-point-move.ts b/site/examples/interaction/data/demo/line-element-point-move.ts index 1d87665f96..bdd9da9504 100644 --- a/site/examples/interaction/data/demo/line-element-point-move.ts +++ b/site/examples/interaction/data/demo/line-element-point-move.ts @@ -30,15 +30,13 @@ chart .interaction({ legendFilter: false, elementPointMove: { - style: { - pointR: 8, - pointStrokeWidth: 2, - pointActiveStroke: '#fff', - pathLineDash: [2, 4], - pathStroke: 'red', - labelFontSize: 14, - labelY: 24, - }, + pointR: 8, + pointStrokeWidth: 2, + pointActiveStroke: '#fff', + pathLineDash: [2, 4], + pathStroke: 'red', + labelFontSize: 14, + labelY: 24, }, }) .encode('x', 'year') diff --git a/site/examples/interaction/data/demo/pie-element-point-move.ts b/site/examples/interaction/data/demo/pie-element-point-move.ts index 8b12e8eacd..1dcb6cb425 100644 --- a/site/examples/interaction/data/demo/pie-element-point-move.ts +++ b/site/examples/interaction/data/demo/pie-element-point-move.ts @@ -22,11 +22,9 @@ chart .interaction({ legendFilter: false, elementPointMove: { - style: { - pathLineDash: [2, 4], - pathStroke: '#fff', - pathLineWidth: 2, - }, + pathLineDash: [2, 4], + pathStroke: '#fff', + pathLineWidth: 2, }, }) .encode('y', 'count') diff --git a/src/interaction/elementPointMove.ts b/src/interaction/elementPointMove.ts index e8807a5328..8aa76470a5 100644 --- a/src/interaction/elementPointMove.ts +++ b/src/interaction/elementPointMove.ts @@ -13,9 +13,6 @@ import { export type ElementPointMoveOptions = { selection?: number[]; - labelStyle?: TextStyleProps; - lineDashPathStyle?: PathStyleProps; - pointStyle?: CircleStyleProps; precision?: number; [key: string]: any; }; @@ -187,9 +184,9 @@ const getSamePointPosition = (center, point, target) => { export function ElementPointMove( elementPointMoveOptions: ElementPointMoveOptions = {}, ) { - const { selection = [], style = {}, precision = 2 } = elementPointMoveOptions; + const { selection = [], precision = 2, ...style } = elementPointMoveOptions; - const defaultStyle = { ...DEFAULT_STYLE, ...style }; + const defaultStyle = { ...DEFAULT_STYLE, ...(style || {}) }; // Shape default style. const pathDefaultStyle = subObject(defaultStyle, 'path') as PathStyleProps;