Skip to content

Commit f435305

Browse files
BBSQQ羽熙
and
羽熙
authored
feat(v2/bar): add basic bar chart (#1330)
Co-authored-by: 羽熙 <[email protected]>
1 parent 8da53b8 commit f435305

File tree

9 files changed

+476
-1
lines changed

9 files changed

+476
-1
lines changed

__tests__/unit/plots/bar/axis-spec.ts

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import { Bar } from '../../../../src';
2+
import { salesByArea } from '../../../data/sales';
3+
import { createDiv } from '../../../utils/dom';
4+
5+
describe('bar axis', () => {
6+
it('meta', () => {
7+
const formatter = (v) => `${Math.floor(v / 10000)}万`;
8+
const bar = new Bar(createDiv(), {
9+
width: 400,
10+
height: 300,
11+
data: salesByArea,
12+
xField: 'sales',
13+
yField: 'area',
14+
meta: {
15+
sales: {
16+
nice: true,
17+
formatter,
18+
},
19+
},
20+
});
21+
22+
bar.render();
23+
24+
const geometry = bar.chart.geometries[0];
25+
// @ts-ignore
26+
expect(geometry.scales.sales.nice).toBe(true);
27+
expect(geometry.scales.sales.formatter).toBe(formatter);
28+
});
29+
30+
it('yAxis', () => {
31+
const bar = new Bar(createDiv(), {
32+
width: 400,
33+
height: 300,
34+
data: salesByArea,
35+
xField: 'area',
36+
yField: 'sales',
37+
yAxis: {
38+
minLimit: 10000,
39+
nice: true,
40+
},
41+
});
42+
43+
bar.render();
44+
45+
const geometry = bar.chart.geometries[0];
46+
const axisOptions = bar.chart.getOptions().axes;
47+
48+
// @ts-ignore
49+
expect(axisOptions.sales.minLimit).toBe(10000);
50+
expect(geometry.scales.sales.minLimit).toBe(10000);
51+
// @ts-ignore
52+
expect(geometry.scales.sales.nice).toBe(true);
53+
});
54+
55+
it('xAxis', () => {
56+
const bar = new Bar(createDiv(), {
57+
width: 400,
58+
height: 300,
59+
data: salesByArea,
60+
xField: 'area',
61+
yField: 'sales',
62+
xAxis: {
63+
label: {
64+
rotate: -Math.PI / 6,
65+
},
66+
},
67+
});
68+
69+
bar.render();
70+
const axisOptions = bar.chart.getOptions().axes;
71+
72+
// @ts-ignore
73+
expect(axisOptions.area.label.rotate).toBe(-Math.PI / 6);
74+
});
75+
});
+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import { Bar } from '../../../../src';
2+
import { salesByArea } from '../../../data/sales';
3+
import { createDiv } from '../../../utils/dom';
4+
5+
describe('bar', () => {
6+
it('x*y', () => {
7+
const bar = new Bar(createDiv(), {
8+
width: 400,
9+
height: 300,
10+
data: salesByArea,
11+
xField: 'area',
12+
yField: 'sales',
13+
});
14+
15+
bar.render();
16+
17+
const geometry = bar.chart.geometries[0];
18+
const positionFields = geometry.getAttribute('position').getFields();
19+
20+
// 类型
21+
expect(geometry.type).toBe('interval');
22+
// 图形元素个数
23+
expect(bar.chart.geometries[0].elements.length).toBe(salesByArea.length);
24+
// x & y
25+
expect(positionFields).toHaveLength(2);
26+
expect(positionFields[0]).toBe('area');
27+
expect(positionFields[1]).toBe('sales');
28+
});
29+
30+
it('x*y*color', () => {
31+
const bar = new Bar(createDiv(), {
32+
width: 400,
33+
height: 300,
34+
data: salesByArea,
35+
xField: 'area',
36+
yField: 'sales',
37+
colorField: 'area',
38+
});
39+
40+
bar.render();
41+
42+
const geometry = bar.chart.geometries[0];
43+
const colorFields = geometry.getAttribute('color').getFields();
44+
45+
expect(colorFields).toHaveLength(1);
46+
expect(colorFields[0]).toBe('area');
47+
});
48+
49+
it('x*y*color with color', () => {
50+
const palette = ['red', 'yellow', 'green'];
51+
const bar = new Bar(createDiv(), {
52+
width: 400,
53+
height: 300,
54+
data: salesByArea,
55+
xField: 'area',
56+
yField: 'sales',
57+
colorField: 'area',
58+
color: palette,
59+
});
60+
61+
bar.render();
62+
63+
const geometry = bar.chart.geometries[0];
64+
const colorAttribute = geometry.getAttribute('color');
65+
const colorFields = colorAttribute.getFields();
66+
67+
expect(colorFields).toHaveLength(1);
68+
expect(colorFields[0]).toBe('area');
69+
geometry.elements.forEach((element, index) => {
70+
const color = element.getModel().color;
71+
expect(color).toBe(palette[index % palette.length]);
72+
});
73+
});
74+
});
+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { Bar } from '../../../../src';
2+
import { salesByArea } from '../../../data/sales';
3+
import { createDiv } from '../../../utils/dom';
4+
5+
describe('bar label', () => {
6+
it('position: right', () => {
7+
const bar = new Bar(createDiv(), {
8+
width: 400,
9+
height: 300,
10+
data: salesByArea,
11+
xField: 'area',
12+
yField: 'sales',
13+
meta: {
14+
sales: {
15+
nice: true,
16+
formatter: (v) => `${Math.floor(v / 10000)}万`,
17+
},
18+
},
19+
label: {
20+
position: 'right',
21+
},
22+
});
23+
24+
bar.render();
25+
26+
const geometry = bar.chart.geometries[0];
27+
const labelGroups = geometry.labelsContainer.getChildren();
28+
29+
// @ts-ignore
30+
expect(geometry.labelOption.cfg).toEqual({
31+
position: 'right',
32+
});
33+
expect(labelGroups).toHaveLength(salesByArea.length);
34+
labelGroups.forEach((label, index) => {
35+
expect(label.get('children')[0].attr('text')).toBe(`${Math.floor(salesByArea[index].sales / 10000)}万`);
36+
});
37+
});
38+
39+
it('label position middle', () => {
40+
const bar = new Bar(createDiv(), {
41+
width: 400,
42+
height: 300,
43+
data: salesByArea,
44+
xField: 'area',
45+
yField: 'sales',
46+
meta: {
47+
sales: {
48+
nice: true,
49+
formatter: (v) => `${Math.floor(v / 10000)}万`,
50+
},
51+
},
52+
label: {
53+
position: 'middle',
54+
},
55+
});
56+
57+
bar.render();
58+
59+
const geometry = bar.chart.geometries[0];
60+
61+
// @ts-ignore
62+
expect(geometry.labelOption.cfg).toEqual({ position: 'middle' });
63+
});
64+
65+
it('label position left', () => {
66+
const bar = new Bar(createDiv(), {
67+
width: 400,
68+
height: 300,
69+
data: salesByArea,
70+
xField: 'area',
71+
yField: 'sales',
72+
meta: {
73+
sales: {
74+
nice: true,
75+
formatter: (v) => `${Math.floor(v / 10000)}万`,
76+
},
77+
},
78+
label: {
79+
position: 'left',
80+
},
81+
});
82+
83+
bar.render();
84+
85+
const geometry = bar.chart.geometries[0];
86+
87+
// @ts-ignore
88+
expect(geometry.labelOption.cfg).toEqual({ position: 'left' });
89+
});
90+
});
+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Bar } from '../../../../src';
2+
import { salesByArea } from '../../../data/sales';
3+
import { createDiv } from '../../../utils/dom';
4+
5+
describe('bar style', () => {
6+
it('style config', () => {
7+
const bar = new Bar(createDiv(), {
8+
width: 400,
9+
height: 300,
10+
data: salesByArea,
11+
xField: 'area',
12+
yField: 'sales',
13+
meta: {
14+
sales: {
15+
nice: true,
16+
formatter: (v) => `${Math.floor(v / 10000)}万`,
17+
},
18+
},
19+
barStyle: {
20+
stroke: 'black',
21+
lineWidth: 2,
22+
},
23+
});
24+
25+
bar.render();
26+
27+
const geometry = bar.chart.geometries[0];
28+
const elements = geometry.elements;
29+
expect(elements[0].shape.attr('stroke')).toBe('black');
30+
expect(elements[0].shape.attr('lineWidth')).toBe(2);
31+
});
32+
33+
it('style callback', () => {
34+
const bar = new Bar(createDiv(), {
35+
width: 400,
36+
height: 300,
37+
data: salesByArea,
38+
xField: 'area',
39+
yField: 'sales',
40+
meta: {
41+
sales: {
42+
nice: true,
43+
formatter: (v) => `${Math.floor(v / 10000)}万`,
44+
},
45+
},
46+
barStyle: (x, y) => {
47+
return {
48+
stroke: 'black',
49+
lineWidth: 2,
50+
};
51+
},
52+
});
53+
54+
bar.render();
55+
56+
const geometry = bar.chart.geometries[0];
57+
const elements = geometry.elements;
58+
expect(elements[0].shape.attr('stroke')).toBe('black');
59+
expect(elements[0].shape.attr('lineWidth')).toBe(2);
60+
});
61+
});

src/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,6 @@ export { Progress, ProgressOptions } from './plots/progress';
3232

3333
// 环形进度图及类型定义
3434
export { RingProgress, RingProgressOptions } from './plots/ring-progress';
35+
36+
// 条形图及类型定义
37+
export { Bar, BarOptions } from './plots/bar';

0 commit comments

Comments
 (0)