Skip to content

Commit dea171a

Browse files
authored
feat: 股票图增强 (#2579)
1 parent 3b84cfd commit dea171a

26 files changed

+739
-391
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { schema, SchemaGeometryOptions, P, Params } from '../../../../src';
2+
import { Y_FIELD } from '../../../../src/plots/stock/constant';
3+
import { getStockData } from '../../../../src/plots/stock/utils';
4+
import { createDiv } from '../../../utils/dom';
5+
6+
describe('adaptor - schema', () => {
7+
function adaptor(params: Params<SchemaGeometryOptions>): Params<SchemaGeometryOptions> {
8+
const { chart, options } = params;
9+
const { data } = options;
10+
11+
chart.data(data);
12+
13+
// 直接使用 geometry 进行测试
14+
schema({
15+
chart,
16+
options: {
17+
...options,
18+
schema: {
19+
shape: 'candle',
20+
},
21+
},
22+
});
23+
return params;
24+
}
25+
26+
function getPlot() {
27+
const plot = new P(
28+
createDiv(),
29+
{
30+
width: 400,
31+
height: 300,
32+
data: getStockData(
33+
[
34+
{
35+
ts_code: '000001.SH',
36+
trade_date: '2020-03-13',
37+
close: 2887.4265,
38+
open: 2804.2322,
39+
high: 2910.8812,
40+
low: 2799.9841,
41+
vol: 366450436,
42+
amount: 393019665.2,
43+
},
44+
{
45+
ts_code: '000001.SH',
46+
trade_date: '2020-03-12',
47+
close: 2923.4856,
48+
open: 2936.0163,
49+
high: 2944.4651,
50+
low: 2906.2838,
51+
vol: 307778457,
52+
amount: 328209202.4,
53+
},
54+
{
55+
ts_code: '000001.SH',
56+
trade_date: '2020-03-11',
57+
close: 2968.5174,
58+
open: 3001.7616,
59+
high: 3010.0286,
60+
low: 2968.5174,
61+
vol: 352470970,
62+
amount: 378766619,
63+
},
64+
],
65+
['open', 'close', 'high', 'low']
66+
),
67+
appendPadding: 10,
68+
xField: 'trade_date',
69+
yField: Y_FIELD,
70+
mapping: {},
71+
},
72+
adaptor
73+
);
74+
75+
plot.render();
76+
return plot;
77+
}
78+
79+
it('default', () => {
80+
const plot = getPlot();
81+
expect(plot.chart.geometries[0].elements.length).toBe(3);
82+
83+
plot.destroy();
84+
});
85+
});
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { Stock } from '../../../../src';
2+
import { createDiv, removeDom } from '../../../utils/dom';
3+
import { kdata as data } from '../../../data/stock';
4+
import { DEFAULT_OPTIONS } from '../../../../src/plots/stock/constant';
5+
6+
describe('Stock', () => {
7+
const div = createDiv('x*y');
8+
const plot = new Stock(div, {
9+
width: 400,
10+
height: 500,
11+
data,
12+
xField: 'date',
13+
yField: ['start', 'end', 'max', 'min'],
14+
});
15+
16+
it('color', () => {
17+
plot.render();
18+
19+
// 图形元素个数
20+
expect(plot.chart.geometries[0].elements.length).toBe(data.length);
21+
expect(plot.chart.geometries[0].elements[0].shape.attr('fill')).toBe(DEFAULT_OPTIONS.risingFill);
22+
// datum.start < datum.end 上涨
23+
expect(plot.chart.geometries[0].elements[data.length - 2].shape.attr('fill')).toBe(DEFAULT_OPTIONS.fallingFill);
24+
});
25+
26+
it('change color', () => {
27+
plot.update({
28+
// 绿涨红跌
29+
fallingFill: '#ef5350',
30+
risingFill: '#26a69a',
31+
});
32+
// 图形元素个数
33+
expect(plot.chart.geometries[0].elements.length).toBe(data.length);
34+
expect(plot.chart.geometries[0].elements[0].shape.attr('fill')).toBe(DEFAULT_OPTIONS.fallingFill);
35+
// datum.start < datum.end 上涨
36+
expect(plot.chart.geometries[0].elements[data.length - 2].shape.attr('fill')).toBe(DEFAULT_OPTIONS.risingFill);
37+
});
38+
39+
afterAll(() => {
40+
removeDom(div);
41+
plot.destroy();
42+
});
43+
});
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { Stock } from '../../../../src';
2+
import { createDiv } from '../../../utils/dom';
3+
import { kdata } from '../../../data/stock';
4+
5+
describe('Stock', () => {
6+
it('set style', () => {
7+
const k = new Stock(createDiv('x*y'), {
8+
width: 400,
9+
height: 500,
10+
data: kdata,
11+
xField: 'date',
12+
yField: ['start', 'end', 'max', 'min'],
13+
style: {
14+
stroke: 'red',
15+
lineWidth: 2,
16+
},
17+
});
18+
19+
k.render();
20+
21+
const geometry = k.chart.geometries[0];
22+
23+
// 图形元素个数
24+
expect(k.chart.geometries[0].elements[0].shape.attr('stroke')).toBe('red');
25+
expect(k.chart.geometries[0].elements[0].shape.attr('lineWidth')).toBe(2);
26+
27+
k.destroy();
28+
});
29+
});
+82-71
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,49 @@
11
import { Stock } from '../../../../src';
2-
import { createDiv } from '../../../utils/dom';
2+
import { createDiv, removeDom } from '../../../utils/dom';
33
import { kdata } from '../../../data/stock';
44

5-
// import { DEFAULT_TOOLTIP_OPTIONS } from '../../../../src/plots/stock/constant';
6-
// import { pick } from '../../../../src/utils';
7-
85
describe('Stock tooltip', () => {
9-
it('tooltip: default options', () => {
10-
const k = new Stock(createDiv('default tooltip'), {
11-
width: 400,
12-
height: 500,
13-
data: kdata,
14-
xField: 'date',
15-
yField: ['start', 'end', 'max', 'min'],
16-
});
6+
const div = createDiv('default tooltip');
7+
const k = new Stock(div, {
8+
width: 400,
9+
height: 500,
10+
data: kdata,
11+
xField: 'date',
12+
yField: ['start', 'end', 'max', 'min'],
13+
});
1714

18-
k.render();
15+
k.render();
16+
it('tooltip: default options', () => {
1917
// @ts-ignore
2018
expect(k.chart.options.tooltip.shared).toBe(true);
2119
// @ts-ignore
2220
expect(k.chart.options.tooltip.showCrosshairs).toBe(true);
2321
// @ts-ignore
24-
expect(k.chart.options.tooltip.showTitle).toBe(false);
25-
// @ts-ignore
2622
expect(k.chart.options.tooltip.showMarkers).toBe(false);
23+
});
2724

28-
// @ts-ignore
29-
// expect(pick(k.chart.options.tooltip, Object.keys(DEFAULT_TOOLTIP_OPTIONS))).toEqual(DEFAULT_TOOLTIP_OPTIONS);
25+
it('tooltip: default show fields of yField', () => {
26+
const geometry = k.chart.geometries[0];
27+
const elements = geometry.elements;
28+
const bbox = elements[0].getBBox();
3029

31-
k.destroy();
30+
// 正常渲染某个元素tooltip
31+
k.chart.showTooltip({ x: bbox.minX + bbox.width / 2, y: bbox.y + bbox.height / 2 });
32+
33+
expect(div.querySelectorAll('.g2-tooltip-list-item').length).toBe(k.options.yField.length);
34+
35+
// 设置hide
36+
k.chart.hideTooltip();
3237
});
3338

34-
it('tooltip: options', () => {
35-
const k = new Stock(createDiv('tooltip: options'), {
36-
width: 400,
37-
height: 500,
38-
data: kdata,
39-
xField: 'date',
40-
yField: ['start', 'end', 'max', 'min'],
39+
it('tooltip: showTitle', () => {
40+
k.update({
4141
tooltip: {
4242
showTitle: true,
4343
title: 'hello world',
4444
},
4545
});
4646

47-
k.render();
48-
4947
// @ts-ignore
5048
expect(k.chart.options.tooltip.showTitle).toBe(true);
5149
// @ts-ignore
@@ -58,17 +56,10 @@ describe('Stock tooltip', () => {
5856
// @ts-ignore
5957
expect(k.chart.options.tooltip).toBe(false);
6058
expect(k.chart.getComponents().find((co) => co.type === 'tooltip')).toBe(undefined);
61-
62-
k.destroy();
6359
});
6460

6561
it('tooltip: custom itemTpl', () => {
66-
const k = new Stock(createDiv('custom itemTpl'), {
67-
width: 400,
68-
height: 500,
69-
data: kdata,
70-
xField: 'date',
71-
yField: ['start', 'end', 'max', 'min'],
62+
k.update({
7263
tooltip: {
7364
itemTpl:
7465
'<li class="g2-tooltip-list-item custom-item-tpl" data-index={index} style="margin-bottom:4px;">' +
@@ -79,68 +70,86 @@ describe('Stock tooltip', () => {
7970
},
8071
});
8172

82-
k.render();
83-
8473
const geometry = k.chart.geometries[0];
8574
const elements = geometry.elements;
8675
const bbox = elements[elements.length - 1].getBBox();
8776

8877
// 渲染自定义itemTpl
89-
k.chart.showTooltip({ x: bbox.maxX, y: bbox.maxY });
78+
k.chart.showTooltip({ x: bbox.minX + bbox.width / 2, y: bbox.y + bbox.height / 2 });
9079
expect(document.getElementsByClassName('custom-item-tpl')[0].innerHTML).not.toBeNull();
9180

92-
k.destroy();
81+
// 设置hide
82+
k.chart.hideTooltip();
9383
});
9484

95-
it('tooltip: change the configuration && operation', () => {
96-
const k = new Stock(createDiv('change the configuration && operation'), {
97-
width: 400,
98-
height: 500,
99-
data: kdata,
100-
xField: 'date',
101-
yField: ['start', 'end', 'max', 'min'],
85+
it('tooltip: fields', () => {
86+
k.update({
87+
tooltip: {
88+
fields: ['start', 'end', 'max', 'min', 'volumn'],
89+
},
10290
});
10391

104-
k.render();
92+
const geometry = k.chart.geometries[0];
93+
const elements = geometry.elements;
94+
const bbox = elements[0].getBBox();
95+
96+
// 正常渲染某个元素tooltip
97+
k.chart.showTooltip({ x: bbox.minX + bbox.width / 2, y: bbox.y + bbox.height / 2 });
98+
99+
expect(div.querySelectorAll('.g2-tooltip-list-item').length).toBe(5);
100+
101+
// 设置hide
102+
k.chart.hideTooltip();
103+
});
104+
105+
// fixme https://github.com/antvis/G2/issues/3435
106+
it.skip('tooltip: fields & formatter', () => {
107+
k.update({
108+
tooltip: {
109+
fields: ['start', 'end', 'max', 'min', 'volumn'],
110+
formatter: () => ({ name: 'x', value: 'a' }),
111+
},
112+
});
105113

106114
const geometry = k.chart.geometries[0];
107115
const elements = geometry.elements;
108116
const bbox = elements[elements.length - 1].getBBox();
109117

110118
// 正常渲染某个元素tooltip
111-
k.chart.showTooltip({ x: bbox.maxX, y: bbox.maxY });
112-
expect(document.getElementsByClassName('g2-tooltip-list-item')[0].innerHTML).not.toBeNull();
119+
k.chart.showTooltip({ x: bbox.minX + bbox.width / 2, y: bbox.y + bbox.height / 2 });
120+
expect(div.getElementsByClassName('g2-tooltip-list-item').length).toBe(5);
113121

114122
// 设置hide
123+
k.chart.hideTooltip();
124+
});
125+
126+
it('tooltip: fields & customContent', () => {
115127
k.update({
116-
...k.options,
117-
tooltip: false,
128+
tooltip: {
129+
fields: ['start', 'end', 'max'],
130+
customContent: (text, items) =>
131+
`<div>${items.map((item, idx) => `<div class="custom-tooltip-item-content">${idx}</div>`)}<div>`,
132+
},
118133
});
119-
// @ts-ignore
120-
expect(k.chart.options.tooltip).toBe(false);
121-
expect(k.chart.getComponents().find((co) => co.type === 'tooltip')).toBe(undefined);
122134

123-
k.destroy();
135+
const elements = k.chart.geometries[0].elements;
136+
const bbox = elements[elements.length - 1].getBBox();
137+
138+
// 正常渲染某个元素tooltip
139+
k.chart.showTooltip({ x: bbox.minX + bbox.width / 2, y: bbox.y + bbox.height / 2 });
140+
expect(div.getElementsByClassName('custom-tooltip-item-content').length).toBe(3);
141+
142+
// 设置hide
143+
k.chart.hideTooltip();
124144
});
125145

126-
it('tooltip: custom crosshairs', () => {
127-
const k = new Stock(createDiv('custom crosshairs'), {
128-
width: 400,
129-
height: 500,
130-
data: kdata,
131-
xField: 'date',
132-
yField: ['start', 'end', 'max', 'min'],
146+
it('tooltip: custom crosshairs', () => {
147+
k.update({
133148
tooltip: {
134149
crosshairs: {
135150
type: 'xy',
136151
follow: true,
137-
text: (
138-
type, // 对应当前 crosshairs 的类型,值为 'x' 或者 'y'
139-
defaultContent, // 对应当前 crosshairs 默认的文本内容
140-
items, // 对应当前 tooltip 内容框中的数据
141-
currentPoint // 对应当前坐标点
142-
) => {
143-
console.log(type, defaultContent, items, currentPoint);
152+
text: () => {
144153
return {
145154
content: 'custom text',
146155
};
@@ -149,12 +158,14 @@ describe('Stock tooltip', () => {
149158
},
150159
});
151160

152-
k.render();
153-
154161
// @ts-ignore
155162
expect(k.chart.options.tooltip.crosshairs.text()).not.toBeUndefined();
156163
// @ts-ignore
157164
expect(k.chart.options.tooltip.crosshairs.text().content).toBe('custom text');
165+
});
166+
167+
afterAll(() => {
158168
k.destroy();
169+
removeDom(div);
159170
});
160171
});

0 commit comments

Comments
 (0)