Skip to content

Commit a59301f

Browse files
authored
feat(column/bar): migrate connected area interaction (#1852)
1 parent dd11880 commit a59301f

File tree

4 files changed

+279
-2
lines changed

4 files changed

+279
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import { Column, ColumnOptions, Bar, BarOptions } from '@antv/g2plot/src';
2+
import { createDiv } from '@antv/g2plot/__tests__/utils/dom';
3+
4+
const DATA = [
5+
{ year: '2014', type: 'Sales', sales: 1000 },
6+
{ year: '2015', type: 'Sales', sales: 1170 },
7+
{ year: '2016', type: 'Sales', sales: 660 },
8+
{ year: '2017', type: 'Sales', sales: 1030 },
9+
{ year: '2014', type: 'Expenses', sales: 400 },
10+
{ year: '2015', type: 'Expenses', sales: 460 },
11+
{ year: '2016', type: 'Expenses', sales: 1120 },
12+
{ year: '2017', type: 'Expenses', sales: 540 },
13+
{ year: '2014', type: 'Profit', sales: 300 },
14+
{ year: '2015', type: 'Profit', sales: 300 },
15+
{ year: '2016', type: 'Profit', sales: 300 },
16+
{ year: '2017', type: 'Profit', sales: 350 },
17+
];
18+
19+
describe('column connected area', () => {
20+
const options: ColumnOptions = {
21+
data: DATA,
22+
autoFit: false,
23+
width: 600,
24+
height: 400,
25+
xField: 'year',
26+
yField: 'sales',
27+
seriesField: 'type',
28+
isStack: true,
29+
yAxis: {
30+
nice: true,
31+
},
32+
connectedArea: {},
33+
};
34+
const plot = new Column(createDiv(), options);
35+
// @ts-ignore
36+
window.__column__ = plot;
37+
38+
it('render', () => {
39+
plot.render();
40+
const hover = plot.chart.interactions['__interval-connected-area-hover__'];
41+
const click = plot.chart.interactions['__interval-connected-area-click__'];
42+
expect(hover).toBeDefined();
43+
expect(click).toBeUndefined();
44+
// @ts-ignore
45+
expect(hover.cfg.start).toHaveLength(1);
46+
// @ts-ignore
47+
expect(hover.cfg.start[0]).toMatchObject({
48+
trigger: `interval:mouseenter`,
49+
action: ['element-highlight-by-color:highlight', 'element-link-by-color:link'],
50+
});
51+
// @ts-ignore
52+
expect(hover.cfg.end).toHaveLength(1);
53+
// @ts-ignore
54+
expect(hover.cfg.end[0]).toMatchObject({
55+
trigger: 'interval:mouseleave',
56+
action: ['element-highlight-by-color:reset', 'element-link-by-color:unlink'],
57+
});
58+
});
59+
60+
/*
61+
it('update', () => {
62+
plot.update({
63+
...options,
64+
connectedArea: {
65+
trigger: 'click',
66+
},
67+
});
68+
plot.render();
69+
const hover = plot.chart.interactions['__interval-connected-area-hover__'];
70+
const click = plot.chart.interactions['__interval-connected-area-click__'];
71+
expect(hover).toBeUndefined();
72+
expect(click).toBeDefined();
73+
// @ts-ignore
74+
expect(click.cfg.start).toHaveLength(1);
75+
// @ts-ignore
76+
expect(click.cfg.start[0]).toMatchObject({
77+
trigger: `interval:click`,
78+
action: [
79+
'element-highlight-by-color:clear',
80+
'element-highlight-by-color:highlight',
81+
'element-link-by-color:clear',
82+
'element-link-by-color:unlink',
83+
'element-link-by-color:link',
84+
],
85+
});
86+
// @ts-ignore
87+
expect(click.cfg.end).toHaveLength(1);
88+
// @ts-ignore
89+
expect(click.cfg.end[0]).toMatchObject({
90+
trigger: 'document:mousedown',
91+
action: ['element-highlight-by-color:clear', 'element-link-by-color:clear'],
92+
});
93+
});
94+
95+
it('off', () => {
96+
plot.update({
97+
...options,
98+
connectedArea: false,
99+
});
100+
plot.render();
101+
const interaction = plot.chart.interactions['__interval-connected-area-hover__'];
102+
expect(interaction).toBeUndefined();
103+
});
104+
*/
105+
});
106+
107+
describe('bar connected area', () => {
108+
const options: BarOptions = {
109+
data: DATA,
110+
autoFit: false,
111+
width: 600,
112+
height: 400,
113+
yField: 'year',
114+
xField: 'sales',
115+
seriesField: 'type',
116+
isStack: true,
117+
xAxis: {
118+
nice: true,
119+
},
120+
connectedArea: {},
121+
};
122+
const plot = new Bar(createDiv(), options);
123+
// @ts-ignore
124+
window.__bar__ = plot;
125+
126+
it('render', () => {
127+
plot.render();
128+
const hover = plot.chart.interactions['__interval-connected-area-hover__'];
129+
const click = plot.chart.interactions['__interval-connected-area-click__'];
130+
expect(hover).toBeDefined();
131+
expect(click).toBeUndefined();
132+
// @ts-ignore
133+
expect(hover.cfg.start).toHaveLength(1);
134+
// @ts-ignore
135+
expect(hover.cfg.start[0]).toMatchObject({
136+
trigger: `interval:mouseenter`,
137+
action: ['element-highlight-by-color:highlight', 'element-link-by-color:link'],
138+
});
139+
// @ts-ignore
140+
expect(hover.cfg.end).toHaveLength(1);
141+
// @ts-ignore
142+
expect(hover.cfg.end[0]).toMatchObject({
143+
trigger: 'interval:mouseleave',
144+
action: ['element-highlight-by-color:reset', 'element-link-by-color:unlink'],
145+
});
146+
});
147+
148+
/*
149+
it('update', () => {
150+
plot.update({
151+
...options,
152+
connectedArea: {
153+
trigger: 'click',
154+
},
155+
});
156+
plot.render();
157+
const hover = plot.chart.interactions['__interval-connected-area-hover__'];
158+
const click = plot.chart.interactions['__interval-connected-area-click__'];
159+
expect(hover).toBeUndefined();
160+
expect(click).toBeDefined();
161+
// @ts-ignore
162+
expect(click.cfg.start).toHaveLength(1);
163+
// @ts-ignore
164+
expect(click.cfg.start[0]).toMatchObject({
165+
trigger: `interval:click`,
166+
action: [
167+
'element-highlight-by-color:clear',
168+
'element-highlight-by-color:highlight',
169+
'element-link-by-color:clear',
170+
'element-link-by-color:unlink',
171+
'element-link-by-color:link',
172+
],
173+
});
174+
// @ts-ignore
175+
expect(click.cfg.end).toHaveLength(1);
176+
// @ts-ignore
177+
expect(click.cfg.end[0]).toMatchObject({
178+
trigger: 'document:mousedown',
179+
action: ['element-highlight-by-color:clear', 'element-link-by-color:clear'],
180+
});
181+
});
182+
183+
it('off', () => {
184+
plot.update({
185+
...options,
186+
connectedArea: false,
187+
});
188+
plot.render();
189+
const interaction = plot.chart.interactions['__interval-connected-area-hover__'];
190+
expect(interaction).toBeUndefined();
191+
});
192+
*/
193+
});

src/adaptor/connected-area.ts

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { registerInteraction } from '@antv/g2';
2+
import { Params } from '../core/adaptor';
3+
4+
export interface ConnectedAreaOptions {
5+
/** 触发方式, 默认 hover */
6+
trigger?: 'hover' | 'click';
7+
}
8+
9+
/** 联通区域组件:使用于堆叠柱形图、堆叠条形图 */
10+
export interface OptionWithConnectedArea {
11+
connectedArea?: ConnectedAreaOptions | false;
12+
}
13+
14+
const INTERACTION_MAP = {
15+
hover: '__interval-connected-area-hover__',
16+
click: '__interval-connected-area-click__',
17+
};
18+
19+
/** hover 触发的连通区域交互 */
20+
registerInteraction(INTERACTION_MAP.hover, {
21+
start: [
22+
{
23+
trigger: `interval:mouseenter`,
24+
action: ['element-highlight-by-color:highlight', 'element-link-by-color:link'],
25+
},
26+
],
27+
end: [
28+
{
29+
trigger: 'interval:mouseleave',
30+
action: ['element-highlight-by-color:reset', 'element-link-by-color:unlink'],
31+
},
32+
],
33+
});
34+
35+
/** click 触发的联通区域交互 */
36+
registerInteraction(INTERACTION_MAP.click, {
37+
start: [
38+
{
39+
trigger: `interval:click`,
40+
action: [
41+
'element-highlight-by-color:clear',
42+
'element-highlight-by-color:highlight',
43+
'element-link-by-color:clear',
44+
'element-link-by-color:unlink',
45+
'element-link-by-color:link',
46+
],
47+
},
48+
],
49+
end: [
50+
{
51+
trigger: 'document:mousedown',
52+
action: ['element-highlight-by-color:clear', 'element-link-by-color:clear'],
53+
},
54+
],
55+
});
56+
57+
/**
58+
* 返回支持联通区域组件交互的 adaptor,适用于堆叠柱形图/堆叠条形图
59+
* @param disable
60+
*/
61+
export function connectedArea<O extends OptionWithConnectedArea>(disable = false) {
62+
return function (params: Params<O>): Params<O> {
63+
const { chart, options } = params;
64+
const { connectedArea } = options;
65+
66+
const clear = () => {
67+
chart.removeInteraction(INTERACTION_MAP.hover);
68+
chart.removeInteraction(INTERACTION_MAP.click);
69+
};
70+
71+
if (!disable && connectedArea) {
72+
const trigger = connectedArea.trigger || 'hover';
73+
clear();
74+
chart.interaction(INTERACTION_MAP[trigger]);
75+
} else {
76+
clear();
77+
}
78+
79+
return params;
80+
};
81+
}

src/plots/column/adaptor.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Params } from '../../core/adaptor';
22
import { findGeometry } from '../../utils';
33
import { tooltip, slider, interaction, animation, theme, scale, annotation, scrollbar } from '../../adaptor/common';
44
import { conversionTag } from '../../adaptor/conversion-tag';
5+
import { connectedArea } from '../../adaptor/connected-area';
56
import { interval } from '../../adaptor/geometries';
67
import { flow, transformLabel, deepAssign } from '../../utils';
78
import { percent } from '../../utils/transform/percent';
@@ -145,6 +146,7 @@ export function adaptor(params: Params<ColumnOptions>, isBar = false) {
145146
interaction,
146147
animation,
147148
annotation(),
148-
conversionTag<ColumnOptions>(options.yField, !isBar)
149+
conversionTag<ColumnOptions>(options.yField, !isBar),
150+
connectedArea<ColumnOptions>(!options.isStack)
149151
)(params);
150152
}

src/plots/column/types.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { Options, StyleAttr } from '../../types';
22
import { OptionWithConversionTag } from '../../adaptor/conversion-tag';
3+
import { OptionWithConnectedArea } from '../../adaptor/connected-area';
34

4-
export interface ColumnOptions extends Options, OptionWithConversionTag {
5+
export interface ColumnOptions extends Options, OptionWithConversionTag, OptionWithConnectedArea {
56
/** x 轴字段 */
67
readonly xField: string;
78
/** y 轴字段 */

0 commit comments

Comments
 (0)