import { customElement, property, type TemplateResult, } from '@design.estate/dees-element'; import { DeesChartEchartsBase } from '../dees-chart-echarts-base.js'; import { demoFunc } from './demo.js'; import { barStyles } from './styles.js'; import { renderChartBar } from './template.js'; import { getEchartsSeriesColors, getThemeColors } from '../dees-chart-echarts-theme.js'; export interface IBarSeriesItem { name: string; data: number[]; color?: string; } declare global { interface HTMLElementTagNameMap { 'dees-chart-bar': DeesChartBar; } } @customElement('dees-chart-bar') export class DeesChartBar extends DeesChartEchartsBase { public static demo = demoFunc; public static demoGroups = ['Chart']; @property({ type: Array }) accessor categories: string[] = []; @property({ type: Array }) accessor series: IBarSeriesItem[] = []; @property({ type: Boolean }) accessor horizontal: boolean = false; @property({ type: Boolean }) accessor stacked: boolean = false; @property({ type: Boolean }) accessor showLegend: boolean = true; @property({ attribute: false }) accessor valueFormatter: (value: number) => string = (val) => `${val}`; public static styles = barStyles; public render(): TemplateResult { return renderChartBar(this); } public async updated(changedProperties: Map) { super.updated(changedProperties); if ( this.chartInstance && (changedProperties.has('categories') || changedProperties.has('series') || changedProperties.has('horizontal') || changedProperties.has('stacked') || changedProperties.has('showLegend')) ) { this.updateChart(); } } protected buildOption(): Record { const colors = getThemeColors(this.goBright); const seriesColors = getEchartsSeriesColors(this.goBright); const formatter = this.valueFormatter; const categoryAxis: Record = { type: 'category', data: this.categories, axisLine: { lineStyle: { color: colors.borderStrong } }, axisLabel: { color: colors.textMuted }, }; const valueAxis: Record = { type: 'value', axisLine: { show: false }, axisLabel: { color: colors.textMuted, formatter: (val: number) => formatter(val), }, splitLine: { lineStyle: { color: colors.borderSubtle } }, }; const seriesData = this.series.map((s, index) => ({ name: s.name, type: 'bar' as const, data: s.data, stack: this.stacked ? 'total' : undefined, itemStyle: { color: s.color || seriesColors[index % seriesColors.length], borderRadius: this.stacked ? [0, 0, 0, 0] : this.horizontal ? [0, 4, 4, 0] : [4, 4, 0, 0], }, barMaxWidth: 40, emphasis: { itemStyle: { shadowBlur: 6, shadowColor: 'rgba(0, 0, 0, 0.15)', }, }, })); // For stacked bars, round the top corners of the last visible series if (this.stacked && seriesData.length > 0) { const last = seriesData[seriesData.length - 1]; last.itemStyle.borderRadius = this.horizontal ? [0, 4, 4, 0] : [4, 4, 0, 0]; } return { tooltip: { trigger: 'axis', axisPointer: { type: 'shadow' }, formatter: (params: any) => { const items = Array.isArray(params) ? params : [params]; let result = `${items[0].axisValueLabel}
`; for (const p of items) { result += `${p.marker} ${p.seriesName}: ${formatter(p.value)}
`; } return result; }, }, legend: this.showLegend && this.series.length > 1 ? { bottom: 8, itemWidth: 10, itemHeight: 10 } : { show: false }, grid: { left: 16, right: 16, top: 16, bottom: this.showLegend && this.series.length > 1 ? 40 : 16, containLabel: true, }, xAxis: this.horizontal ? valueAxis : categoryAxis, yAxis: this.horizontal ? categoryAxis : valueAxis, series: seriesData, }; } }