Files
dees-catalog/ts_web/elements/00group-chart/dees-chart-bar/component.ts
2026-04-04 11:05:01 +00:00

143 lines
4.1 KiB
TypeScript

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 } 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<string, any>) {
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<string, any> {
const seriesColors = getEchartsSeriesColors(this.goBright);
const isDark = !this.goBright;
const formatter = this.valueFormatter;
const categoryAxis: Record<string, any> = {
type: 'category',
data: this.categories,
axisLine: { lineStyle: { color: isDark ? 'hsl(0 0% 20%)' : 'hsl(0 0% 85%)' } },
axisLabel: { color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 40%)' },
};
const valueAxis: Record<string, any> = {
type: 'value',
axisLine: { show: false },
axisLabel: {
color: isDark ? 'hsl(0 0% 63.9%)' : 'hsl(0 0% 40%)',
formatter: (val: number) => formatter(val),
},
splitLine: { lineStyle: { color: isDark ? 'hsl(0 0% 14%)' : 'hsl(0 0% 92%)' } },
};
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 = `<strong>${items[0].axisValueLabel}</strong><br/>`;
for (const p of items) {
result += `${p.marker} ${p.seriesName}: <strong>${formatter(p.value)}</strong><br/>`;
}
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,
};
}
}