feat(chart-area): add series statistics display and computation for chart data
This commit is contained in:
@@ -33,6 +33,9 @@ export class DeesChartArea extends DeesElement {
|
|||||||
@state()
|
@state()
|
||||||
accessor chart: IChartApi | null = null;
|
accessor chart: IChartApi | null = null;
|
||||||
|
|
||||||
|
@state()
|
||||||
|
accessor seriesStats: Array<{ name: string; latest: number; min: number; max: number; avg: number; color: string }> = [];
|
||||||
|
|
||||||
@property()
|
@property()
|
||||||
accessor label: string = 'Untitled Chart';
|
accessor label: string = 'Untitled Chart';
|
||||||
|
|
||||||
@@ -172,7 +175,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
for (const [, api] of this.seriesApis) {
|
for (const [, api] of this.seriesApis) {
|
||||||
const color = colors[idx % colors.length];
|
const color = colors[idx % colors.length];
|
||||||
api.applyOptions({
|
api.applyOptions({
|
||||||
topColor: this.hslToRgba(color, isDark ? 0.2 : 0.3),
|
topColor: this.hslToRgba(color, isDark ? 0.4 : 0.5),
|
||||||
bottomColor: this.hslToRgba(color, 0),
|
bottomColor: this.hslToRgba(color, 0),
|
||||||
lineColor: color,
|
lineColor: color,
|
||||||
});
|
});
|
||||||
@@ -194,7 +197,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
chartSeries.forEach((s, index) => {
|
chartSeries.forEach((s, index) => {
|
||||||
const color = colors[index % colors.length];
|
const color = colors[index % colors.length];
|
||||||
const api = this.chart!.addSeries(this.lcBundle!.AreaSeries, {
|
const api = this.chart!.addSeries(this.lcBundle!.AreaSeries, {
|
||||||
topColor: this.hslToRgba(color, isDark ? 0.2 : 0.3),
|
topColor: this.hslToRgba(color, isDark ? 0.4 : 0.5),
|
||||||
bottomColor: this.hslToRgba(color, 0),
|
bottomColor: this.hslToRgba(color, 0),
|
||||||
lineColor: color,
|
lineColor: color,
|
||||||
lineWidth: 2,
|
lineWidth: 2,
|
||||||
@@ -218,6 +221,23 @@ export class DeesChartArea extends DeesElement {
|
|||||||
|
|
||||||
this.seriesApis.set(s.name || `series-${index}`, api);
|
this.seriesApis.set(s.name || `series-${index}`, api);
|
||||||
});
|
});
|
||||||
|
this.computeStats(chartSeries);
|
||||||
|
}
|
||||||
|
|
||||||
|
private computeStats(chartSeries: ChartSeriesConfig) {
|
||||||
|
const isDark = !this.goBright;
|
||||||
|
const colors = this.getSeriesColors(isDark);
|
||||||
|
this.seriesStats = chartSeries.map((s, index) => {
|
||||||
|
const values = s.data.map(d => d.y);
|
||||||
|
if (values.length === 0) {
|
||||||
|
return { name: s.name || `series-${index}`, latest: 0, min: 0, max: 0, avg: 0, color: colors[index % colors.length] };
|
||||||
|
}
|
||||||
|
const latest = values[values.length - 1];
|
||||||
|
const min = Math.min(...values);
|
||||||
|
const max = Math.max(...values);
|
||||||
|
const avg = Math.round((values.reduce((sum, v) => sum + v, 0) / values.length) * 100) / 100;
|
||||||
|
return { name: s.name || `series-${index}`, latest, min, max, avg, color: colors[index % colors.length] };
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private updatePriceLines(name: string, api: ISeriesApi<any>, data: Array<{ x: any; y: number }>, color: string) {
|
private updatePriceLines(name: string, api: ISeriesApi<any>, data: Array<{ x: any; y: number }>, color: string) {
|
||||||
@@ -468,6 +488,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
api.setData(this.convertDataToLC(filtered));
|
api.setData(this.convertDataToLC(filtered));
|
||||||
this.updatePriceLines(name, api, filtered, colors[index % colors.length]);
|
this.updatePriceLines(name, api, filtered, colors[index % colors.length]);
|
||||||
});
|
});
|
||||||
|
this.computeStats(newSeries);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -505,6 +526,7 @@ export class DeesChartArea extends DeesElement {
|
|||||||
api.setData(this.convertDataToLC(s.data));
|
api.setData(this.convertDataToLC(s.data));
|
||||||
this.updatePriceLines(name, api, s.data, colors[index % colors.length]);
|
this.updatePriceLines(name, api, s.data, colors[index % colors.length]);
|
||||||
});
|
});
|
||||||
|
this.computeStats(newSeries);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -34,9 +34,46 @@ export const chartAreaStyles = [
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: 44px;
|
top: 44px;
|
||||||
left: 0;
|
left: 0;
|
||||||
bottom: 0;
|
bottom: 32px;
|
||||||
right: 0;
|
right: 0;
|
||||||
}
|
}
|
||||||
|
.statsBar {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24px;
|
||||||
|
padding: 0 16px;
|
||||||
|
border-top: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
||||||
|
font-size: 11px;
|
||||||
|
color: ${cssManager.bdTheme('hsl(0 0% 45%)', 'hsl(0 0% 55%)')};
|
||||||
|
}
|
||||||
|
.statsSeries {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
.statsSeries + .statsSeries {
|
||||||
|
padding-left: 24px;
|
||||||
|
border-left: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
|
||||||
|
}
|
||||||
|
.statsColor {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 2px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.statsName {
|
||||||
|
font-weight: 500;
|
||||||
|
color: ${cssManager.bdTheme('hsl(0 0% 20%)', 'hsl(0 0% 80%)')};
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
.statsItem strong {
|
||||||
|
color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
|
||||||
|
}
|
||||||
.lw-tooltip {
|
.lw-tooltip {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
|||||||
@@ -6,7 +6,20 @@ export const renderChartArea = (component: DeesChartArea): TemplateResult => {
|
|||||||
<div class="mainbox">
|
<div class="mainbox">
|
||||||
<div class="chartTitle">${component.label}</div>
|
<div class="chartTitle">${component.label}</div>
|
||||||
<div class="chartContainer"></div>
|
<div class="chartContainer"></div>
|
||||||
|
${component.seriesStats.length > 0 ? html`
|
||||||
|
<div class="statsBar">
|
||||||
|
${component.seriesStats.map(s => html`
|
||||||
|
<div class="statsSeries">
|
||||||
|
<span class="statsColor" style="background:${s.color}"></span>
|
||||||
|
<span class="statsName">${s.name}</span>
|
||||||
|
<span class="statsItem">latest <strong>${component.yAxisFormatter(s.latest)}</strong></span>
|
||||||
|
<span class="statsItem">min <strong>${component.yAxisFormatter(s.min)}</strong></span>
|
||||||
|
<span class="statsItem">max <strong>${component.yAxisFormatter(s.max)}</strong></span>
|
||||||
|
<span class="statsItem">avg <strong>${component.yAxisFormatter(s.avg)}</strong></span>
|
||||||
|
</div>
|
||||||
|
`)}
|
||||||
|
</div>
|
||||||
|
` : ''}
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user