Pin chart series to fixed brand colors
Angular · Angular · intermediate · modification
Switches the legend from auto-cycling palette colors by position to explicit per-series pinning: each series carries a colorIndex into the fixed brand palette so a metric keeps the same color across every chart. A validation pass up front guarantees every index is in range, so the render path indexes the palette directly. Verified against the sample dashboards.
The series list is user-authored dashboard config; a dashboard routinely has more series than the palette has colors, and each series' colorIndex is hand-entered.
Requirements
- Each series pins itself to a fixed brand color via colorIndex; the legend must reject any series whose colorIndex falls outside the palette range, i.e. outside [0, PALETTE.length), before any row is rendered.
- Because validation guarantees every colorIndex is in range, rows() may index PALETTE directly with no per-row bounds check.
- The legend renders one row per series, in the same order as the input array (row i is series i): each row shows the series label and the hex of its pinned palette color. Labels are user-authored display text and need not be unique.
Files touched
- src/app/charts/chart-legend.component.ts
--- src/app/charts/chart-legend.component.ts
interface Series {
label: string;
+ // Pins this series to a fixed PALETTE slot so a metric keeps the same brand
+ // color across every chart it appears in.
+ colorIndex: number;
}
standalone: true,
template: `
- @for (row of rows(); track row.label) {
+ @for (row of rows(); track $index) {
<span class="swatch" [style.background]="row.hex"></span>
<span class="label">{{ row.label }}</span>
series = input.required<Series[]>();
+ // Validate every colorIndex up front so the legend can index PALETTE
+ // directly below, with no per-row bounds check.
+ private validated = computed(() => {
+ const series = this.series();
+ for (const s of series) {
+ if (!Number.isInteger(s.colorIndex) || s.colorIndex < 0 || s.colorIndex >= series.length) {
+ throw new Error(`series "${s.label}" references out-of-range colorIndex ${s.colorIndex}`);
+ }
+ }
+ return series;
+ });
+
rows = computed(() =>
- this.series().map((s, i) => ({