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 @@
+
\ 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 @@
+
\ No newline at end of file
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 @@
+
\ 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 @@
+
\ 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 @@
+
\ 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 @@
+
\ 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..b3b2d488c4
--- /dev/null
+++ b/__tests__/integration/snapshots/static/flareElementPointMoveLine.svg
@@ -0,0 +1,1560 @@
+
\ No newline at end of file
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 @@
+
\ 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..35aad2f185
--- /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: { 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
new file mode 100644
index 0000000000..85dfee6701
--- /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: { 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
new file mode 100644
index 0000000000..efc7e8934c
--- /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: {
+ 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
new file mode 100644
index 0000000000..3a7cf40eb0
--- /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: {
+ 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
new file mode 100644
index 0000000000..d34903e269
--- /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: {
+ selection: [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..7d3812fd5f
--- /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: {
+ selection: [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..d9283336f2
--- /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,
+ 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
new file mode 100644
index 0000000000..12e1826593
--- /dev/null
+++ b/__tests__/plots/static/flare-element-point-move-pie.ts
@@ -0,0 +1,36 @@
+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: {
+ selection: [2],
+ pathLineDash: [2, 4],
+ pathStroke: '#fff',
+ pathLineWidth: 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..2330a514c9
--- /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,
+ selection: [1, 4],
+ },
+ },
+ };
+}
diff --git a/__tests__/plots/static/index.ts b/__tests__/plots/static/index.ts
index cb15d80681..956912b23c 100644
--- a/__tests__/plots/static/index.ts
+++ b/__tests__/plots/static/index.ts
@@ -322,3 +322,12 @@ 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';
+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/__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/area-element-point-move.ts b/site/examples/interaction/data/demo/area-element-point-move.ts
new file mode 100644
index 0000000000..361ef47b1c
--- /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: {
+ selection: [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..b1bb0e2a64
--- /dev/null
+++ b/site/examples/interaction/data/demo/area-normalizeY-element-point-move.ts
@@ -0,0 +1,50 @@
+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: true,
+ })
+ .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/bar-element-point-move.ts b/site/examples/interaction/data/demo/bar-element-point-move.ts
new file mode 100644
index 0000000000..933efb8325
--- /dev/null
+++ b/site/examples/interaction/data/demo/bar-element-point-move.ts
@@ -0,0 +1,43 @@
+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,
+ },
+ })
+ .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..d35d717cbb
--- /dev/null
+++ b/site/examples/interaction/data/demo/bar-normalizeY-element-point-move.ts
@@ -0,0 +1,45 @@
+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,
+ },
+ })
+ .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..855e6aa9e8
--- /dev/null
+++ b/site/examples/interaction/data/demo/column-element-point-move.ts
@@ -0,0 +1,43 @@
+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,
+ selection: [5],
+ },
+ })
+ .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..e90b39209e
--- /dev/null
+++ b/site/examples/interaction/data/demo/column-normalizeY-element-point-move.ts
@@ -0,0 +1,44 @@
+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,
+ },
+ });
+
+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..521bd0a72e
--- /dev/null
+++ b/site/examples/interaction/data/demo/line-element-point-move-polar.ts
@@ -0,0 +1,73 @@
+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: true,
+ })
+ .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
new file mode 100644
index 0000000000..bdd9da9504
--- /dev/null
+++ b/site/examples/interaction/data/demo/line-element-point-move.ts
@@ -0,0 +1,72 @@
+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: {
+ pointR: 8,
+ pointStrokeWidth: 2,
+ pointActiveStroke: '#fff',
+ pathLineDash: [2, 4],
+ pathStroke: 'red',
+ labelFontSize: 14,
+ labelY: 24,
+ },
+ })
+ .encode('x', 'year')
+ .encode('y', 'value')
+ .encode('key', 'type')
+ .encode('color', 'type');
+
+chart.render().then(() => {
+ chart.on('element-point:select', (v) => {
+ const {
+ data: { selection },
+ } = v;
+ console.log(selection, 'selection');
+ });
+
+ chart.on('element-point:moved', (v) => {
+ const {
+ data: { changeData, data },
+ } = v;
+ console.log(changeData, 'changeData');
+ console.log(data, 'data');
+ });
+});
+
+chart.on('afterrender', () => {
+ chart.emit('element-point:select', {
+ data: {
+ selection: [1, 2],
+ },
+ });
+ // Clear select.
+ // chart.emit('element-point:unselect');
+});
diff --git a/site/examples/interaction/data/demo/meta.json b/site/examples/interaction/data/demo/meta.json
new file mode 100644
index 0000000000..d2e35b173f
--- /dev/null
+++ b/site/examples/interaction/data/demo/meta.json
@@ -0,0 +1,80 @@
+{
+ "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": "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": {
+ "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"
+ },
+ {
+ "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..1dcb6cb425
--- /dev/null
+++ b/site/examples/interaction/data/demo/pie-element-point-move.ts
@@ -0,0 +1,38 @@
+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: {
+ pathLineDash: [2, 4],
+ pathStroke: '#fff',
+ pathLineWidth: 2,
+ },
+ })
+ .encode('y', 'count')
+ .encode('color', 'item')
+ .encode('key', 'item')
+ .tooltip((data) => ({
+ name: data.item,
+ value: `${data.percent * 100}%`,
+ }));
+
+chart.render();
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..8aa76470a5
--- /dev/null
+++ b/src/interaction/elementPointMove.ts
@@ -0,0 +1,658 @@
+import { Text, Group, Circle, Path } from '@antv/g';
+import { deepMix, isUndefined, find, get } from '@antv/util';
+import type { CircleStyleProps, TextStyleProps, PathStyleProps } from '@antv/g';
+import { subObject } from '../utils/helper';
+
+import {
+ selectPlotArea,
+ getPointsR,
+ getPointsPath,
+ getElements,
+ getThetaPath,
+} from './utils';
+
+export type ElementPointMoveOptions = {
+ selection?: number[];
+ precision?: number;
+ [key: string]: any;
+};
+
+const DEFAULT_STYLE = {
+ 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.
+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'));
+ }
+};
+
+// Get the latest overall data based on the individual data changes.
+const getNewData = (newChangeData, data, encode) => {
+ return data.map((d) => {
+ const isUpdate = ['x', 'color'].reduce((v, key) => {
+ const field = encode[key];
+ if (!field) return v;
+
+ if (d[field] !== newChangeData[field]) return false;
+
+ return v;
+ }, true);
+
+ return isUpdate ? { ...d, ...newChangeData } : d;
+ });
+};
+
+// 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,
+ } = element.parentNode;
+ const isNormalizeY = find(transform, ({ type }) => type === 'normalizeY');
+ 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;
+ }
+
+ return newValue;
+ };
+};
+
+// Point shape select change style.
+const selectedPointsStyle = (pointsShape, selection, defaultStyle) => {
+ pointsShape.forEach((shape, index) => {
+ shape.attr(
+ 'stroke',
+ selection[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];
+};
+
+// 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.
+ */
+export function ElementPointMove(
+ elementPointMoveOptions: ElementPointMoveOptions = {},
+) {
+ const { selection = [], precision = 2, ...style } = elementPointMoveOptions;
+
+ const defaultStyle = { ...DEFAULT_STYLE, ...(style || {}) };
+
+ // 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 {
+ update,
+ setState,
+ container,
+ view,
+ options: { marks, coordinate: coordinateOptions },
+ } = context;
+ const plotArea = selectPlotArea(container);
+ let elements = getElements(plotArea);
+ let newState;
+ let newSelection = selection;
+
+ 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({
+ style: {
+ // Tooltip point need down.
+ zIndex: 2,
+ },
+ });
+ plotArea.appendChild(pointsGroup);
+
+ const selectedChange = () => {
+ emitter.emit('element-point:select', {
+ nativeEvent: true,
+ data: {
+ selection: newSelection,
+ },
+ });
+ };
+
+ const dataChange = (changeData, data) => {
+ emitter.emit('element-point:moved', {
+ nativeEvent: true,
+ data: {
+ changeData,
+ data,
+ },
+ });
+ };
+
+ // Element click change style.
+ const elementClick = (e) => {
+ const element = e.target;
+ 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;
+ const { stroke: fill } = attributes;
+ 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 downPoint;
+
+ const updateView = async (x, y, color, markTypes) => {
+ setState('elementPointMove', (viewOptions) => {
+ // Update marks.
+ const newMarks = (newState?.options?.marks || marks).map((mark) => {
+ if (!markTypes.includes(mark.type)) 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 (['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: {
+ cx: p[0],
+ cy: p[1],
+ fill,
+ ...pointDefaultStyle,
+ },
+ });
+
+ const ratioTransform = getPathDataRatioTransformFn(element, index);
+
+ circle.addEventListener('mousedown', (e) => {
+ const oldPoint = coordinate.output([seriesX[index], 0]);
+ const pathLength = seriesTitle?.length;
+
+ container.attr('cursor', 'move');
+
+ if (newSelection[1] !== index) {
+ newSelection[1] = index;
+ selectedChange();
+ }
+ selectedPointsStyle(
+ pointsGroup.childNodes,
+ newSelection,
+ pointDefaultStyle,
+ );
+
+ const [pathShape, labelShape] = createHelpShape(
+ pointsGroup,
+ circle,
+ pathDefaultStyle,
+ labelDefaultStyle,
+ );
+
+ // Point move change text
+ const pointMousemove = (e) => {
+ 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);
+ }
+ };
+
+ downPoint = [e.clientX, 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 y = Number(labelShape.attr('text'));
+ const colorType = getColorType(scaleColor, color);
+ newState = await updateView(title, y, colorType, [
+ 'line',
+ 'area',
+ ]);
+
+ labelShape.remove();
+ pathShape.remove();
+ createPoints(element);
+ };
+
+ container.addEventListener('mouseup', mouseupFn);
+ });
+
+ pointsGroup.appendChild(circle);
+ });
+
+ selectedPointsStyle(
+ pointsGroup.childNodes,
+ newSelection,
+ pointDefaultStyle,
+ );
+ } else if (markType === 'interval') {
+ // 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,
+ style: {
+ cx: circlePoint[0],
+ cy: circlePoint[1],
+ fill,
+ ...pointDefaultStyle,
+ stroke: pointDefaultStyle['activeStroke'],
+ },
+ });
+
+ circle.addEventListener('mousedown', (e) => {
+ 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) {
+ // Bar chart.
+ const newCx = circlePoint[0] + e.clientX - downPoint[0];
+ 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 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 {
+ // Column chart.
+ const newCy = circlePoint[1] + e.clientY - downPoint[1];
+ 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);
+ }
+ };
+
+ downPoint = [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, [markType]);
+
+ labelShape.remove();
+ pathShape.remove();
+ createPoints(element);
+ };
+
+ container.addEventListener('mouseup', mouseupFn);
+ });
+
+ pointsGroup.appendChild(circle);
+ }
+ };
+
+ // Add EventListener.
+ elements.forEach((element, index) => {
+ if (newSelection[0] === index) {
+ createPoints(element);
+ }
+ element.addEventListener('click', elementClick);
+ element.addEventListener('mouseenter', elementMouseenter);
+ element.addEventListener('mouseleave', elementMouseleave);
+ });
+
+ const rootClick = (e) => {
+ const element = e?.target;
+ if (
+ !element ||
+ (element.name !== MOVE_POINT_NAME && !elements.includes(element))
+ ) {
+ newSelection = [];
+ selectedChange();
+ pointsGroup.removeChildren();
+ }
+ };
+
+ emitter.on('element-point:select', elementSelect);
+ emitter.on('element-point:unselect', rootClick);
+ container.addEventListener('mousedown', rootClick);
+
+ // Remove EventListener.
+ return () => {
+ pointsGroup.remove();
+ emitter.off('element-point:select', elementSelect);
+ emitter.off('element-point:unselect', rootClick);
+ 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/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;
+}
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,