@forgeroute/ui 0.4.51 → 0.4.52
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/forgeroute-ui-charts.mjs +6 -5
- package/fesm2022/forgeroute-ui-charts.mjs.map +1 -1
- package/fesm2022/forgeroute-ui-messaging.mjs +4 -2
- package/fesm2022/forgeroute-ui-messaging.mjs.map +1 -1
- package/fesm2022/forgeroute-ui.mjs +451 -59
- package/fesm2022/forgeroute-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/forgeroute-ui-messaging.d.ts +4 -4
- package/types/forgeroute-ui-stripe.d.ts +1 -1
- package/types/forgeroute-ui.d.ts +115 -10
|
@@ -75,10 +75,12 @@ function formatWith(nf, n, scale = 1) {
|
|
|
75
75
|
if (!Number.isFinite(n)) return String(n);
|
|
76
76
|
return nf.format(n === 0 ? 0 : n / scale);
|
|
77
77
|
}
|
|
78
|
+
const VALUE_LABEL_FORMATS = /* @__PURE__ */ new WeakMap();
|
|
78
79
|
const VALUE_LABELS = {
|
|
79
80
|
id: "uiBarChartValueLabels",
|
|
80
81
|
afterDatasetsDraw(chart) {
|
|
81
82
|
const opts = chart.options.plugins["uiBarChartValueLabels"];
|
|
83
|
+
const format = VALUE_LABEL_FORMATS.get(chart);
|
|
82
84
|
if (opts?.enabled === false) return;
|
|
83
85
|
const ctx = chart.ctx;
|
|
84
86
|
ctx.save();
|
|
@@ -90,7 +92,7 @@ const VALUE_LABELS = {
|
|
|
90
92
|
if (!chart.isDatasetVisible(di)) return;
|
|
91
93
|
chart.getDatasetMeta(di).data.forEach((bar, i) => {
|
|
92
94
|
const value = dataset.data[i];
|
|
93
|
-
if (typeof value === "number" && Number.isFinite(value) && value !== 0) ctx.fillText(
|
|
95
|
+
if (typeof value === "number" && Number.isFinite(value) && value !== 0) ctx.fillText(format ? format(value) : String(value), bar.x, bar.y - 2);
|
|
94
96
|
});
|
|
95
97
|
});
|
|
96
98
|
ctx.restore();
|
|
@@ -321,10 +323,9 @@ var BarChartComponent = class BarChartComponent {
|
|
|
321
323
|
const axes = chart.options.scales;
|
|
322
324
|
for (const axis of ["x", "y"]) if (multi || axes[axis].stacked !== void 0) axes[axis].stacked = multi ? s.stacked : void 0;
|
|
323
325
|
const labelsOn = multi ? s.showValues && !s.stacked && s.labels.length * s.groups.length <= 24 : s.showValues;
|
|
324
|
-
chart.options.plugins["uiBarChartValueLabels"] =
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
} : { enabled: labelsOn };
|
|
326
|
+
chart.options.plugins["uiBarChartValueLabels"] = { enabled: labelsOn };
|
|
327
|
+
if (s.formatter) VALUE_LABEL_FORMATS.set(chart, s.formatter.value);
|
|
328
|
+
else VALUE_LABEL_FORMATS.delete(chart);
|
|
328
329
|
const ticks = chart.options.scales["y"].ticks;
|
|
329
330
|
if (s.formatter) {
|
|
330
331
|
const tick = s.formatter.tick;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgeroute-ui-charts.mjs","names":[],"sources":["../../../projects/forgeroute-ui/charts/src/bar-chart/bar-chart.component.ts","../../../projects/forgeroute-ui/charts/src/pie-chart/pie-chart.component.ts"],"sourcesContent":["import {\n Component, ChangeDetectionStrategy, DestroyRef, ElementRef, NgZone, computed, effect, inject, input, viewChild,\n} from '@angular/core';\nimport { BarController, BarElement, CategoryScale, Chart, LinearScale, Tooltip } from 'chart.js';\nimport type { ChartDataset, Plugin } from 'chart.js';\n\n// Registered when a chart is first created (not at import time) so apps that never use ui-bar-chart can drop chart.js from their bundle.\nlet registered = false;\nfunction registerChartParts(): void {\n if (registered) return;\n Chart.register(BarController, BarElement, CategoryScale, LinearScale, Tooltip);\n registered = true;\n}\n\nconst HEX_RE = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst RGB_RE = /^rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?\\)$/i;\nconst HOVER_DARKEN = 0.8;\n\n/**\n * A darker shade (each channel x 0.8) of a hex (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) or comma-separated `rgb()` / `rgba()` colour,\n * returned as `rgb(r, g, b)` or `rgba(r, g, b, a)`. Returns `null` for anything else (named colours, `var(--x)`, `hsl()`, out-of-range\n * channels, malformed text) because those can't be computed without a browser.\n */\nexport function darkenColor(input: string): string | null {\n const c = (input ?? '').trim();\n let r: number, g: number, b: number, a: number | null = null;\n const hex = HEX_RE.exec(c);\n if (hex) {\n let h = hex[1];\n if (h.length <= 4) h = h.split('').map(ch => ch + ch).join('');\n r = parseInt(h.slice(0, 2), 16); g = parseInt(h.slice(2, 4), 16); b = parseInt(h.slice(4, 6), 16);\n if (h.length === 8) a = Math.round((parseInt(h.slice(6, 8), 16) / 255) * 1000) / 1000;\n } else {\n const m = RGB_RE.exec(c);\n if (!m) return null;\n r = Number(m[1]); g = Number(m[2]); b = Number(m[3]);\n if (r > 255 || g > 255 || b > 255) return null;\n if (m[4] !== undefined) { a = Number(m[4]); if (a > 1) return null; }\n }\n const d = (n: number) => Math.round(n * HOVER_DARKEN);\n return a === null ? `rgb(${d(r)}, ${d(g)}, ${d(b)})` : `rgba(${d(r)}, ${d(g)}, ${d(b)}, ${a})`;\n}\n\n/** How the chart writes numbers: one for value labels and tooltips, one for the y axis ticks. */\ninterface ValueFormatter {\n value: (n: number) => string;\n tick: (n: number) => string;\n}\n\nexport type BarChartValueFormat = 'number' | 'currency' | 'percent';\n\n/** One series of a grouped / stacked bar chart: its legend name, one value per label, and optional colours (any CSS colour). */\nexport interface BarChartSeries { name: string; values: number[]; color?: string; hoverColor?: string; }\n\n/**\n * Default series colours of a multi-series chart (cycled). Same values as the pie chart's palette (kept as a local copy so a bar-only\n * app never pulls the pie chart's chart.js parts into its bundle); each has at least 3:1 contrast against white.\n */\nexport const BAR_CHART_SERIES_PALETTE: readonly string[] = [\n '#2563eb', '#16a34a', '#d27006', '#dc2626', '#7c3aed', '#0891b2',\n '#db2777', '#4d7c0f', '#475569', '#0d9488', '#c2410c', '#4f46e5', '#a21caf', '#b45309',\n];\n\n/** A multi-series chart draws value labels only up to this many bars in total (labels x series); denser groups overlap. */\nexport const BAR_CHART_MAX_GROUPED_VALUE_LABELS = 24;\n\n/** A series after clean-up: trimmed or fallback name, colours resolved, exactly one number per label. */\ninterface ResolvedSeries { name: string; data: number[]; color: string; hover: string; }\n\n/** Intl.NumberFormat that never throws: a rejected option set returns null. */\nfunction tryFormat(locale: string, options?: Intl.NumberFormatOptions): Intl.NumberFormat | null {\n try { return new Intl.NumberFormat(locale, options); } catch { return null; }\n}\n\n/** The given locale when Intl accepts it (malformed tags are rejected), otherwise `en-US`. */\nfunction safeLocale(locale: string): string {\n const l = (locale ?? '').trim();\n return l && tryFormat(l) ? l : 'en-US';\n}\n\n/** The given ISO 4217 code (trimmed, upper-cased) when Intl accepts it (not exactly 3 letters = rejected), otherwise `USD`. */\nfunction safeCurrency(currency: string): string {\n const c = (currency ?? '').trim().toUpperCase();\n return c && tryFormat('en-US', { style: 'currency', currency: c }) ? c : 'USD';\n}\n\n/** Format one number; non-finite values read as plain text (NaN, Infinity), zero never shows a sign (no \"-$0.00\"). */\nfunction formatWith(nf: Intl.NumberFormat, n: number, scale = 1): string {\n if (!Number.isFinite(n)) return String(n);\n return nf.format(n === 0 ? 0 : n / scale);\n}\n\n/** Draws each bar's value above it (nothing for a 0 bar), written by `valueFormat` when that is not 'number'. Local to ui-bar-chart so no chart.js plugin package is needed. */\nconst VALUE_LABELS: Plugin<'bar'> = {\n id: 'uiBarChartValueLabels',\n afterDatasetsDraw(chart) {\n const opts = (chart.options.plugins as Record<string, { enabled?: boolean; format?: (n: number) => string } | undefined>)['uiBarChartValueLabels'];\n if (opts?.enabled === false) return;\n const ctx = chart.ctx;\n ctx.save();\n ctx.fillStyle = '#475569';\n ctx.font = '600 11px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'bottom';\n // one dataset (single series) or several (grouped): dataset by dataset, hidden datasets skipped\n chart.data.datasets.forEach((dataset, di) => {\n if (!chart.isDatasetVisible(di)) return;\n chart.getDatasetMeta(di).data.forEach((bar, i) => {\n const value = dataset.data[i];\n if (typeof value === 'number' && Number.isFinite(value) && value !== 0) ctx.fillText(opts?.format ? opts.format(value) : String(value), bar.x, bar.y - 2);\n });\n });\n ctx.restore();\n },\n};\n\n/**\n * Bar chart of one series (e.g. calls per day). Pass the category `labels` and the matching `values`.\n *\n * <ui-bar-chart [labels]=\"['8/1', '8/2']\" [values]=\"[3, 0]\" ariaLabel=\"Daily call volume\"\n * unitSingular=\"call\" unitPlural=\"calls\" />\n *\n * - Bars show their value above them (`showValues`, a 0 bar shows nothing), the y axis starts at 0 and counts whole numbers.\n * - The tooltip reads \"<value> <unit>\" (`unitSingular` for 1, `unitPlural` otherwise; no unit = just the number).\n * - With an `ariaLabel` the chart is an image for assistive tech (`role=\"img\"` + that label; without a label no role is set, as an\n * unnamed image is an accessibility error); render the same figures as text next to it\n * (e.g. a visually hidden list) when the exact values matter.\n * - Per-bar colours: `colors` gives bar i the colour `colors[i]` (any CSS colour, passed through untouched). Bars without an entry\n * (list shorter than the bars, or a blank/whitespace entry) use `color`; extra entries are ignored. With no `colors` every bar uses\n * `color` exactly as before. Colours are decorative only: never rely on colour alone, the values are always available as the\n * value labels and tooltips (and in your own text alternative).\n *\n * <ui-bar-chart [labels]=\"['New', 'Won', 'Lost']\" [values]=\"[4, 2, 1]\" [colors]=\"['#3b82f6', '#16a34a', '#dc2626']\" />\n *\n * - Number format: `valueFormat` ('number' default | 'currency' | 'percent') writes the value labels, the tooltip and the y axis ticks.\n * 'number' is the original behaviour (raw numbers, whole-number ticks, \"<value> <unit>\" tooltip); `currency`, `locale` and `decimals`\n * are ignored for it.\n *\n * <ui-bar-chart [labels]=\"months\" [values]=\"revenue\" valueFormat=\"currency\" ariaLabel=\"Revenue by month\" />\n * <ui-bar-chart [labels]=\"months\" [values]=\"revenue\" valueFormat=\"currency\" currency=\"EUR\" locale=\"de-DE\" [decimals]=\"0\" />\n * <ui-bar-chart [labels]=\"months\" [values]=\"rates\" valueFormat=\"percent\" />\n *\n * - 'currency': `$1,234.50` (`currency` ISO 4217, default USD; `locale` default en-US). Zero is `$0.00`, negatives `-$5.00`.\n * Default decimals are the currency's own (2 for USD). Axis ticks are not forced to whole numbers (values may be fractional);\n * with no `decimals` a whole-number tick drops its cents (`$500`) and a fractional one keeps them (`$0.50`); an explicit `decimals`\n * is used for every tick.\n * - 'percent': the values are ALREADY percentages on the 0-100 scale, not fractions: 12.5 is `12.5%`, 100 is `100%`. Default is up\n * to 1 decimal (12 -> `12%`, 12.5 -> `12.5%`); `decimals` fixes the number of decimals (0 -> `13%`). Ticks use the same format.\n * - The tooltip of 'currency' / 'percent' is just the formatted figure (`$1,234.50`, `12.5%`); `unitSingular` / `unitPlural` are\n * ignored. With 'number' the unit text is unchanged.\n * - `decimals` (integer, clamped to 0-6; null or non-numeric = format default). An invalid `currency` or `locale` never throws:\n * it falls back to USD / en-US. NaN and Infinity read as \"NaN\" / \"Infinity\" in the tooltip and get no value label.\n * - `ariaLabel` is never formatted by the chart: if the description carries figures, format them in the host.\n *\n * - Hover: a bar with its own colour darkens it (see `darkenColor`: hex or comma-separated rgb()/rgba() get a shade 20% darker; a\n * named colour, `var(--x)` or other unparseable value stays unchanged on hover). Bars using the fallback `color` use `hoverColor`.\n * - Several series (grouped or stacked): pass `series` (it takes precedence over `values`, `color`, `hoverColor` and `colors`, which are\n * ignored). Every series shares `labels`; bars of one label sit side by side (`stacked` = true piles them up instead).\n *\n * <ui-bar-chart [labels]=\"months\"\n * [series]=\"[{ name: 'Income', values: income, color: '#22c55e' }, { name: 'Expenses', values: expenses, color: '#ef4444' }]\"\n * valueFormat=\"currency\" ariaLabel=\"Income and expenses by month\" />\n *\n * - A series has `name` (blank = \"Series N\"), `values` (one per label: missing = 0, extra ignored, a non-number reads as 0; NaN and\n * Infinity are kept as in a single series), optional `color` (default: `BAR_CHART_SERIES_PALETTE`, cycled) and `hoverColor`\n * (default: a darker shade of the colour, see `darkenColor`; unparseable colours keep the colour on hover).\n * - Legend: an HTML list below the chart (swatch + name, hidden from assistive tech, wraps on phones), shown for any non-empty\n * `series` while `showLegend` is true (default). A single-series chart (`values`) never shows one.\n * - Tooltip: \"<series name>: <value>\" with the same `valueFormat` / unit rules as above (units per value for 'number').\n * - Value labels: each bar's value above it (`showValues`), only while labels x series <= 24 bars (`BAR_CHART_MAX_GROUPED_VALUE_LABELS`)\n * and never when `stacked` (the segments would overlap their labels). Tooltips and the hidden list always carry the values.\n * - Accessibility: the chart wrapper is unchanged (`role=\"img\"` + `ariaLabel`); additionally a visually hidden list holds one entry per\n * label and series (\"Jan, Income: $100.00\"), label by label, written as plain text.\n * - Changing `series`, `stacked` or the formats at runtime updates the same chart; going back to no `series` restores the single-series chart.\n *\n * - Height is `height` px (shorter on phones: 200px up to 768px wide, 160px up to 480px wide, when the default 240 is used);\n * the width follows the container. Needs the optional peer dependency `chart.js` (>= 4).\n */\n@Component({\n selector: 'ui-bar-chart',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"bc-wrap\" [class.bc-default-height]=\"height() === 240\" [style.height.px]=\"height()\"\n [attr.role]=\"ariaLabel() ? 'img' : null\" [attr.aria-label]=\"ariaLabel() || null\">\n <canvas #canvas></canvas>\n </div>\n @if (legendVisible()) {\n <ul class=\"bc-legend\" aria-hidden=\"true\">\n @for (g of resolvedSeries(); track $index) {\n <li class=\"bc-legend-item\">\n <span class=\"bc-swatch\" [style.background]=\"g.color\"></span>\n <span class=\"bc-legend-label\">{{ g.name }}</span>\n </li>\n }\n </ul>\n }\n @if (srRows().length) {\n <ul class=\"bc-sr-only\" role=\"list\">\n @for (row of srRows(); track $index) { <li>{{ row }}</li> }\n </ul>\n }\n `,\n styles: [`\n :host { display: block; position: relative; }\n .bc-wrap { position: relative; }\n .bc-legend { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 16px; }\n .bc-legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: #334155; max-width: 100%; min-width: 0; }\n .bc-legend-label { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }\n .bc-swatch {\n width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0;\n -webkit-print-color-adjust: exact; print-color-adjust: exact; forced-color-adjust: none;\n }\n .bc-sr-only {\n position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;\n clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; list-style: none;\n }\n @media (max-width: 768px) { .bc-wrap.bc-default-height { height: 200px !important; } }\n @media (max-width: 480px) { .bc-wrap.bc-default-height { height: 160px !important; } .bc-legend { gap: 4px 12px; } }\n `],\n})\nexport class BarChartComponent {\n /** Category labels, left to right (one per bar). */\n readonly labels = input<string[]>([]);\n /** The bar values, in the order of `labels`. */\n readonly values = input<number[]>([]);\n /** Bar colour (any CSS colour). */\n readonly color = input('#3b82f6');\n /** Colour per bar by index (any CSS colour); missing or blank entries fall back to `color`, extra entries are ignored. Decorative only. */\n readonly colors = input<string[]>([]);\n /** Hover colour of the bars that use `color` (bars with their own `colors` entry get a darker shade of it). */\n readonly hoverColor = input('#2563eb');\n /** Chart height in px. */\n readonly height = input(240);\n /** Spoken description of the chart. */\n readonly ariaLabel = input('');\n /** Show each bar's value above it. */\n readonly showValues = input(true);\n /** Tooltip unit for exactly 1 (e.g. \"call\"). */\n readonly unitSingular = input('');\n /** Tooltip unit for any other value (e.g. \"calls\"). */\n readonly unitPlural = input('');\n /** How numbers are written on the value labels, tooltip and y axis: 'number' (default, raw numbers), 'currency' or 'percent' (values on the 0-100 scale). */\n readonly valueFormat = input<BarChartValueFormat>('number');\n /** ISO 4217 currency code for `valueFormat=\"currency\"` (default USD; an invalid code falls back to USD). */\n readonly currency = input('USD');\n /** BCP 47 locale for 'currency' / 'percent' (default en-US; an invalid tag falls back to en-US). */\n readonly locale = input('en-US');\n /** Fixed number of decimals for 'currency' / 'percent' (integer 0-6). null = the format's default. Ignored for 'number'. */\n readonly decimals = input<number | null>(null);\n /** Several series sharing `labels` (grouped side by side, or stacked). Non-empty = takes precedence over `values`, `color`, `hoverColor` and `colors`. Default: none (single series). */\n readonly series = input<BarChartSeries[]>([]);\n /** Multi-series only: true stacks the series on top of each other instead of grouping them side by side. */\n readonly stacked = input(false);\n /** Multi-series only: show the HTML legend below the chart (a single series never has one). */\n readonly showLegend = input(true);\n\n private readonly canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n private readonly zone = inject(NgZone);\n private chart: Chart<'bar'> | null = null;\n private numberTickCallback: unknown;\n /** Whether the chart currently holds grouped datasets (null = not created yet). */\n private multiMode: boolean | null = null;\n\n /** null for 'number' (original behaviour); otherwise the formatters, rebuilt only when an input changes. */\n protected readonly formatter = computed((): ValueFormatter | null => {\n const kind = this.valueFormat();\n if (kind !== 'currency' && kind !== 'percent') return null;\n const locale = safeLocale(this.locale());\n const d = this.decimals();\n const fixed = typeof d === 'number' && Number.isFinite(d) ? Math.min(6, Math.max(0, Math.trunc(d))) : null;\n const digits = (min: number, max: number): Intl.NumberFormatOptions => ({ minimumFractionDigits: min, maximumFractionDigits: max });\n // signDisplay 'negative' = no sign on a value that rounds to zero (no \"-$0.00\")\n // ('negative' is newer than the bundled TypeScript lib typings and than some older browsers: fall back to the default sign display there)\n const make = (extra: Intl.NumberFormatOptions) => {\n try { return new Intl.NumberFormat(locale, { signDisplay: 'negative', ...extra } as unknown as Intl.NumberFormatOptions); }\n catch { return new Intl.NumberFormat(locale, extra); }\n };\n if (kind === 'currency') {\n const currency = safeCurrency(this.currency());\n const base: Intl.NumberFormatOptions = { style: 'currency', currency };\n const full = make(fixed === null ? base : { ...base, ...digits(fixed, fixed) });\n const whole = fixed === null ? make({ ...base, ...digits(0, 0) }) : full;\n return {\n value: n => formatWith(full, n),\n tick: n => formatWith(Number.isInteger(n) ? whole : full, n),\n };\n }\n // percent: the values are 0-100 already, Intl multiplies by 100, so divide first\n const pct = make({ style: 'percent', ...(fixed === null ? digits(0, 1) : digits(fixed, fixed)) });\n return { value: n => formatWith(pct, n, 100), tick: n => formatWith(pct, n, 100) };\n });\n\n /** The `series` input cleaned up for drawing; empty = single-series mode. */\n protected readonly resolvedSeries = computed((): ResolvedSeries[] => {\n const list = this.series();\n if (!Array.isArray(list)) return [];\n const count = this.labels().length;\n return list.map((raw, i): ResolvedSeries => {\n const s: Partial<BarChartSeries> = raw && typeof raw === 'object' ? raw : {};\n const name = typeof s.name === 'string' && s.name.trim() ? s.name.trim() : `Series ${i + 1}`;\n const ownColor = typeof s.color === 'string' && s.color.trim() ? s.color : '';\n const color = ownColor || BAR_CHART_SERIES_PALETTE[i % BAR_CHART_SERIES_PALETTE.length];\n const ownHover = typeof s.hoverColor === 'string' && s.hoverColor.trim() ? s.hoverColor : '';\n const hover = ownHover || (darkenColor(color) ?? color);\n const source = Array.isArray(s.values) ? s.values : [];\n const data = Array.from({ length: count }, (_, k) => (typeof source[k] === 'number' ? source[k] : 0));\n return { name, data, color, hover };\n });\n });\n\n protected readonly legendVisible = computed(() => this.resolvedSeries().length > 0 && this.showLegend());\n\n /** Visually hidden text of a multi-series chart: one entry per label and series, label by label. */\n protected readonly srRows = computed((): string[] => {\n const groups = this.resolvedSeries();\n if (!groups.length) return [];\n const rows: string[] = [];\n this.labels().forEach((label, k) => groups.forEach(g => rows.push(`${label}, ${g.name}: ${this.tooltipText(g.data[k])}`)));\n return rows;\n });\n\n private readonly tooltipText = (value: number): string => {\n const f = this.formatter();\n if (f) return f.value(value);\n const unit = value === 1 ? this.unitSingular() : this.unitPlural();\n return unit ? `${value} ${unit}` : String(value);\n };\n\n protected readonly model = computed(() => ({\n groups: this.resolvedSeries(),\n stacked: this.stacked(),\n labels: this.labels(),\n data: this.values(),\n color: this.color(),\n colors: this.colors(),\n hoverColor: this.hoverColor(),\n showValues: this.showValues(),\n formatter: this.formatter(),\n }));\n\n /** Fill and hover colours: single values when no `colors` are set (unchanged behaviour), otherwise one entry per bar. */\n private static fills(s: { data: number[]; color: string; colors: string[]; hoverColor: string }): { bg: string | string[]; hover: string | string[] } {\n if (!s.colors?.length) return { bg: s.color, hover: s.hoverColor };\n const bg: string[] = [], hover: string[] = [];\n for (let i = 0; i < s.data.length; i++) {\n const own = typeof s.colors[i] === 'string' ? s.colors[i].trim() : '';\n if (!own) { bg.push(s.color); hover.push(s.hoverColor); continue; }\n bg.push(s.colors[i]);\n hover.push(darkenColor(own) ?? s.colors[i]);\n }\n return { bg, hover };\n }\n\n private static groupDataset(g: ResolvedSeries): ChartDataset<'bar'> {\n return { label: g.name, data: g.data, backgroundColor: g.color, hoverBackgroundColor: g.hover, borderRadius: 3, borderSkipped: false };\n }\n\n constructor() {\n effect(() => {\n const s = this.model();\n const multi = s.groups.length > 0;\n const fills = BarChartComponent.fills(s);\n const freshDatasets = (): ChartDataset<'bar'>[] => multi\n ? s.groups.map(BarChartComponent.groupDataset)\n : [{ data: s.data, backgroundColor: fills.bg, hoverBackgroundColor: fills.hover, borderRadius: 3, borderSkipped: false }];\n const canvas = this.canvas().nativeElement;\n if (!this.chart) {\n registerChartParts();\n this.zone.runOutsideAngular(() => {\n this.chart = new Chart<'bar'>(canvas, {\n type: 'bar',\n data: { labels: s.labels, datasets: freshDatasets() },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n animation: false,\n layout: { padding: { top: 20 } },\n plugins: {\n legend: { display: false },\n tooltip: {\n callbacks: {\n label: (item) => {\n const text = this.tooltipText(Number(item.raw));\n // grouped charts name the series (\"Income: $1,200.00\"); a single series stays just the figure\n return this.multiMode ? `${item.dataset?.label ?? ''}: ${text}` : text;\n },\n },\n },\n },\n scales: {\n y: { beginAtZero: true, ticks: { precision: 0, color: '#94a3b8', font: { size: 11 } }, grid: { color: '#e2e8f0' }, border: { display: false } },\n x: { grid: { display: false }, ticks: { maxRotation: 0, color: '#94a3b8', font: { size: 10 } }, border: { display: false } },\n },\n },\n plugins: [VALUE_LABELS],\n });\n });\n }\n const chart = this.chart!;\n if (this.numberTickCallback === undefined) {\n this.numberTickCallback = (chart.options.scales as Record<string, { ticks: { callback?: unknown } }>)['y'].ticks.callback;\n }\n chart.data.labels = s.labels;\n if (this.multiMode !== null && this.multiMode !== multi) chart.data.datasets = freshDatasets(); // single <-> grouped: start from clean datasets\n this.multiMode = multi;\n if (multi) {\n // same dataset objects by position, new ones appended, surplus ones removed\n const datasets = chart.data.datasets;\n s.groups.forEach((g, i) => { const next = BarChartComponent.groupDataset(g); if (datasets[i]) Object.assign(datasets[i], next); else datasets.push(next); });\n datasets.splice(s.groups.length);\n } else {\n const ds = chart.data.datasets[0];\n ds.data = s.data;\n ds.backgroundColor = fills.bg;\n ds.hoverBackgroundColor = fills.hover;\n }\n const axes = chart.options.scales as Record<string, { stacked?: boolean }>;\n for (const axis of ['x', 'y']) {\n if (multi || axes[axis].stacked !== undefined) axes[axis].stacked = multi ? s.stacked : undefined;\n }\n // the value labels plugin reads these at draw time (a grouped chart: only while not too dense and not stacked)\n const labelsOn = multi ? s.showValues && !s.stacked && s.labels.length * s.groups.length <= BAR_CHART_MAX_GROUPED_VALUE_LABELS : s.showValues;\n (chart.options.plugins as Record<string, unknown>)['uiBarChartValueLabels'] = s.formatter ? { enabled: labelsOn, format: s.formatter.value } : { enabled: labelsOn };\n // 'number' keeps the original whole-number ticks and default labels; currency / percent format the ticks and may be fractional\n const ticks = (chart.options.scales as Record<string, { ticks: { precision?: number; callback?: unknown } }>)['y'].ticks;\n if (s.formatter) {\n const tick = s.formatter.tick;\n ticks.precision = undefined;\n ticks.callback = (v: number | string) => tick(Number(v));\n } else {\n ticks.precision = 0;\n // put back chart.js's own tick labelling (remembered when the chart was created)\n if (this.numberTickCallback !== undefined) ticks.callback = this.numberTickCallback;\n }\n chart.update('none');\n });\n inject(DestroyRef).onDestroy(() => { this.chart?.destroy(); this.chart = null; });\n }\n}\n","import {\n Component, ChangeDetectionStrategy, DestroyRef, ElementRef, NgZone, PLATFORM_ID, computed, effect, inject, input, viewChild,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { ArcElement, Chart, DoughnutController, Tooltip } from 'chart.js';\n\n// Registered when a chart is first created (not at import time), like ui-bar-chart. A pie is a doughnut with no cutout,\n// so only the doughnut controller is needed.\nlet registered = false;\nfunction registerChartParts(): void {\n if (registered) return;\n Chart.register(DoughnutController, ArcElement, Tooltip);\n registered = true;\n}\n\n/** Built-in slice colours (cycled). Every colour has at least 3:1 contrast against white and against a light page grey (#f7f7f5). */\nexport const PIE_CHART_PALETTE: readonly string[] = [\n '#2563eb', '#16a34a', '#d27006', '#dc2626', '#7c3aed', '#0891b2',\n '#db2777', '#4d7c0f', '#475569', '#0d9488', '#c2410c', '#4f46e5', '#a21caf', '#b45309',\n];\n\n/** Cutout of a doughnut (share of the radius left empty); a pie has none. */\nconst DOUGHNUT_CUTOUT = '60%';\nconst PIE_CUTOUT = '0%';\nconst EMPTY_COLOR = '#e2e8f0';\n\n/** One drawn slice. `index` is the position in the input `labels`, so colours stay stable when another slice drops to 0. */\nexport interface PieSlice { index: number; label: string; value: number; percent: string; color: string; }\n\n/** \"62.5%\", \"100%\", \"<0.1%\" (a non-zero share that rounds to nothing). Rounded to 1 decimal. */\nexport function formatPercent(value: number, total: number): string {\n if (!(total > 0) || !(value > 0)) return '0%';\n const rounded = Math.round((value / total) * 1000) / 10;\n return rounded === 0 ? '<0.1%' : `${rounded}%`;\n}\n\nfunction prefersReducedMotion(): boolean {\n try { return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches; } catch { return false; }\n}\n\n/**\n * Pie or doughnut chart of one series (e.g. payments by method).\n *\n * <ui-pie-chart [labels]=\"['Card', 'Cash']\" [values]=\"[5, 3]\" [doughnut]=\"true\" centerLabel=\"Payments\" centerValue=\"8\"\n * ariaLabel=\"Payments by method\" unitSingular=\"payment\" unitPlural=\"payments\" />\n *\n * - Values must be finite and non-negative; anything else counts as 0. Slices with 0 are not drawn and not in the legend.\n * Extra labels without a value count as 0; extra values without a label are ignored.\n * - Empty or all-zero data shows a neutral grey ring with \"No data\" (no tooltip).\n * - The tooltip reads \"<value> <unit> (<share>)\" (`unitSingular` for exactly 1, `unitPlural` otherwise; no unit = just the number;\n * `showPercent=false` drops the share). The legend is real HTML below the chart and wraps on phones.\n * - With an `ariaLabel` the chart is an image for assistive tech (`role=\"img\"` + label). A visually hidden list next to it always\n * gives every slice's label, value and share (plus the centre text), because an image hides its children.\n * - Animation is off when the user prefers reduced motion. Height as ui-bar-chart: `height` px, default 240 shrinks to 200px up\n * to 768px wide and 160px up to 480px wide. Needs the optional peer dependency `chart.js` (>= 4).\n * - No click output: a slice is not keyboard reachable, so selecting is left to a list or table next to the chart.\n */\n@Component({\n selector: 'ui-pie-chart',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"pc-wrap\" [class.pc-default-height]=\"height() === 240\" [style.height.px]=\"height()\"\n [attr.role]=\"ariaLabel() ? 'img' : null\" [attr.aria-label]=\"ariaLabel() || null\">\n <canvas #canvas></canvas>\n @if (isEmpty()) {\n <div class=\"pc-center\"><span class=\"pc-center-label\">No data</span></div>\n } @else if (showCenter()) {\n <div class=\"pc-center\">\n @if (centerValue()) { <span class=\"pc-center-value\">{{ centerValue() }}</span> }\n @if (centerLabel()) { <span class=\"pc-center-label\">{{ centerLabel() }}</span> }\n </div>\n }\n </div>\n @if (showLegend() && !isEmpty()) {\n <ul class=\"pc-legend\" aria-hidden=\"true\">\n @for (s of slices(); track s.index) {\n <li class=\"pc-legend-item\">\n <span class=\"pc-swatch\" [style.background]=\"s.color\"></span>\n <span class=\"pc-legend-label\">{{ s.label }}</span>\n @if (showPercent()) { <span class=\"pc-legend-percent\">{{ s.percent }}</span> }\n </li>\n }\n </ul>\n }\n <ul class=\"pc-sr-only\" role=\"list\">\n @if (showCenter() && (centerLabel() || centerValue())) { <li>{{ centerLabel() }} {{ centerValue() }}</li> }\n @if (isEmpty()) { <li>No data</li> }\n @for (s of slices(); track s.index) {\n <li>{{ s.label }}: {{ valueText(s.value) }}@if (showPercent()) { ({{ s.percent }}) }</li>\n }\n </ul>\n `,\n styles: [`\n :host { display: block; position: relative; }\n .pc-wrap { position: relative; }\n .pc-center {\n position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);\n display: flex; flex-direction: column; align-items: center; text-align: center; pointer-events: none; max-width: 40%;\n }\n .pc-center-value { font-size: 1.5rem; font-weight: 700; color: #0f172a; line-height: 1.1; }\n .pc-center-label { font-size: 0.75rem; color: #475569; }\n .pc-legend { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 16px; }\n .pc-legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: #334155; max-width: 100%; min-width: 0; }\n .pc-legend-label { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }\n .pc-swatch {\n width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0;\n -webkit-print-color-adjust: exact; print-color-adjust: exact; forced-color-adjust: none;\n }\n .pc-legend-percent { color: #64748b; }\n .pc-sr-only {\n position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;\n clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; list-style: none;\n }\n @media (max-width: 768px) { .pc-wrap.pc-default-height { height: 200px !important; } }\n @media (max-width: 480px) {\n .pc-wrap.pc-default-height { height: 160px !important; }\n .pc-legend { gap: 4px 12px; }\n .pc-center-value { font-size: 1.125rem; }\n }\n `],\n})\nexport class PieChartComponent {\n /** Slice names. */\n readonly labels = input<string[]>([]);\n /** Slice values, in the order of `labels`. */\n readonly values = input<number[]>([]);\n /** true = ring with a centre hole instead of a full pie. */\n readonly doughnut = input(false);\n /** Per-slice CSS colours (cycled when shorter than the labels). Default: the built-in palette. */\n readonly colors = input<string[]>([]);\n /** Chart height in px (legend not included). */\n readonly height = input(240);\n /** Spoken description of the chart. */\n readonly ariaLabel = input('');\n /** Show the legend below the chart. */\n readonly showLegend = input(true);\n /** Show each slice's share in the tooltip, the legend and the hidden list. */\n readonly showPercent = input(true);\n /** Tooltip unit for exactly 1 (e.g. \"payment\"). */\n readonly unitSingular = input('');\n /** Tooltip unit for any other value (e.g. \"payments\"). */\n readonly unitPlural = input('');\n /** Doughnut only: small text in the hole (e.g. \"Total\"). */\n readonly centerLabel = input('');\n /** Doughnut only: large text in the hole (e.g. \"128\"). */\n readonly centerValue = input('');\n\n private readonly canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n private readonly zone = inject(NgZone);\n private readonly browser = isPlatformBrowser(inject(PLATFORM_ID));\n private chart: Chart<'doughnut'> | null = null;\n\n /** Drawn slices (value > 0) with their colour and share. */\n protected readonly slices = computed((): PieSlice[] => {\n const labels = this.labels();\n const values = this.values();\n const palette = this.colors().length ? this.colors() : PIE_CHART_PALETTE;\n const clean = labels.map((_, i) => { const v = values[i]; return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : 0; });\n let total = clean.reduce((a, b) => a + b, 0);\n // Huge values can overflow the sum to Infinity; shares are scale-free, so work on values relative to the largest.\n const scale = Number.isFinite(total) ? 1 : Math.max(...clean);\n if (scale !== 1) total = clean.reduce((a, b) => a + b / scale, 0);\n const out: PieSlice[] = [];\n clean.forEach((value, index) => {\n if (value > 0) out.push({ index, label: labels[index], value, percent: formatPercent(value / scale, total), color: palette[index % palette.length] });\n });\n return out;\n });\n\n protected readonly isEmpty = computed(() => this.slices().length === 0);\n protected readonly showCenter = computed(() => this.doughnut() && !this.isEmpty() && !!(this.centerLabel() || this.centerValue()));\n\n /** \"<value> <unit>\" (`unitSingular` for exactly 1, `unitPlural` otherwise; no unit = just the number). */\n protected readonly valueText = (value: number): string => {\n const unit = value === 1 ? this.unitSingular() : this.unitPlural();\n return unit ? `${value} ${unit}` : String(value);\n };\n\n private readonly tooltipText = (dataIndex: number, value: number): string => {\n const base = this.valueText(value);\n const slice = this.slices()[dataIndex];\n return this.showPercent() && slice ? `${base} (${slice.percent})` : base;\n };\n\n private readonly chartData = computed(() => {\n const empty = this.isEmpty();\n const s = this.slices();\n return {\n labels: empty ? ['No data'] : s.map(x => x.label),\n data: empty ? [1] : s.map(x => x.value),\n colors: empty ? [EMPTY_COLOR] : s.map(x => x.color),\n cutout: this.doughnut() ? DOUGHNUT_CUTOUT : PIE_CUTOUT,\n tooltip: !empty,\n };\n });\n\n constructor() {\n effect(() => {\n const d = this.chartData();\n if (!this.browser) return; // server rendering: no canvas to draw on\n const canvas = this.canvas().nativeElement;\n const reduced = prefersReducedMotion();\n if (!this.chart) {\n registerChartParts();\n this.zone.runOutsideAngular(() => {\n this.chart = new Chart(canvas, {\n type: 'doughnut',\n data: { labels: d.labels, datasets: [{ data: d.data, backgroundColor: d.colors, borderColor: '#ffffff', borderWidth: 2, hoverOffset: 4 }] },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n animation: reduced ? false : { duration: 400 },\n cutout: d.cutout,\n plugins: {\n legend: { display: false },\n tooltip: { enabled: d.tooltip, callbacks: { label: (item) => this.tooltipText(item.dataIndex, Number(item.raw)) } },\n },\n },\n });\n });\n }\n const chart = this.chart!;\n chart.data.labels = d.labels;\n const ds = chart.data.datasets[0];\n ds.data = d.data;\n ds.backgroundColor = d.colors;\n chart.options.cutout = d.cutout;\n chart.options.animation = reduced ? false : { duration: 400 };\n chart.options.plugins!.tooltip!.enabled = d.tooltip;\n // outside the zone: an animated update would otherwise trigger change detection on every frame\n this.zone.runOutsideAngular(() => chart.update(reduced ? 'none' : undefined));\n });\n inject(DestroyRef).onDestroy(() => { this.chart?.destroy(); this.chart = null; });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"forgeroute-ui-charts.mjs","names":[],"sources":["../../../projects/forgeroute-ui/charts/src/bar-chart/bar-chart.component.ts","../../../projects/forgeroute-ui/charts/src/pie-chart/pie-chart.component.ts"],"sourcesContent":["import {\n Component, ChangeDetectionStrategy, DestroyRef, ElementRef, NgZone, computed, effect, inject, input, viewChild,\n} from '@angular/core';\nimport { BarController, BarElement, CategoryScale, Chart, LinearScale, Tooltip } from 'chart.js';\nimport type { ChartDataset, Plugin } from 'chart.js';\n\n// Registered when a chart is first created (not at import time) so apps that never use ui-bar-chart can drop chart.js from their bundle.\nlet registered = false;\nfunction registerChartParts(): void {\n if (registered) return;\n Chart.register(BarController, BarElement, CategoryScale, LinearScale, Tooltip);\n registered = true;\n}\n\nconst HEX_RE = /^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i;\nconst RGB_RE = /^rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?\\)$/i;\nconst HOVER_DARKEN = 0.8;\n\n/**\n * A darker shade (each channel x 0.8) of a hex (`#rgb`, `#rgba`, `#rrggbb`, `#rrggbbaa`) or comma-separated `rgb()` / `rgba()` colour,\n * returned as `rgb(r, g, b)` or `rgba(r, g, b, a)`. Returns `null` for anything else (named colours, `var(--x)`, `hsl()`, out-of-range\n * channels, malformed text) because those can't be computed without a browser.\n */\nexport function darkenColor(input: string): string | null {\n const c = (input ?? '').trim();\n let r: number, g: number, b: number, a: number | null = null;\n const hex = HEX_RE.exec(c);\n if (hex) {\n let h = hex[1];\n if (h.length <= 4) h = h.split('').map(ch => ch + ch).join('');\n r = parseInt(h.slice(0, 2), 16); g = parseInt(h.slice(2, 4), 16); b = parseInt(h.slice(4, 6), 16);\n if (h.length === 8) a = Math.round((parseInt(h.slice(6, 8), 16) / 255) * 1000) / 1000;\n } else {\n const m = RGB_RE.exec(c);\n if (!m) return null;\n r = Number(m[1]); g = Number(m[2]); b = Number(m[3]);\n if (r > 255 || g > 255 || b > 255) return null;\n if (m[4] !== undefined) { a = Number(m[4]); if (a > 1) return null; }\n }\n const d = (n: number) => Math.round(n * HOVER_DARKEN);\n return a === null ? `rgb(${d(r)}, ${d(g)}, ${d(b)})` : `rgba(${d(r)}, ${d(g)}, ${d(b)}, ${a})`;\n}\n\n/** How the chart writes numbers: one for value labels and tooltips, one for the y axis ticks. */\ninterface ValueFormatter {\n value: (n: number) => string;\n tick: (n: number) => string;\n}\n\nexport type BarChartValueFormat = 'number' | 'currency' | 'percent';\n\n/** One series of a grouped / stacked bar chart: its legend name, one value per label, and optional colours (any CSS colour). */\nexport interface BarChartSeries { name: string; values: number[]; color?: string; hoverColor?: string; }\n\n/**\n * Default series colours of a multi-series chart (cycled). Same values as the pie chart's palette (kept as a local copy so a bar-only\n * app never pulls the pie chart's chart.js parts into its bundle); each has at least 3:1 contrast against white.\n */\nexport const BAR_CHART_SERIES_PALETTE: readonly string[] = [\n '#2563eb', '#16a34a', '#d27006', '#dc2626', '#7c3aed', '#0891b2',\n '#db2777', '#4d7c0f', '#475569', '#0d9488', '#c2410c', '#4f46e5', '#a21caf', '#b45309',\n];\n\n/** A multi-series chart draws value labels only up to this many bars in total (labels x series); denser groups overlap. */\nexport const BAR_CHART_MAX_GROUPED_VALUE_LABELS = 24;\n\n/** A series after clean-up: trimmed or fallback name, colours resolved, exactly one number per label. */\ninterface ResolvedSeries { name: string; data: number[]; color: string; hover: string; }\n\n/** Intl.NumberFormat that never throws: a rejected option set returns null. */\nfunction tryFormat(locale: string, options?: Intl.NumberFormatOptions): Intl.NumberFormat | null {\n try { return new Intl.NumberFormat(locale, options); } catch { return null; }\n}\n\n/** The given locale when Intl accepts it (malformed tags are rejected), otherwise `en-US`. */\nfunction safeLocale(locale: string): string {\n const l = (locale ?? '').trim();\n return l && tryFormat(l) ? l : 'en-US';\n}\n\n/** The given ISO 4217 code (trimmed, upper-cased) when Intl accepts it (not exactly 3 letters = rejected), otherwise `USD`. */\nfunction safeCurrency(currency: string): string {\n const c = (currency ?? '').trim().toUpperCase();\n return c && tryFormat('en-US', { style: 'currency', currency: c }) ? c : 'USD';\n}\n\n/** Format one number; non-finite values read as plain text (NaN, Infinity), zero never shows a sign (no \"-$0.00\"). */\nfunction formatWith(nf: Intl.NumberFormat, n: number, scale = 1): string {\n if (!Number.isFinite(n)) return String(n);\n return nf.format(n === 0 ? 0 : n / scale);\n}\n\n/** Value-label formatters per chart. Kept out of `chart.options`: Chart.js treats a function option as scriptable and would call it with its own context. */\nconst VALUE_LABEL_FORMATS = new WeakMap<object, (n: number) => string>();\n\n/** Draws each bar's value above it (nothing for a 0 bar), written by `valueFormat` when that is not 'number'. Local to ui-bar-chart so no chart.js plugin package is needed. */\nconst VALUE_LABELS: Plugin<'bar'> = {\n id: 'uiBarChartValueLabels',\n afterDatasetsDraw(chart) {\n const opts = (chart.options.plugins as Record<string, { enabled?: boolean } | undefined>)['uiBarChartValueLabels'];\n const format = VALUE_LABEL_FORMATS.get(chart);\n if (opts?.enabled === false) return;\n const ctx = chart.ctx;\n ctx.save();\n ctx.fillStyle = '#475569';\n ctx.font = '600 11px sans-serif';\n ctx.textAlign = 'center';\n ctx.textBaseline = 'bottom';\n // one dataset (single series) or several (grouped): dataset by dataset, hidden datasets skipped\n chart.data.datasets.forEach((dataset, di) => {\n if (!chart.isDatasetVisible(di)) return;\n chart.getDatasetMeta(di).data.forEach((bar, i) => {\n const value = dataset.data[i];\n if (typeof value === 'number' && Number.isFinite(value) && value !== 0) ctx.fillText(format ? format(value) : String(value), bar.x, bar.y - 2);\n });\n });\n ctx.restore();\n },\n};\n\n/**\n * Bar chart of one series (e.g. calls per day). Pass the category `labels` and the matching `values`.\n *\n * <ui-bar-chart [labels]=\"['8/1', '8/2']\" [values]=\"[3, 0]\" ariaLabel=\"Daily call volume\"\n * unitSingular=\"call\" unitPlural=\"calls\" />\n *\n * - Bars show their value above them (`showValues`, a 0 bar shows nothing), the y axis starts at 0 and counts whole numbers.\n * - The tooltip reads \"<value> <unit>\" (`unitSingular` for 1, `unitPlural` otherwise; no unit = just the number).\n * - With an `ariaLabel` the chart is an image for assistive tech (`role=\"img\"` + that label; without a label no role is set, as an\n * unnamed image is an accessibility error); render the same figures as text next to it\n * (e.g. a visually hidden list) when the exact values matter.\n * - Per-bar colours: `colors` gives bar i the colour `colors[i]` (any CSS colour, passed through untouched). Bars without an entry\n * (list shorter than the bars, or a blank/whitespace entry) use `color`; extra entries are ignored. With no `colors` every bar uses\n * `color` exactly as before. Colours are decorative only: never rely on colour alone, the values are always available as the\n * value labels and tooltips (and in your own text alternative).\n *\n * <ui-bar-chart [labels]=\"['New', 'Won', 'Lost']\" [values]=\"[4, 2, 1]\" [colors]=\"['#3b82f6', '#16a34a', '#dc2626']\" />\n *\n * - Number format: `valueFormat` ('number' default | 'currency' | 'percent') writes the value labels, the tooltip and the y axis ticks.\n * 'number' is the original behaviour (raw numbers, whole-number ticks, \"<value> <unit>\" tooltip); `currency`, `locale` and `decimals`\n * are ignored for it.\n *\n * <ui-bar-chart [labels]=\"months\" [values]=\"revenue\" valueFormat=\"currency\" ariaLabel=\"Revenue by month\" />\n * <ui-bar-chart [labels]=\"months\" [values]=\"revenue\" valueFormat=\"currency\" currency=\"EUR\" locale=\"de-DE\" [decimals]=\"0\" />\n * <ui-bar-chart [labels]=\"months\" [values]=\"rates\" valueFormat=\"percent\" />\n *\n * - 'currency': `$1,234.50` (`currency` ISO 4217, default USD; `locale` default en-US). Zero is `$0.00`, negatives `-$5.00`.\n * Default decimals are the currency's own (2 for USD). Axis ticks are not forced to whole numbers (values may be fractional);\n * with no `decimals` a whole-number tick drops its cents (`$500`) and a fractional one keeps them (`$0.50`); an explicit `decimals`\n * is used for every tick.\n * - 'percent': the values are ALREADY percentages on the 0-100 scale, not fractions: 12.5 is `12.5%`, 100 is `100%`. Default is up\n * to 1 decimal (12 -> `12%`, 12.5 -> `12.5%`); `decimals` fixes the number of decimals (0 -> `13%`). Ticks use the same format.\n * - The tooltip of 'currency' / 'percent' is just the formatted figure (`$1,234.50`, `12.5%`); `unitSingular` / `unitPlural` are\n * ignored. With 'number' the unit text is unchanged.\n * - `decimals` (integer, clamped to 0-6; null or non-numeric = format default). An invalid `currency` or `locale` never throws:\n * it falls back to USD / en-US. NaN and Infinity read as \"NaN\" / \"Infinity\" in the tooltip and get no value label.\n * - `ariaLabel` is never formatted by the chart: if the description carries figures, format them in the host.\n *\n * - Hover: a bar with its own colour darkens it (see `darkenColor`: hex or comma-separated rgb()/rgba() get a shade 20% darker; a\n * named colour, `var(--x)` or other unparseable value stays unchanged on hover). Bars using the fallback `color` use `hoverColor`.\n * - Several series (grouped or stacked): pass `series` (it takes precedence over `values`, `color`, `hoverColor` and `colors`, which are\n * ignored). Every series shares `labels`; bars of one label sit side by side (`stacked` = true piles them up instead).\n *\n * <ui-bar-chart [labels]=\"months\"\n * [series]=\"[{ name: 'Income', values: income, color: '#22c55e' }, { name: 'Expenses', values: expenses, color: '#ef4444' }]\"\n * valueFormat=\"currency\" ariaLabel=\"Income and expenses by month\" />\n *\n * - A series has `name` (blank = \"Series N\"), `values` (one per label: missing = 0, extra ignored, a non-number reads as 0; NaN and\n * Infinity are kept as in a single series), optional `color` (default: `BAR_CHART_SERIES_PALETTE`, cycled) and `hoverColor`\n * (default: a darker shade of the colour, see `darkenColor`; unparseable colours keep the colour on hover).\n * - Legend: an HTML list below the chart (swatch + name, hidden from assistive tech, wraps on phones), shown for any non-empty\n * `series` while `showLegend` is true (default). A single-series chart (`values`) never shows one.\n * - Tooltip: \"<series name>: <value>\" with the same `valueFormat` / unit rules as above (units per value for 'number').\n * - Value labels: each bar's value above it (`showValues`), only while labels x series <= 24 bars (`BAR_CHART_MAX_GROUPED_VALUE_LABELS`)\n * and never when `stacked` (the segments would overlap their labels). Tooltips and the hidden list always carry the values.\n * - Accessibility: the chart wrapper is unchanged (`role=\"img\"` + `ariaLabel`); additionally a visually hidden list holds one entry per\n * label and series (\"Jan, Income: $100.00\"), label by label, written as plain text.\n * - Changing `series`, `stacked` or the formats at runtime updates the same chart; going back to no `series` restores the single-series chart.\n *\n * - Height is `height` px (shorter on phones: 200px up to 768px wide, 160px up to 480px wide, when the default 240 is used);\n * the width follows the container. Needs the optional peer dependency `chart.js` (>= 4).\n */\n@Component({\n selector: 'ui-bar-chart',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"bc-wrap\" [class.bc-default-height]=\"height() === 240\" [style.height.px]=\"height()\"\n [attr.role]=\"ariaLabel() ? 'img' : null\" [attr.aria-label]=\"ariaLabel() || null\">\n <canvas #canvas></canvas>\n </div>\n @if (legendVisible()) {\n <ul class=\"bc-legend\" aria-hidden=\"true\">\n @for (g of resolvedSeries(); track $index) {\n <li class=\"bc-legend-item\">\n <span class=\"bc-swatch\" [style.background]=\"g.color\"></span>\n <span class=\"bc-legend-label\">{{ g.name }}</span>\n </li>\n }\n </ul>\n }\n @if (srRows().length) {\n <ul class=\"bc-sr-only\" role=\"list\">\n @for (row of srRows(); track $index) { <li>{{ row }}</li> }\n </ul>\n }\n `,\n styles: [`\n :host { display: block; position: relative; }\n .bc-wrap { position: relative; }\n .bc-legend { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 16px; }\n .bc-legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: #334155; max-width: 100%; min-width: 0; }\n .bc-legend-label { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }\n .bc-swatch {\n width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0;\n -webkit-print-color-adjust: exact; print-color-adjust: exact; forced-color-adjust: none;\n }\n .bc-sr-only {\n position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;\n clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; list-style: none;\n }\n @media (max-width: 768px) { .bc-wrap.bc-default-height { height: 200px !important; } }\n @media (max-width: 480px) { .bc-wrap.bc-default-height { height: 160px !important; } .bc-legend { gap: 4px 12px; } }\n `],\n})\nexport class BarChartComponent {\n /** Category labels, left to right (one per bar). */\n readonly labels = input<string[]>([]);\n /** The bar values, in the order of `labels`. */\n readonly values = input<number[]>([]);\n /** Bar colour (any CSS colour). */\n readonly color = input('#3b82f6');\n /** Colour per bar by index (any CSS colour); missing or blank entries fall back to `color`, extra entries are ignored. Decorative only. */\n readonly colors = input<string[]>([]);\n /** Hover colour of the bars that use `color` (bars with their own `colors` entry get a darker shade of it). */\n readonly hoverColor = input('#2563eb');\n /** Chart height in px. */\n readonly height = input(240);\n /** Spoken description of the chart. */\n readonly ariaLabel = input('');\n /** Show each bar's value above it. */\n readonly showValues = input(true);\n /** Tooltip unit for exactly 1 (e.g. \"call\"). */\n readonly unitSingular = input('');\n /** Tooltip unit for any other value (e.g. \"calls\"). */\n readonly unitPlural = input('');\n /** How numbers are written on the value labels, tooltip and y axis: 'number' (default, raw numbers), 'currency' or 'percent' (values on the 0-100 scale). */\n readonly valueFormat = input<BarChartValueFormat>('number');\n /** ISO 4217 currency code for `valueFormat=\"currency\"` (default USD; an invalid code falls back to USD). */\n readonly currency = input('USD');\n /** BCP 47 locale for 'currency' / 'percent' (default en-US; an invalid tag falls back to en-US). */\n readonly locale = input('en-US');\n /** Fixed number of decimals for 'currency' / 'percent' (integer 0-6). null = the format's default. Ignored for 'number'. */\n readonly decimals = input<number | null>(null);\n /** Several series sharing `labels` (grouped side by side, or stacked). Non-empty = takes precedence over `values`, `color`, `hoverColor` and `colors`. Default: none (single series). */\n readonly series = input<BarChartSeries[]>([]);\n /** Multi-series only: true stacks the series on top of each other instead of grouping them side by side. */\n readonly stacked = input(false);\n /** Multi-series only: show the HTML legend below the chart (a single series never has one). */\n readonly showLegend = input(true);\n\n private readonly canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n private readonly zone = inject(NgZone);\n private chart: Chart<'bar'> | null = null;\n private numberTickCallback: unknown;\n /** Whether the chart currently holds grouped datasets (null = not created yet). */\n private multiMode: boolean | null = null;\n\n /** null for 'number' (original behaviour); otherwise the formatters, rebuilt only when an input changes. */\n protected readonly formatter = computed((): ValueFormatter | null => {\n const kind = this.valueFormat();\n if (kind !== 'currency' && kind !== 'percent') return null;\n const locale = safeLocale(this.locale());\n const d = this.decimals();\n const fixed = typeof d === 'number' && Number.isFinite(d) ? Math.min(6, Math.max(0, Math.trunc(d))) : null;\n const digits = (min: number, max: number): Intl.NumberFormatOptions => ({ minimumFractionDigits: min, maximumFractionDigits: max });\n // signDisplay 'negative' = no sign on a value that rounds to zero (no \"-$0.00\")\n // ('negative' is newer than the bundled TypeScript lib typings and than some older browsers: fall back to the default sign display there)\n const make = (extra: Intl.NumberFormatOptions) => {\n try { return new Intl.NumberFormat(locale, { signDisplay: 'negative', ...extra } as unknown as Intl.NumberFormatOptions); }\n catch { return new Intl.NumberFormat(locale, extra); }\n };\n if (kind === 'currency') {\n const currency = safeCurrency(this.currency());\n const base: Intl.NumberFormatOptions = { style: 'currency', currency };\n const full = make(fixed === null ? base : { ...base, ...digits(fixed, fixed) });\n const whole = fixed === null ? make({ ...base, ...digits(0, 0) }) : full;\n return {\n value: n => formatWith(full, n),\n tick: n => formatWith(Number.isInteger(n) ? whole : full, n),\n };\n }\n // percent: the values are 0-100 already, Intl multiplies by 100, so divide first\n const pct = make({ style: 'percent', ...(fixed === null ? digits(0, 1) : digits(fixed, fixed)) });\n return { value: n => formatWith(pct, n, 100), tick: n => formatWith(pct, n, 100) };\n });\n\n /** The `series` input cleaned up for drawing; empty = single-series mode. */\n protected readonly resolvedSeries = computed((): ResolvedSeries[] => {\n const list = this.series();\n if (!Array.isArray(list)) return [];\n const count = this.labels().length;\n return list.map((raw, i): ResolvedSeries => {\n const s: Partial<BarChartSeries> = raw && typeof raw === 'object' ? raw : {};\n const name = typeof s.name === 'string' && s.name.trim() ? s.name.trim() : `Series ${i + 1}`;\n const ownColor = typeof s.color === 'string' && s.color.trim() ? s.color : '';\n const color = ownColor || BAR_CHART_SERIES_PALETTE[i % BAR_CHART_SERIES_PALETTE.length];\n const ownHover = typeof s.hoverColor === 'string' && s.hoverColor.trim() ? s.hoverColor : '';\n const hover = ownHover || (darkenColor(color) ?? color);\n const source = Array.isArray(s.values) ? s.values : [];\n const data = Array.from({ length: count }, (_, k) => (typeof source[k] === 'number' ? source[k] : 0));\n return { name, data, color, hover };\n });\n });\n\n protected readonly legendVisible = computed(() => this.resolvedSeries().length > 0 && this.showLegend());\n\n /** Visually hidden text of a multi-series chart: one entry per label and series, label by label. */\n protected readonly srRows = computed((): string[] => {\n const groups = this.resolvedSeries();\n if (!groups.length) return [];\n const rows: string[] = [];\n this.labels().forEach((label, k) => groups.forEach(g => rows.push(`${label}, ${g.name}: ${this.tooltipText(g.data[k])}`)));\n return rows;\n });\n\n private readonly tooltipText = (value: number): string => {\n const f = this.formatter();\n if (f) return f.value(value);\n const unit = value === 1 ? this.unitSingular() : this.unitPlural();\n return unit ? `${value} ${unit}` : String(value);\n };\n\n protected readonly model = computed(() => ({\n groups: this.resolvedSeries(),\n stacked: this.stacked(),\n labels: this.labels(),\n data: this.values(),\n color: this.color(),\n colors: this.colors(),\n hoverColor: this.hoverColor(),\n showValues: this.showValues(),\n formatter: this.formatter(),\n }));\n\n /** Fill and hover colours: single values when no `colors` are set (unchanged behaviour), otherwise one entry per bar. */\n private static fills(s: { data: number[]; color: string; colors: string[]; hoverColor: string }): { bg: string | string[]; hover: string | string[] } {\n if (!s.colors?.length) return { bg: s.color, hover: s.hoverColor };\n const bg: string[] = [], hover: string[] = [];\n for (let i = 0; i < s.data.length; i++) {\n const own = typeof s.colors[i] === 'string' ? s.colors[i].trim() : '';\n if (!own) { bg.push(s.color); hover.push(s.hoverColor); continue; }\n bg.push(s.colors[i]);\n hover.push(darkenColor(own) ?? s.colors[i]);\n }\n return { bg, hover };\n }\n\n private static groupDataset(g: ResolvedSeries): ChartDataset<'bar'> {\n return { label: g.name, data: g.data, backgroundColor: g.color, hoverBackgroundColor: g.hover, borderRadius: 3, borderSkipped: false };\n }\n\n constructor() {\n effect(() => {\n const s = this.model();\n const multi = s.groups.length > 0;\n const fills = BarChartComponent.fills(s);\n const freshDatasets = (): ChartDataset<'bar'>[] => multi\n ? s.groups.map(BarChartComponent.groupDataset)\n : [{ data: s.data, backgroundColor: fills.bg, hoverBackgroundColor: fills.hover, borderRadius: 3, borderSkipped: false }];\n const canvas = this.canvas().nativeElement;\n if (!this.chart) {\n registerChartParts();\n this.zone.runOutsideAngular(() => {\n this.chart = new Chart<'bar'>(canvas, {\n type: 'bar',\n data: { labels: s.labels, datasets: freshDatasets() },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n animation: false,\n layout: { padding: { top: 20 } },\n plugins: {\n legend: { display: false },\n tooltip: {\n callbacks: {\n label: (item) => {\n const text = this.tooltipText(Number(item.raw));\n // grouped charts name the series (\"Income: $1,200.00\"); a single series stays just the figure\n return this.multiMode ? `${item.dataset?.label ?? ''}: ${text}` : text;\n },\n },\n },\n },\n scales: {\n y: { beginAtZero: true, ticks: { precision: 0, color: '#94a3b8', font: { size: 11 } }, grid: { color: '#e2e8f0' }, border: { display: false } },\n x: { grid: { display: false }, ticks: { maxRotation: 0, color: '#94a3b8', font: { size: 10 } }, border: { display: false } },\n },\n },\n plugins: [VALUE_LABELS],\n });\n });\n }\n const chart = this.chart!;\n if (this.numberTickCallback === undefined) {\n this.numberTickCallback = (chart.options.scales as Record<string, { ticks: { callback?: unknown } }>)['y'].ticks.callback;\n }\n chart.data.labels = s.labels;\n if (this.multiMode !== null && this.multiMode !== multi) chart.data.datasets = freshDatasets(); // single <-> grouped: start from clean datasets\n this.multiMode = multi;\n if (multi) {\n // same dataset objects by position, new ones appended, surplus ones removed\n const datasets = chart.data.datasets;\n s.groups.forEach((g, i) => { const next = BarChartComponent.groupDataset(g); if (datasets[i]) Object.assign(datasets[i], next); else datasets.push(next); });\n datasets.splice(s.groups.length);\n } else {\n const ds = chart.data.datasets[0];\n ds.data = s.data;\n ds.backgroundColor = fills.bg;\n ds.hoverBackgroundColor = fills.hover;\n }\n const axes = chart.options.scales as Record<string, { stacked?: boolean }>;\n for (const axis of ['x', 'y']) {\n if (multi || axes[axis].stacked !== undefined) axes[axis].stacked = multi ? s.stacked : undefined;\n }\n // the value labels plugin reads these at draw time (a grouped chart: only while not too dense and not stacked)\n const labelsOn = multi ? s.showValues && !s.stacked && s.labels.length * s.groups.length <= BAR_CHART_MAX_GROUPED_VALUE_LABELS : s.showValues;\n (chart.options.plugins as Record<string, unknown>)['uiBarChartValueLabels'] = { enabled: labelsOn };\n if (s.formatter) VALUE_LABEL_FORMATS.set(chart, s.formatter.value); else VALUE_LABEL_FORMATS.delete(chart);\n // 'number' keeps the original whole-number ticks and default labels; currency / percent format the ticks and may be fractional\n const ticks = (chart.options.scales as Record<string, { ticks: { precision?: number; callback?: unknown } }>)['y'].ticks;\n if (s.formatter) {\n const tick = s.formatter.tick;\n ticks.precision = undefined;\n ticks.callback = (v: number | string) => tick(Number(v));\n } else {\n ticks.precision = 0;\n // put back chart.js's own tick labelling (remembered when the chart was created)\n if (this.numberTickCallback !== undefined) ticks.callback = this.numberTickCallback;\n }\n chart.update('none');\n });\n inject(DestroyRef).onDestroy(() => { this.chart?.destroy(); this.chart = null; });\n }\n}\n","import {\n Component, ChangeDetectionStrategy, DestroyRef, ElementRef, NgZone, PLATFORM_ID, computed, effect, inject, input, viewChild,\n} from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\nimport { ArcElement, Chart, DoughnutController, Tooltip } from 'chart.js';\n\n// Registered when a chart is first created (not at import time), like ui-bar-chart. A pie is a doughnut with no cutout,\n// so only the doughnut controller is needed.\nlet registered = false;\nfunction registerChartParts(): void {\n if (registered) return;\n Chart.register(DoughnutController, ArcElement, Tooltip);\n registered = true;\n}\n\n/** Built-in slice colours (cycled). Every colour has at least 3:1 contrast against white and against a light page grey (#f7f7f5). */\nexport const PIE_CHART_PALETTE: readonly string[] = [\n '#2563eb', '#16a34a', '#d27006', '#dc2626', '#7c3aed', '#0891b2',\n '#db2777', '#4d7c0f', '#475569', '#0d9488', '#c2410c', '#4f46e5', '#a21caf', '#b45309',\n];\n\n/** Cutout of a doughnut (share of the radius left empty); a pie has none. */\nconst DOUGHNUT_CUTOUT = '60%';\nconst PIE_CUTOUT = '0%';\nconst EMPTY_COLOR = '#e2e8f0';\n\n/** One drawn slice. `index` is the position in the input `labels`, so colours stay stable when another slice drops to 0. */\nexport interface PieSlice { index: number; label: string; value: number; percent: string; color: string; }\n\n/** \"62.5%\", \"100%\", \"<0.1%\" (a non-zero share that rounds to nothing). Rounded to 1 decimal. */\nexport function formatPercent(value: number, total: number): string {\n if (!(total > 0) || !(value > 0)) return '0%';\n const rounded = Math.round((value / total) * 1000) / 10;\n return rounded === 0 ? '<0.1%' : `${rounded}%`;\n}\n\nfunction prefersReducedMotion(): boolean {\n try { return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches; } catch { return false; }\n}\n\n/**\n * Pie or doughnut chart of one series (e.g. payments by method).\n *\n * <ui-pie-chart [labels]=\"['Card', 'Cash']\" [values]=\"[5, 3]\" [doughnut]=\"true\" centerLabel=\"Payments\" centerValue=\"8\"\n * ariaLabel=\"Payments by method\" unitSingular=\"payment\" unitPlural=\"payments\" />\n *\n * - Values must be finite and non-negative; anything else counts as 0. Slices with 0 are not drawn and not in the legend.\n * Extra labels without a value count as 0; extra values without a label are ignored.\n * - Empty or all-zero data shows a neutral grey ring with \"No data\" (no tooltip).\n * - The tooltip reads \"<value> <unit> (<share>)\" (`unitSingular` for exactly 1, `unitPlural` otherwise; no unit = just the number;\n * `showPercent=false` drops the share). The legend is real HTML below the chart and wraps on phones.\n * - With an `ariaLabel` the chart is an image for assistive tech (`role=\"img\"` + label). A visually hidden list next to it always\n * gives every slice's label, value and share (plus the centre text), because an image hides its children.\n * - Animation is off when the user prefers reduced motion. Height as ui-bar-chart: `height` px, default 240 shrinks to 200px up\n * to 768px wide and 160px up to 480px wide. Needs the optional peer dependency `chart.js` (>= 4).\n * - No click output: a slice is not keyboard reachable, so selecting is left to a list or table next to the chart.\n */\n@Component({\n selector: 'ui-pie-chart',\n standalone: true,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"pc-wrap\" [class.pc-default-height]=\"height() === 240\" [style.height.px]=\"height()\"\n [attr.role]=\"ariaLabel() ? 'img' : null\" [attr.aria-label]=\"ariaLabel() || null\">\n <canvas #canvas></canvas>\n @if (isEmpty()) {\n <div class=\"pc-center\"><span class=\"pc-center-label\">No data</span></div>\n } @else if (showCenter()) {\n <div class=\"pc-center\">\n @if (centerValue()) { <span class=\"pc-center-value\">{{ centerValue() }}</span> }\n @if (centerLabel()) { <span class=\"pc-center-label\">{{ centerLabel() }}</span> }\n </div>\n }\n </div>\n @if (showLegend() && !isEmpty()) {\n <ul class=\"pc-legend\" aria-hidden=\"true\">\n @for (s of slices(); track s.index) {\n <li class=\"pc-legend-item\">\n <span class=\"pc-swatch\" [style.background]=\"s.color\"></span>\n <span class=\"pc-legend-label\">{{ s.label }}</span>\n @if (showPercent()) { <span class=\"pc-legend-percent\">{{ s.percent }}</span> }\n </li>\n }\n </ul>\n }\n <ul class=\"pc-sr-only\" role=\"list\">\n @if (showCenter() && (centerLabel() || centerValue())) { <li>{{ centerLabel() }} {{ centerValue() }}</li> }\n @if (isEmpty()) { <li>No data</li> }\n @for (s of slices(); track s.index) {\n <li>{{ s.label }}: {{ valueText(s.value) }}@if (showPercent()) { ({{ s.percent }}) }</li>\n }\n </ul>\n `,\n styles: [`\n :host { display: block; position: relative; }\n .pc-wrap { position: relative; }\n .pc-center {\n position: absolute; top: 50%; left: 50%; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%);\n display: flex; flex-direction: column; align-items: center; text-align: center; pointer-events: none; max-width: 40%;\n }\n .pc-center-value { font-size: 1.5rem; font-weight: 700; color: #0f172a; line-height: 1.1; }\n .pc-center-label { font-size: 0.75rem; color: #475569; }\n .pc-legend { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-wrap: wrap; justify-content: center; gap: 6px 16px; }\n .pc-legend-item { display: flex; align-items: center; gap: 6px; font-size: 0.8125rem; color: #334155; max-width: 100%; min-width: 0; }\n .pc-legend-label { min-width: 0; overflow-wrap: anywhere; word-break: break-word; }\n .pc-swatch {\n width: 10px; height: 10px; border-radius: 2px; flex-shrink: 0;\n -webkit-print-color-adjust: exact; print-color-adjust: exact; forced-color-adjust: none;\n }\n .pc-legend-percent { color: #64748b; }\n .pc-sr-only {\n position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;\n clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; list-style: none;\n }\n @media (max-width: 768px) { .pc-wrap.pc-default-height { height: 200px !important; } }\n @media (max-width: 480px) {\n .pc-wrap.pc-default-height { height: 160px !important; }\n .pc-legend { gap: 4px 12px; }\n .pc-center-value { font-size: 1.125rem; }\n }\n `],\n})\nexport class PieChartComponent {\n /** Slice names. */\n readonly labels = input<string[]>([]);\n /** Slice values, in the order of `labels`. */\n readonly values = input<number[]>([]);\n /** true = ring with a centre hole instead of a full pie. */\n readonly doughnut = input(false);\n /** Per-slice CSS colours (cycled when shorter than the labels). Default: the built-in palette. */\n readonly colors = input<string[]>([]);\n /** Chart height in px (legend not included). */\n readonly height = input(240);\n /** Spoken description of the chart. */\n readonly ariaLabel = input('');\n /** Show the legend below the chart. */\n readonly showLegend = input(true);\n /** Show each slice's share in the tooltip, the legend and the hidden list. */\n readonly showPercent = input(true);\n /** Tooltip unit for exactly 1 (e.g. \"payment\"). */\n readonly unitSingular = input('');\n /** Tooltip unit for any other value (e.g. \"payments\"). */\n readonly unitPlural = input('');\n /** Doughnut only: small text in the hole (e.g. \"Total\"). */\n readonly centerLabel = input('');\n /** Doughnut only: large text in the hole (e.g. \"128\"). */\n readonly centerValue = input('');\n\n private readonly canvas = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n private readonly zone = inject(NgZone);\n private readonly browser = isPlatformBrowser(inject(PLATFORM_ID));\n private chart: Chart<'doughnut'> | null = null;\n\n /** Drawn slices (value > 0) with their colour and share. */\n protected readonly slices = computed((): PieSlice[] => {\n const labels = this.labels();\n const values = this.values();\n const palette = this.colors().length ? this.colors() : PIE_CHART_PALETTE;\n const clean = labels.map((_, i) => { const v = values[i]; return typeof v === 'number' && Number.isFinite(v) && v > 0 ? v : 0; });\n let total = clean.reduce((a, b) => a + b, 0);\n // Huge values can overflow the sum to Infinity; shares are scale-free, so work on values relative to the largest.\n const scale = Number.isFinite(total) ? 1 : Math.max(...clean);\n if (scale !== 1) total = clean.reduce((a, b) => a + b / scale, 0);\n const out: PieSlice[] = [];\n clean.forEach((value, index) => {\n if (value > 0) out.push({ index, label: labels[index], value, percent: formatPercent(value / scale, total), color: palette[index % palette.length] });\n });\n return out;\n });\n\n protected readonly isEmpty = computed(() => this.slices().length === 0);\n protected readonly showCenter = computed(() => this.doughnut() && !this.isEmpty() && !!(this.centerLabel() || this.centerValue()));\n\n /** \"<value> <unit>\" (`unitSingular` for exactly 1, `unitPlural` otherwise; no unit = just the number). */\n protected readonly valueText = (value: number): string => {\n const unit = value === 1 ? this.unitSingular() : this.unitPlural();\n return unit ? `${value} ${unit}` : String(value);\n };\n\n private readonly tooltipText = (dataIndex: number, value: number): string => {\n const base = this.valueText(value);\n const slice = this.slices()[dataIndex];\n return this.showPercent() && slice ? `${base} (${slice.percent})` : base;\n };\n\n private readonly chartData = computed(() => {\n const empty = this.isEmpty();\n const s = this.slices();\n return {\n labels: empty ? ['No data'] : s.map(x => x.label),\n data: empty ? [1] : s.map(x => x.value),\n colors: empty ? [EMPTY_COLOR] : s.map(x => x.color),\n cutout: this.doughnut() ? DOUGHNUT_CUTOUT : PIE_CUTOUT,\n tooltip: !empty,\n };\n });\n\n constructor() {\n effect(() => {\n const d = this.chartData();\n if (!this.browser) return; // server rendering: no canvas to draw on\n const canvas = this.canvas().nativeElement;\n const reduced = prefersReducedMotion();\n if (!this.chart) {\n registerChartParts();\n this.zone.runOutsideAngular(() => {\n this.chart = new Chart(canvas, {\n type: 'doughnut',\n data: { labels: d.labels, datasets: [{ data: d.data, backgroundColor: d.colors, borderColor: '#ffffff', borderWidth: 2, hoverOffset: 4 }] },\n options: {\n responsive: true,\n maintainAspectRatio: false,\n animation: reduced ? false : { duration: 400 },\n cutout: d.cutout,\n plugins: {\n legend: { display: false },\n tooltip: { enabled: d.tooltip, callbacks: { label: (item) => this.tooltipText(item.dataIndex, Number(item.raw)) } },\n },\n },\n });\n });\n }\n const chart = this.chart!;\n chart.data.labels = d.labels;\n const ds = chart.data.datasets[0];\n ds.data = d.data;\n ds.backgroundColor = d.colors;\n chart.options.cutout = d.cutout;\n chart.options.animation = reduced ? false : { duration: 400 };\n chart.options.plugins!.tooltip!.enabled = d.tooltip;\n // outside the zone: an animated update would otherwise trigger change detection on every frame\n this.zone.runOutsideAngular(() => chart.update(reduced ? 'none' : undefined));\n });\n inject(DestroyRef).onDestroy(() => { this.chart?.destroy(); this.chart = null; });\n }\n}\n"],"mappings":"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"}
|
|
@@ -4723,7 +4723,8 @@ var SendEmailComponent = class SendEmailComponent {
|
|
|
4723
4723
|
"activeKey",
|
|
4724
4724
|
"ariaLabel",
|
|
4725
4725
|
"name",
|
|
4726
|
-
"noWrap"
|
|
4726
|
+
"noWrap",
|
|
4727
|
+
"orientation"
|
|
4727
4728
|
],
|
|
4728
4729
|
outputs: ["tabChange"]
|
|
4729
4730
|
},
|
|
@@ -6992,7 +6993,8 @@ var SendTextComponent = class SendTextComponent {
|
|
|
6992
6993
|
"activeKey",
|
|
6993
6994
|
"ariaLabel",
|
|
6994
6995
|
"name",
|
|
6995
|
-
"noWrap"
|
|
6996
|
+
"noWrap",
|
|
6997
|
+
"orientation"
|
|
6996
6998
|
],
|
|
6997
6999
|
outputs: ["tabChange"]
|
|
6998
7000
|
},
|