Skip to content

Commit 6d5f954

Browse files
arthur-polidorioCSimoesJr
authored andcommitted
feat(charts): implementa chart do tipo bar
1 parent 6834471 commit 6d5f954

7 files changed

+718
-224
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
import { EChartsOption } from 'echarts/dist/echarts.esm';
2+
import { PoChartNewComponent } from './po-chart-new.component';
3+
4+
export class PoChartGridUtils {
5+
constructor(private readonly component: PoChartNewComponent) {}
6+
7+
setGridOption(options: EChartsOption) {
8+
const tokenBorderWidthSm = this.resolvePx('--border-width-sm');
9+
const paddingBottom = this.getPaddingBottomGrid();
10+
const paddingTop = this.getPaddingTopGrid();
11+
options.grid = {
12+
top: paddingTop,
13+
left: this.component.options?.axis?.paddingLeft || 16,
14+
right: this.component.options?.axis?.paddingRight || 32,
15+
bottom: this.component.options?.axis?.paddingBottom || paddingBottom,
16+
containLabel: true,
17+
borderWidth: tokenBorderWidthSm
18+
};
19+
}
20+
21+
setOptionsAxis(options: EChartsOption) {
22+
const tokenFontSizeGrid = this.resolvePx('--font-size-grid', '.po-chart');
23+
const tokenBorderWidthSm = this.resolvePx('--border-width-sm');
24+
25+
options.xAxis = {
26+
type: this.component.isTypeBar ? 'value' : 'category',
27+
axisLabel: {
28+
fontFamily: this.component.getCSSVariable('--font-family-grid', '.po-chart'),
29+
fontSize: tokenFontSizeGrid || 12,
30+
fontWeight: Number(this.component.getCSSVariable('--font-weight-grid', '.po-chart')),
31+
rotate: this.component.options?.axis?.rotateLegend,
32+
interval: 0,
33+
width: 72,
34+
overflow: 'break'
35+
},
36+
splitLine: {
37+
show: this.component.options?.axis?.showXAxis || false,
38+
lineStyle: {
39+
type: 'solid',
40+
width: tokenBorderWidthSm,
41+
color: this.component.getCSSVariable('--color-grid', '.po-chart')
42+
}
43+
}
44+
};
45+
46+
options.yAxis = {
47+
type: this.component.isTypeBar ? 'category' : 'value',
48+
splitNumber: 5,
49+
axisLabel: {
50+
margin: 10,
51+
fontFamily: this.component.getCSSVariable('--font-family-grid', '.po-chart'),
52+
fontSize: tokenFontSizeGrid || 12,
53+
fontWeight: Number(this.component.getCSSVariable('--font-weight-grid', '.po-chart'))
54+
},
55+
splitLine: {
56+
show: this.component.options?.axis?.showYAxis ?? true,
57+
lineStyle: {
58+
color: this.component.getCSSVariable('--color-grid', '.po-chart')
59+
}
60+
}
61+
};
62+
63+
if (this.component.isTypeBar) {
64+
options.yAxis.data = this.component.categories;
65+
} else {
66+
options.xAxis.data = this.component.categories;
67+
options.xAxis.boundaryGap = this.component.boundaryGap;
68+
}
69+
}
70+
71+
setOptionDataZoom(options: EChartsOption) {
72+
options.dataZoom = [
73+
{
74+
show: true,
75+
realtime: true,
76+
bottom: this.component.options?.bottomDataZoom || 'calc(100%)',
77+
height: 25,
78+
right: this.component.options?.axis?.paddingRight || 32,
79+
xAxisIndex: [0]
80+
},
81+
{
82+
type: 'inside',
83+
realtime: true,
84+
xAxisIndex: [0]
85+
}
86+
];
87+
}
88+
89+
setShowAxisDetails(options: EChartsOption) {
90+
if (this.component.options?.axis?.showAxisDetails) {
91+
options.tooltip = {
92+
trigger: 'none',
93+
axisPointer: {
94+
type: 'cross',
95+
label: {
96+
backgroundColor: '#6a7985'
97+
}
98+
}
99+
};
100+
}
101+
}
102+
103+
setSerieTypeLine(serie: any, tokenBorderWidthMd: number, color: string) {
104+
if (serie.type === 'line') {
105+
serie.symbolSize = 8;
106+
serie.symbol = 'circle';
107+
serie.itemStyle = {
108+
color: !this.component.options?.fillPoints ? this.component.getCSSVariable('--color-neutral-light-00') : color,
109+
borderColor: color,
110+
borderWidth: tokenBorderWidthMd
111+
};
112+
serie.lineStyle = { color: color, width: tokenBorderWidthMd };
113+
}
114+
}
115+
116+
setSerieTypeArea(serie: any, index: number) {
117+
if (serie.isTypeArea) {
118+
serie.areaStyle = {
119+
color: serie.color?.includes('color')
120+
? this.component.getCSSVariable(`--${serie.color.replace('po-', '')}`)
121+
: serie.overlayColor
122+
};
123+
124+
if (index > 7 || serie.isNotTokenColor) {
125+
serie.areaStyle.opacity = 0.5;
126+
}
127+
}
128+
}
129+
130+
setSerieTypeBarColumn(serie: any, color: string) {
131+
if (serie.type === 'bar') {
132+
serie.itemStyle = {
133+
borderRadius: this.resolvePx('--border-radius-bar', '.po-chart'),
134+
color: color
135+
};
136+
serie.emphasis = { focus: 'series' };
137+
this.component.boundaryGap = true;
138+
}
139+
}
140+
141+
resolvePx(size: string, selector?: string): number {
142+
const token = this.component.getCSSVariable(size, selector);
143+
if (token.endsWith('px')) {
144+
return parseFloat(token);
145+
} else if (token.endsWith('rem')) {
146+
return parseFloat(token) * 16;
147+
} else if (token.endsWith('em')) {
148+
const parentElement = selector ? document.querySelector(selector) : document.documentElement;
149+
const parentFontSize = parentElement ? parseFloat(getComputedStyle(parentElement).fontSize) : 16;
150+
return parseFloat(token) * parentFontSize;
151+
}
152+
}
153+
154+
private getPaddingBottomGrid() {
155+
const options = this.component.options;
156+
if (
157+
options?.dataZoom &&
158+
options?.bottomDataZoom &&
159+
(options?.legend === false || options?.legendVerticalPosition === 'top')
160+
) {
161+
if (typeof options?.bottomDataZoom === 'boolean' && options?.bottomDataZoom === true) {
162+
options.bottomDataZoom = 8;
163+
}
164+
return 50;
165+
} else if (options?.dataZoom && options?.bottomDataZoom && options?.legendVerticalPosition !== 'top') {
166+
if (typeof options?.bottomDataZoom === 'boolean' && options?.bottomDataZoom === true) {
167+
options.bottomDataZoom = 32;
168+
}
169+
return 70;
170+
} else if (
171+
(options?.dataZoom && !options?.bottomDataZoom && options?.legend === false) ||
172+
(!options?.dataZoom && options?.legend === false) ||
173+
(!options?.dataZoom && options?.legendVerticalPosition === 'top')
174+
) {
175+
return 0;
176+
}
177+
return 50;
178+
}
179+
180+
private getPaddingTopGrid() {
181+
const options = this.component.options;
182+
if (
183+
(options?.dataZoom && !options?.bottomDataZoom) ||
184+
(options?.dataZoom && options?.bottomDataZoom && options?.legendVerticalPosition === 'top') ||
185+
(!options?.dataZoom && options?.legendVerticalPosition === 'top')
186+
) {
187+
if (typeof options?.bottomDataZoom === 'boolean' && options?.bottomDataZoom === true) {
188+
options.bottomDataZoom = 8;
189+
}
190+
const fixed = this.component.dataLabel?.fixed && !options?.axis?.maxRange;
191+
return fixed ? 60 : 50;
192+
} else if (
193+
(options?.dataZoom && options?.bottomDataZoom && options?.legendVerticalPosition !== 'top') ||
194+
(!options?.dataZoom && options?.legendVerticalPosition !== 'top')
195+
) {
196+
const fixed = this.component.dataLabel?.fixed && !options?.axis?.maxRange;
197+
return fixed ? 30 : 20;
198+
}
199+
}
200+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
import { PoChartGridUtils } from './po-chart-grid-utils';
2+
import { EChartsOption } from 'echarts';
3+
4+
describe('PoChartGridUtils', () => {
5+
let utils: PoChartGridUtils;
6+
let mockCtx: any;
7+
8+
beforeEach(() => {
9+
mockCtx = {
10+
boundaryGap: false,
11+
isTypeBar: false,
12+
categories: ['A', 'B'],
13+
options: {
14+
axis: { rotateLegend: 45, showXAxis: true, showYAxis: true },
15+
fillPoints: true
16+
},
17+
resolvePx: jasmine.createSpy('resolvePx').and.returnValue(10),
18+
getCSSVariable: jasmine.createSpy('getCSSVariable').and.callFake((key: string) => {
19+
const vars = {
20+
'--color-neutral-light-00': '#fff',
21+
'--color-grid': '#ccc',
22+
'--font-family-grid': 'Arial',
23+
'--font-weight-grid': '400'
24+
};
25+
return vars[key] || '';
26+
})
27+
};
28+
29+
utils = new PoChartGridUtils(mockCtx);
30+
});
31+
32+
describe('setSerieTypeLine', () => {
33+
it('should set properties when type is line', () => {
34+
const serie: any = { type: 'line' };
35+
const color = '#00f';
36+
37+
utils.setSerieTypeLine(serie, 2, color);
38+
39+
expect(serie.symbolSize).toBe(8);
40+
expect(serie.symbol).toBe('circle');
41+
expect(serie.itemStyle.color).toBe('#00f');
42+
expect(serie.itemStyle.borderColor).toBe('#00f');
43+
expect(serie.itemStyle.borderWidth).toBe(2);
44+
expect(serie.lineStyle.color).toBe('#00f');
45+
expect(serie.lineStyle.width).toBe(2);
46+
});
47+
});
48+
49+
describe('setSerieTypeArea', () => {
50+
it('should set areaStyle and opacity', () => {
51+
const serie: any = {
52+
isTypeArea: true,
53+
color: 'color-01',
54+
overlayColor: 'rgba(255,255,255,0.5)'
55+
};
56+
57+
utils.setSerieTypeArea(serie, 8); // index > 7
58+
59+
expect(serie.areaStyle.opacity).toBe(0.5);
60+
});
61+
});
62+
63+
describe('setSerieTypeBarColumn', () => {
64+
it('should set itemStyle and emphasis when type is bar', () => {
65+
const serie: any = { type: 'bar' };
66+
const color = '#f00';
67+
68+
utils.setSerieTypeBarColumn(serie, color);
69+
70+
expect(serie.itemStyle.color).toBe(color);
71+
expect(serie.emphasis.focus).toBe('series');
72+
expect(mockCtx.boundaryGap).toBe(true);
73+
});
74+
});
75+
76+
describe('setOptionsAxis', () => {
77+
it('should define xAxis and yAxis correctly', () => {
78+
const option: EChartsOption = {};
79+
80+
utils.setOptionsAxis(option);
81+
82+
expect(option.xAxis).toBeDefined();
83+
expect(option.yAxis).toBeDefined();
84+
expect(option.xAxis['axisLabel'].rotate).toBe(45);
85+
expect(option.xAxis['axisLabel'].overflow).toBe('break');
86+
});
87+
});
88+
});

projects/ui/src/lib/components/po-chart-new/po-chart-new.component.html

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<div *ngIf="series.length" [class.expanded]="isExpanded" id="chart-container">
22
<div class="po-chart-header">
3-
<div class="po-chart-header-title">
3+
<div class="po-chart-header-title po-lg-9 po-md-8 po-sm-6" style="padding: 0">
44
<strong> {{ title }} </strong>
55
</div>
66

7-
<div class="po-chart-header-actions">
7+
<div class="po-chart-header-actions po-lg-3 po-md-4 po-sm-6">
88
<po-button
99
p-icon="ICON_LIST_BULLETS"
1010
p-kind="tertiary"

0 commit comments

Comments
 (0)