@aceshooting/lyra-ui 1.0.1 → 1.2.0
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/README.md +9 -10
- package/custom-elements.json +15118 -8342
- package/dist/components/chart/chart.d.ts +57 -1
- package/dist/components/chart/chart.js +202 -12
- package/dist/components/chart/chart.stories.d.ts +32 -0
- package/dist/components/chart/chart.stories.js +141 -0
- package/dist/components/chart/chart.styles.js +16 -0
- package/dist/components/chart/histogram.d.ts +2 -0
- package/dist/components/chart/histogram.js +18 -2
- package/dist/components/chart/line-chart.stories.d.ts +17 -0
- package/dist/components/chart/line-chart.stories.js +75 -0
- package/dist/components/chart/lite-chart.d.ts +83 -0
- package/dist/components/chart/lite-chart.js +424 -0
- package/dist/components/chart/lite-chart.stories.d.ts +14 -0
- package/dist/components/chart/lite-chart.stories.js +114 -0
- package/dist/components/chart/lite-chart.styles.d.ts +1 -0
- package/dist/components/chart/lite-chart.styles.js +83 -0
- package/dist/components/combobox/combobox.d.ts +9 -0
- package/dist/components/combobox/combobox.js +76 -13
- package/dist/components/combobox/combobox.stories.d.ts +18 -0
- package/dist/components/combobox/combobox.stories.js +75 -0
- package/dist/components/date-picker/calendar-core.js +13 -2
- package/dist/components/date-picker/date-input.d.ts +9 -1
- package/dist/components/date-picker/date-input.js +55 -7
- package/dist/components/date-picker/date-input.stories.d.ts +5 -0
- package/dist/components/date-picker/date-input.stories.js +36 -0
- package/dist/components/date-picker/date-picker.d.ts +11 -3
- package/dist/components/date-picker/date-picker.js +87 -37
- package/dist/components/date-picker/date-picker.stories.d.ts +4 -0
- package/dist/components/date-picker/date-picker.stories.js +12 -0
- package/dist/components/date-picker/date-picker.styles.js +1 -1
- package/dist/components/empty/empty.d.ts +12 -1
- package/dist/components/empty/empty.js +20 -3
- package/dist/components/empty/empty.stories.d.ts +2 -0
- package/dist/components/empty/empty.stories.js +20 -0
- package/dist/components/empty/empty.styles.js +11 -0
- package/dist/components/export-button/csv.js +6 -2
- package/dist/components/export-button/export-button.d.ts +15 -1
- package/dist/components/export-button/export-button.js +89 -12
- package/dist/components/export-button/export-button.stories.d.ts +1 -0
- package/dist/components/export-button/export-button.stories.js +5 -0
- package/dist/components/export-button/export-button.styles.js +11 -3
- package/dist/components/file-input/accept.d.ts +8 -2
- package/dist/components/file-input/accept.js +9 -3
- package/dist/components/file-input/file-input.d.ts +5 -2
- package/dist/components/file-input/file-input.js +23 -8
- package/dist/components/file-input/file-input.stories.d.ts +2 -0
- package/dist/components/file-input/file-input.stories.js +9 -0
- package/dist/components/flag/flag.d.ts +69 -3
- package/dist/components/flag/flag.js +107 -30
- package/dist/components/flag/flag.stories.d.ts +1 -0
- package/dist/components/flag/flag.stories.js +14 -0
- package/dist/components/flag/flag.styles.js +1 -1
- package/dist/components/flag/language-map.d.ts +11 -0
- package/dist/components/flag/language-map.js +12 -1
- package/dist/components/gauge/gauge.d.ts +2 -0
- package/dist/components/gauge/gauge.js +19 -5
- package/dist/components/gauge/gauge.stories.d.ts +2 -0
- package/dist/components/gauge/gauge.stories.js +6 -0
- package/dist/components/graph/graph-loader.d.ts +28 -0
- package/dist/components/graph/graph-loader.js +44 -0
- package/dist/components/graph/graph.d.ts +41 -15
- package/dist/components/graph/graph.js +146 -71
- package/dist/components/graph/graph.stories.d.ts +3 -0
- package/dist/components/graph/graph.stories.js +38 -0
- package/dist/components/graph/graph.styles.js +6 -1
- package/dist/components/heatmap/calendar-grid.d.ts +7 -0
- package/dist/components/heatmap/calendar-grid.js +27 -10
- package/dist/components/heatmap/heatmap.d.ts +149 -12
- package/dist/components/heatmap/heatmap.js +445 -28
- package/dist/components/heatmap/heatmap.stories.d.ts +22 -0
- package/dist/components/heatmap/heatmap.stories.js +155 -0
- package/dist/components/heatmap/heatmap.styles.js +60 -2
- package/dist/components/map/map.d.ts +17 -1
- package/dist/components/map/map.js +68 -21
- package/dist/components/map/map.stories.d.ts +10 -0
- package/dist/components/map/map.stories.js +107 -12
- package/dist/components/map/map.styles.js +2 -2
- package/dist/components/playback/playback.d.ts +6 -2
- package/dist/components/playback/playback.js +36 -12
- package/dist/components/playback/playback.stories.d.ts +2 -0
- package/dist/components/playback/playback.stories.js +6 -0
- package/dist/components/playback/playback.styles.js +10 -2
- package/dist/components/select/select.d.ts +125 -0
- package/dist/components/select/select.js +480 -0
- package/dist/components/select/select.stories.d.ts +21 -0
- package/dist/components/select/select.stories.js +91 -0
- package/dist/components/select/select.styles.d.ts +1 -0
- package/dist/components/select/select.styles.js +212 -0
- package/dist/components/skeleton/skeleton.js +4 -7
- package/dist/components/sparkline/sparkline.d.ts +1 -1
- package/dist/components/sparkline/sparkline.js +40 -13
- package/dist/components/sparkline/sparkline.stories.d.ts +4 -0
- package/dist/components/sparkline/sparkline.stories.js +22 -0
- package/dist/components/split/split.d.ts +24 -3
- package/dist/components/split/split.js +155 -31
- package/dist/components/split/split.stories.d.ts +2 -0
- package/dist/components/split/split.stories.js +20 -0
- package/dist/components/stat/stat.d.ts +43 -1
- package/dist/components/stat/stat.js +97 -4
- package/dist/components/stat/stat.stories.d.ts +4 -0
- package/dist/components/stat/stat.stories.js +66 -1
- package/dist/components/stat/stat.styles.js +64 -0
- package/dist/components/table/table.d.ts +64 -2
- package/dist/components/table/table.js +213 -17
- package/dist/components/table/table.stories.d.ts +6 -0
- package/dist/components/table/table.stories.js +45 -0
- package/dist/components/table/table.styles.js +51 -4
- package/dist/components/time-range/time-range.d.ts +34 -5
- package/dist/components/time-range/time-range.js +217 -36
- package/dist/components/time-range/time-range.stories.d.ts +2 -0
- package/dist/components/time-range/time-range.stories.js +13 -0
- package/dist/components/time-range/time-range.styles.js +44 -2
- package/dist/components/toast/toast-item.d.ts +14 -2
- package/dist/components/toast/toast-item.js +134 -17
- package/dist/components/toast/toast-item.styles.js +28 -2
- package/dist/components/toast/toast.stories.d.ts +3 -0
- package/dist/components/toast/toast.stories.js +41 -1
- package/dist/components/toast/toast.styles.js +11 -11
- package/dist/components/toast/toaster.d.ts +1 -1
- package/dist/components/toast/toaster.js +13 -6
- package/dist/components/tree/tree-node.d.ts +13 -7
- package/dist/components/tree/tree-node.js +24 -10
- package/dist/components/tree/tree.d.ts +64 -15
- package/dist/components/tree/tree.js +113 -22
- package/dist/components/tree/tree.stories.d.ts +4 -0
- package/dist/components/tree/tree.stories.js +31 -1
- package/dist/components/tree/update-cascade.d.ts +13 -0
- package/dist/components/tree/update-cascade.js +13 -0
- package/dist/components/widget/widget.d.ts +25 -1
- package/dist/components/widget/widget.js +164 -6
- package/dist/components/widget/widget.stories.d.ts +3 -0
- package/dist/components/widget/widget.stories.js +43 -0
- package/dist/components/widget/widget.styles.js +20 -3
- package/dist/components/word-cloud/word-cloud-layout.d.ts +63 -0
- package/dist/components/word-cloud/word-cloud-layout.js +145 -0
- package/dist/components/word-cloud/word-cloud.d.ts +65 -0
- package/dist/components/word-cloud/word-cloud.js +255 -0
- package/dist/components/word-cloud/word-cloud.stories.d.ts +10 -0
- package/dist/components/word-cloud/word-cloud.stories.js +55 -0
- package/dist/components/word-cloud/word-cloud.styles.d.ts +1 -0
- package/dist/components/word-cloud/word-cloud.styles.js +55 -0
- package/dist/internal/a11y.js +2 -1
- package/dist/internal/rtl.d.ts +7 -0
- package/dist/internal/rtl.js +9 -0
- package/dist/lyra.d.ts +9 -1
- package/dist/lyra.js +6 -0
- package/llms-full.txt +962 -276
- package/llms.txt +12 -9
- package/package.json +6 -4
|
@@ -42,6 +42,10 @@ export type LyraChartType = 'line' | 'bar' | 'scatter' | 'pie' | 'doughnut' | 'r
|
|
|
42
42
|
*
|
|
43
43
|
* @customElement lyra-chart
|
|
44
44
|
* @event lyra-zoom - `detail: { zoomed }`.
|
|
45
|
+
* @event lyra-point-click - Fired when a click lands on (or nearest,
|
|
46
|
+
* intersect-only — see `handlePointClick()`) a data point/segment.
|
|
47
|
+
* `detail: { datasetIndex: number, index: number, label: string |
|
|
48
|
+
* undefined, value: unknown }`.
|
|
45
49
|
* @csspart base, canvas, reset-zoom-button
|
|
46
50
|
*/
|
|
47
51
|
export declare class LyraChart extends LyraElement {
|
|
@@ -57,6 +61,10 @@ export declare class LyraChart extends LyraElement {
|
|
|
57
61
|
yLabel: string;
|
|
58
62
|
y2Label: string;
|
|
59
63
|
beginAtZero: boolean;
|
|
64
|
+
/** Sets `options.indexAxis = 'y'`, Chart.js's own mechanism for horizontal bars (also applies to line/area types). */
|
|
65
|
+
horizontal: boolean;
|
|
66
|
+
/** Stacks the `x`/`y`(/`y2`) scale entries `buildScales()` returns; only meaningful for `bar` and `line` types. */
|
|
67
|
+
stacked: boolean;
|
|
60
68
|
/**
|
|
61
69
|
* Raw Chart.js configuration passthrough — mirrors `wa-chart`'s `config`
|
|
62
70
|
* property. Recursively deep-merged over the `Series`-derived config in
|
|
@@ -69,25 +77,73 @@ export declare class LyraChart extends LyraElement {
|
|
|
69
77
|
/** True until the lazy-loaded `chart.js` peer dependency has settled (success or failure). */
|
|
70
78
|
private loading;
|
|
71
79
|
private zoomed;
|
|
80
|
+
private visible;
|
|
81
|
+
private intersectionObserver?;
|
|
82
|
+
private lastSignature;
|
|
72
83
|
private canvasEl?;
|
|
73
84
|
private chart?;
|
|
74
85
|
private chartJsModule?;
|
|
75
86
|
private builtType?;
|
|
87
|
+
private suppressZoomComplete;
|
|
76
88
|
connectedCallback(): void;
|
|
77
89
|
disconnectedCallback(): void;
|
|
78
90
|
protected updated(changed: PropertyValues): void;
|
|
79
91
|
private seriesToDataset;
|
|
92
|
+
/**
|
|
93
|
+
* Resolves the `--lyra-chart-*` theme tokens (declared in
|
|
94
|
+
* `chart.styles.ts`, each layered over an existing semantic token) via
|
|
95
|
+
* `getComputedStyle`. Chart.js renders to canvas, not the DOM, so it can't
|
|
96
|
+
* consume CSS `var()` directly — same constraint documented on
|
|
97
|
+
* `heatmap.ts`'s `labelColor()`/`noDataFill()`/`scaleEndpoints()` — so this
|
|
98
|
+
* is called fresh from `buildConfig()` on every draw rather than cached.
|
|
99
|
+
*/
|
|
100
|
+
private themeColors;
|
|
101
|
+
/**
|
|
102
|
+
* A content-affecting-properties fingerprint used by `updated()` to skip a
|
|
103
|
+
* redundant `draw()` when neither visibility nor any of these properties
|
|
104
|
+
* actually changed since the last draw (e.g. an unrelated property/state
|
|
105
|
+
* update, or `requestUpdate()` with nothing changed). Mirrors
|
|
106
|
+
* `lite-chart.ts`'s `computeSignature()`.
|
|
107
|
+
*/
|
|
108
|
+
private computeSignature;
|
|
80
109
|
/**
|
|
81
110
|
* Builds `options.scales` for the effective chart type: no scale at all for
|
|
82
111
|
* pie/doughnut (a proportional-area chart has no axis), the single radial
|
|
83
112
|
* `r` scale Chart.js v4 uses for radar/polarArea, and the cartesian
|
|
84
|
-
* `x`/`y`(/`y2`) block for every other (line/bar/scatter/bubble) type
|
|
113
|
+
* `x`/`y`(/`y2`) block for every other (line/bar/scatter/bubble) type — with
|
|
114
|
+
* `x` itself further split within that block: scatter and bubble datasets
|
|
115
|
+
* carry raw numeric `{x, y(, r)}` points (via `Series.points`) and need a
|
|
116
|
+
* linear `x` scale, while line/bar plot against `labels` and need the
|
|
117
|
+
* default categorical one. `theme` (from `themeColors()`) drives every
|
|
118
|
+
* scale's `ticks.color`/`grid.color`/axis `title.color` so grid lines and
|
|
119
|
+
* labels retheme instead of sitting at Chart.js's own hardcoded defaults.
|
|
85
120
|
*/
|
|
86
121
|
private buildScales;
|
|
122
|
+
/**
|
|
123
|
+
* `options.onClick` handler wired in `buildConfig()`. The chart-wide
|
|
124
|
+
* `interaction` mode above (`'index'`/`'nearest'`, `intersect: false`) is
|
|
125
|
+
* tuned for hover tooltips — resolving which single point/segment was
|
|
126
|
+
* actually clicked needs its own `getElementsAtEventForMode('nearest', {
|
|
127
|
+
* intersect: true }, true)` lookup instead, so a click landing off any
|
|
128
|
+
* point/segment reports nothing (`elements` empty) rather than firing for
|
|
129
|
+
* whatever's nearest. Covers the per-bar/per-segment click ask for any
|
|
130
|
+
* chart type (bar/line/pie/doughnut/etc.), not just bars.
|
|
131
|
+
*/
|
|
132
|
+
private handlePointClick;
|
|
87
133
|
private buildConfig;
|
|
88
134
|
private draw;
|
|
89
135
|
/** Reset any active zoom/pan back to the original view. */
|
|
90
136
|
resetZoom(): void;
|
|
137
|
+
/**
|
|
138
|
+
* Forces a redraw so `themeColors()` re-reads the `--lyra-chart-*` custom
|
|
139
|
+
* properties from the current computed style. No global theme-broadcast
|
|
140
|
+
* event exists anywhere in lyra-ui (nothing to subscribe to here) — this
|
|
141
|
+
* is the escape hatch for a consumer's own theme-toggle handler to call
|
|
142
|
+
* directly when it flips e.g. a `data-theme` attribute upstream that
|
|
143
|
+
* doesn't otherwise change any `lyra-chart` property, so Lit's reactive
|
|
144
|
+
* update loop has nothing of its own to trigger `draw()` on.
|
|
145
|
+
*/
|
|
146
|
+
refreshTheme(): void;
|
|
91
147
|
render(): TemplateResult;
|
|
92
148
|
}
|
|
93
149
|
declare global {
|
|
@@ -27,6 +27,18 @@ function isPlainObject(value) {
|
|
|
27
27
|
// response) reach up through the merge and mutate `Object.prototype` —
|
|
28
28
|
// skipped unconditionally regardless of `base`'s own shape.
|
|
29
29
|
const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
|
|
30
|
+
function prefersReducedMotion() {
|
|
31
|
+
return typeof window !== 'undefined' && !!window.matchMedia?.('(prefers-reduced-motion: reduce)').matches;
|
|
32
|
+
}
|
|
33
|
+
// Defensive JS-side fallbacks for themeColors() below, mirroring the
|
|
34
|
+
// light-mode default of each `--lyra-chart-*` token's own fallback chain
|
|
35
|
+
// (see chart.styles.ts) — only reached if getComputedStyle somehow can't
|
|
36
|
+
// resolve the custom property at all (e.g. host detached from the document).
|
|
37
|
+
const FALLBACK_GRID_COLOR = '#8a8a90';
|
|
38
|
+
const FALLBACK_TICK_COLOR = '#6b7280';
|
|
39
|
+
const FALLBACK_LEGEND_COLOR = '#1a1a1a';
|
|
40
|
+
const FALLBACK_TOOLTIP_BG = '#fff';
|
|
41
|
+
const FALLBACK_TOOLTIP_TEXT = '#1a1a1a';
|
|
30
42
|
function deepMerge(base, override) {
|
|
31
43
|
if (!isPlainObject(base) || !isPlainObject(override)) {
|
|
32
44
|
return (override === undefined ? base : override);
|
|
@@ -60,6 +72,10 @@ function deepMerge(base, override) {
|
|
|
60
72
|
*
|
|
61
73
|
* @customElement lyra-chart
|
|
62
74
|
* @event lyra-zoom - `detail: { zoomed }`.
|
|
75
|
+
* @event lyra-point-click - Fired when a click lands on (or nearest,
|
|
76
|
+
* intersect-only — see `handlePointClick()`) a data point/segment.
|
|
77
|
+
* `detail: { datasetIndex: number, index: number, label: string |
|
|
78
|
+
* undefined, value: unknown }`.
|
|
63
79
|
* @csspart base, canvas, reset-zoom-button
|
|
64
80
|
*/
|
|
65
81
|
export class LyraChart extends LyraElement {
|
|
@@ -76,9 +92,21 @@ export class LyraChart extends LyraElement {
|
|
|
76
92
|
this.yLabel = '';
|
|
77
93
|
this.y2Label = '';
|
|
78
94
|
this.beginAtZero = true;
|
|
95
|
+
/** Sets `options.indexAxis = 'y'`, Chart.js's own mechanism for horizontal bars (also applies to line/area types). */
|
|
96
|
+
this.horizontal = false;
|
|
97
|
+
/** Stacks the `x`/`y`(/`y2`) scale entries `buildScales()` returns; only meaningful for `bar` and `line` types. */
|
|
98
|
+
this.stacked = false;
|
|
79
99
|
/** True until the lazy-loaded `chart.js` peer dependency has settled (success or failure). */
|
|
80
100
|
this.loading = true;
|
|
81
101
|
this.zoomed = false;
|
|
102
|
+
this.visible = true;
|
|
103
|
+
this.lastSignature = '';
|
|
104
|
+
// `chartjs-plugin-zoom`'s own `resetZoom()` synchronously re-invokes the
|
|
105
|
+
// `onZoomComplete` callback below as part of its reset, which would emit a
|
|
106
|
+
// stale `{zoomed: true}` right before `resetZoom()` emits the real
|
|
107
|
+
// `{zoomed: false}`. Set while this component's own `resetZoom()` is
|
|
108
|
+
// driving the plugin so that re-entrant callback is ignored.
|
|
109
|
+
this.suppressZoomComplete = false;
|
|
82
110
|
}
|
|
83
111
|
static { this.styles = [LyraElement.styles, styles]; }
|
|
84
112
|
connectedCallback() {
|
|
@@ -90,11 +118,21 @@ export class LyraChart extends LyraElement {
|
|
|
90
118
|
this.chartJsModule = mod;
|
|
91
119
|
this.draw();
|
|
92
120
|
});
|
|
121
|
+
if (typeof IntersectionObserver !== 'undefined') {
|
|
122
|
+
this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
123
|
+
const wasVisible = this.visible;
|
|
124
|
+
this.visible = entries[0]?.isIntersecting ?? true;
|
|
125
|
+
if (this.visible && !wasVisible)
|
|
126
|
+
this.draw();
|
|
127
|
+
});
|
|
128
|
+
this.intersectionObserver.observe(this);
|
|
129
|
+
}
|
|
93
130
|
}
|
|
94
131
|
disconnectedCallback() {
|
|
95
132
|
super.disconnectedCallback();
|
|
96
133
|
this.chart?.destroy();
|
|
97
134
|
this.chart = undefined;
|
|
135
|
+
this.intersectionObserver?.disconnect();
|
|
98
136
|
}
|
|
99
137
|
updated(changed) {
|
|
100
138
|
if (this.loading)
|
|
@@ -109,9 +147,23 @@ export class LyraChart extends LyraElement {
|
|
|
109
147
|
if (changed.has('height')) {
|
|
110
148
|
this.style.setProperty('--lyra-chart-height', this.height);
|
|
111
149
|
}
|
|
150
|
+
// While `chart.js` is still loading, `draw()` would no-op anyway (no
|
|
151
|
+
// `chartJsModule`/`canvasEl` yet) — bail before touching `lastSignature`
|
|
152
|
+
// so that phantom "no-op" update doesn't get cached as the baseline and
|
|
153
|
+
// silently swallow the real first draw once loading finishes with no
|
|
154
|
+
// other property having changed in the meantime.
|
|
155
|
+
if (this.loading)
|
|
156
|
+
return;
|
|
112
157
|
const onlyZoomChanged = changed.size === 1 && changed.has('zoomed');
|
|
113
|
-
if (
|
|
114
|
-
|
|
158
|
+
if (onlyZoomChanged)
|
|
159
|
+
return;
|
|
160
|
+
if (!this.visible)
|
|
161
|
+
return; // becoming visible again triggers its own draw() via the observer above
|
|
162
|
+
const signature = this.computeSignature();
|
|
163
|
+
if (signature === this.lastSignature)
|
|
164
|
+
return;
|
|
165
|
+
this.lastSignature = signature;
|
|
166
|
+
this.draw();
|
|
115
167
|
}
|
|
116
168
|
seriesToDataset(s) {
|
|
117
169
|
const colors = Array.isArray(s.color) ? s.color : s.color ? [s.color] : undefined;
|
|
@@ -130,41 +182,134 @@ export class LyraChart extends LyraElement {
|
|
|
130
182
|
tooltip: s.noTooltip ? { enabled: false } : undefined,
|
|
131
183
|
};
|
|
132
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Resolves the `--lyra-chart-*` theme tokens (declared in
|
|
187
|
+
* `chart.styles.ts`, each layered over an existing semantic token) via
|
|
188
|
+
* `getComputedStyle`. Chart.js renders to canvas, not the DOM, so it can't
|
|
189
|
+
* consume CSS `var()` directly — same constraint documented on
|
|
190
|
+
* `heatmap.ts`'s `labelColor()`/`noDataFill()`/`scaleEndpoints()` — so this
|
|
191
|
+
* is called fresh from `buildConfig()` on every draw rather than cached.
|
|
192
|
+
*/
|
|
193
|
+
themeColors() {
|
|
194
|
+
const cs = getComputedStyle(this);
|
|
195
|
+
return {
|
|
196
|
+
grid: cs.getPropertyValue('--lyra-chart-grid-color').trim() || FALLBACK_GRID_COLOR,
|
|
197
|
+
tick: cs.getPropertyValue('--lyra-chart-tick-color').trim() || FALLBACK_TICK_COLOR,
|
|
198
|
+
legend: cs.getPropertyValue('--lyra-chart-legend-color').trim() || FALLBACK_LEGEND_COLOR,
|
|
199
|
+
tooltipBg: cs.getPropertyValue('--lyra-chart-tooltip-bg').trim() || FALLBACK_TOOLTIP_BG,
|
|
200
|
+
tooltipText: cs.getPropertyValue('--lyra-chart-tooltip-text').trim() || FALLBACK_TOOLTIP_TEXT,
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* A content-affecting-properties fingerprint used by `updated()` to skip a
|
|
205
|
+
* redundant `draw()` when neither visibility nor any of these properties
|
|
206
|
+
* actually changed since the last draw (e.g. an unrelated property/state
|
|
207
|
+
* update, or `requestUpdate()` with nothing changed). Mirrors
|
|
208
|
+
* `lite-chart.ts`'s `computeSignature()`.
|
|
209
|
+
*/
|
|
210
|
+
computeSignature() {
|
|
211
|
+
return JSON.stringify([
|
|
212
|
+
this.type,
|
|
213
|
+
this.labels,
|
|
214
|
+
this.datasets,
|
|
215
|
+
this.legend,
|
|
216
|
+
this.area,
|
|
217
|
+
this.xLabel,
|
|
218
|
+
this.yLabel,
|
|
219
|
+
this.y2Label,
|
|
220
|
+
this.beginAtZero,
|
|
221
|
+
this.horizontal,
|
|
222
|
+
this.stacked,
|
|
223
|
+
this.config,
|
|
224
|
+
]);
|
|
225
|
+
}
|
|
133
226
|
/**
|
|
134
227
|
* Builds `options.scales` for the effective chart type: no scale at all for
|
|
135
228
|
* pie/doughnut (a proportional-area chart has no axis), the single radial
|
|
136
229
|
* `r` scale Chart.js v4 uses for radar/polarArea, and the cartesian
|
|
137
|
-
* `x`/`y`(/`y2`) block for every other (line/bar/scatter/bubble) type
|
|
230
|
+
* `x`/`y`(/`y2`) block for every other (line/bar/scatter/bubble) type — with
|
|
231
|
+
* `x` itself further split within that block: scatter and bubble datasets
|
|
232
|
+
* carry raw numeric `{x, y(, r)}` points (via `Series.points`) and need a
|
|
233
|
+
* linear `x` scale, while line/bar plot against `labels` and need the
|
|
234
|
+
* default categorical one. `theme` (from `themeColors()`) drives every
|
|
235
|
+
* scale's `ticks.color`/`grid.color`/axis `title.color` so grid lines and
|
|
236
|
+
* labels retheme instead of sitting at Chart.js's own hardcoded defaults.
|
|
138
237
|
*/
|
|
139
|
-
buildScales() {
|
|
238
|
+
buildScales(theme) {
|
|
140
239
|
if (this.type === 'pie' || this.type === 'doughnut')
|
|
141
240
|
return {};
|
|
142
241
|
if (this.type === 'radar' || this.type === 'polarArea') {
|
|
143
242
|
return {
|
|
144
243
|
r: {
|
|
145
244
|
beginAtZero: this.beginAtZero,
|
|
245
|
+
ticks: { color: theme.tick },
|
|
246
|
+
grid: { color: theme.grid },
|
|
247
|
+
angleLines: { color: theme.grid },
|
|
248
|
+
pointLabels: { color: theme.tick },
|
|
146
249
|
},
|
|
147
250
|
};
|
|
148
251
|
}
|
|
149
252
|
const hasY2 = this.datasets.some((s) => s.axis === 'y2');
|
|
253
|
+
// `stacked` only applies to bar/line-family charts sharing a categorical
|
|
254
|
+
// axis, per the design spec — scatter/bubble's linear x scale and the
|
|
255
|
+
// radial r scale above are out of scope.
|
|
256
|
+
const stacked = this.stacked && (this.type === 'bar' || this.type === 'line');
|
|
150
257
|
return {
|
|
151
258
|
x: {
|
|
152
|
-
type: this.type === 'scatter' ? 'linear' : 'category',
|
|
153
|
-
title: { display: !!this.xLabel, text: this.xLabel },
|
|
259
|
+
type: this.type === 'scatter' || this.type === 'bubble' ? 'linear' : 'category',
|
|
260
|
+
title: { display: !!this.xLabel, text: this.xLabel, color: theme.tick },
|
|
261
|
+
ticks: { color: theme.tick },
|
|
262
|
+
grid: { color: theme.grid },
|
|
263
|
+
stacked,
|
|
264
|
+
},
|
|
265
|
+
y: {
|
|
266
|
+
beginAtZero: this.beginAtZero,
|
|
267
|
+
title: { display: !!this.yLabel, text: this.yLabel, color: theme.tick },
|
|
268
|
+
ticks: { color: theme.tick },
|
|
269
|
+
grid: { color: theme.grid },
|
|
270
|
+
stacked,
|
|
154
271
|
},
|
|
155
|
-
y: { beginAtZero: this.beginAtZero, title: { display: !!this.yLabel, text: this.yLabel } },
|
|
156
272
|
...(hasY2
|
|
157
273
|
? {
|
|
158
274
|
y2: {
|
|
159
275
|
position: 'right',
|
|
160
|
-
grid: { drawOnChartArea: false },
|
|
161
|
-
title: { display: !!this.y2Label, text: this.y2Label },
|
|
276
|
+
grid: { drawOnChartArea: false, color: theme.grid },
|
|
277
|
+
title: { display: !!this.y2Label, text: this.y2Label, color: theme.tick },
|
|
278
|
+
ticks: { color: theme.tick },
|
|
279
|
+
stacked,
|
|
162
280
|
},
|
|
163
281
|
}
|
|
164
282
|
: {}),
|
|
165
283
|
};
|
|
166
284
|
}
|
|
285
|
+
/**
|
|
286
|
+
* `options.onClick` handler wired in `buildConfig()`. The chart-wide
|
|
287
|
+
* `interaction` mode above (`'index'`/`'nearest'`, `intersect: false`) is
|
|
288
|
+
* tuned for hover tooltips — resolving which single point/segment was
|
|
289
|
+
* actually clicked needs its own `getElementsAtEventForMode('nearest', {
|
|
290
|
+
* intersect: true }, true)` lookup instead, so a click landing off any
|
|
291
|
+
* point/segment reports nothing (`elements` empty) rather than firing for
|
|
292
|
+
* whatever's nearest. Covers the per-bar/per-segment click ask for any
|
|
293
|
+
* chart type (bar/line/pie/doughnut/etc.), not just bars.
|
|
294
|
+
*/
|
|
295
|
+
handlePointClick(event, chart) {
|
|
296
|
+
// Chart.js's own `onClick` handler hands us its `ChartEvent` wrapper, but
|
|
297
|
+
// `getElementsAtEventForMode()`'s .d.ts (inaccurately) types its first
|
|
298
|
+
// param as a DOM `Event` — at runtime Chart.js only reads `.x`/`.y` off
|
|
299
|
+
// whatever is passed (see chart.js/src/helpers/helpers.dom.ts
|
|
300
|
+
// `getRelativePosition()`), which `ChartEvent` already has, so the cast
|
|
301
|
+
// here is a type-only correction, not a behavior change.
|
|
302
|
+
const elements = chart.getElementsAtEventForMode(event, 'nearest', { intersect: true }, true);
|
|
303
|
+
const hit = elements[0];
|
|
304
|
+
if (!hit)
|
|
305
|
+
return;
|
|
306
|
+
const { datasetIndex, index } = hit;
|
|
307
|
+
const label = chart.data.labels?.[index];
|
|
308
|
+
const value = chart.data.datasets[datasetIndex]?.data?.[index] ?? null;
|
|
309
|
+
this.emit('lyra-point-click', { datasetIndex, index, label, value });
|
|
310
|
+
}
|
|
167
311
|
buildConfig() {
|
|
312
|
+
const theme = this.themeColors();
|
|
168
313
|
const generated = {
|
|
169
314
|
type: this.type,
|
|
170
315
|
data: {
|
|
@@ -174,9 +319,25 @@ export class LyraChart extends LyraElement {
|
|
|
174
319
|
options: {
|
|
175
320
|
responsive: true,
|
|
176
321
|
maintainAspectRatio: false,
|
|
322
|
+
// Chart.js's own mechanism for horizontal bars (also flips line/area
|
|
323
|
+
// types onto a horizontal category axis).
|
|
324
|
+
indexAxis: this.horizontal ? 'y' : undefined,
|
|
325
|
+
// Chart.js's own default ~1000ms draw-in animation only ever fires
|
|
326
|
+
// from `new Chart()` (chart/type-change construction) — every
|
|
327
|
+
// in-place update in `draw()` already passes `'none'` to
|
|
328
|
+
// `Chart#update()`. A CSS media query can't reach that
|
|
329
|
+
// canvas-internal animation loop, so `prefersReducedMotion()` is
|
|
330
|
+
// checked here instead and fed into `options.animation`.
|
|
331
|
+
animation: prefersReducedMotion() ? false : undefined,
|
|
177
332
|
interaction: { intersect: false, mode: this.type === 'scatter' ? 'nearest' : 'index' },
|
|
333
|
+
onClick: (event, _elements, chart) => this.handlePointClick(event, chart),
|
|
178
334
|
plugins: {
|
|
179
|
-
legend: { display: this.legend },
|
|
335
|
+
legend: { display: this.legend, labels: { color: theme.legend } },
|
|
336
|
+
tooltip: {
|
|
337
|
+
backgroundColor: theme.tooltipBg,
|
|
338
|
+
titleColor: theme.tooltipText,
|
|
339
|
+
bodyColor: theme.tooltipText,
|
|
340
|
+
},
|
|
180
341
|
zoom: this.zoom
|
|
181
342
|
? {
|
|
182
343
|
pan: { enabled: false },
|
|
@@ -186,6 +347,8 @@ export class LyraChart extends LyraElement {
|
|
|
186
347
|
pinch: { enabled: true },
|
|
187
348
|
mode: 'x',
|
|
188
349
|
onZoomComplete: () => {
|
|
350
|
+
if (this.suppressZoomComplete)
|
|
351
|
+
return;
|
|
189
352
|
this.zoomed = true;
|
|
190
353
|
this.emit('lyra-zoom', { zoomed: true });
|
|
191
354
|
},
|
|
@@ -194,7 +357,7 @@ export class LyraChart extends LyraElement {
|
|
|
194
357
|
}
|
|
195
358
|
: undefined,
|
|
196
359
|
},
|
|
197
|
-
scales: this.buildScales(),
|
|
360
|
+
scales: this.buildScales(theme),
|
|
198
361
|
},
|
|
199
362
|
};
|
|
200
363
|
if (!this.config)
|
|
@@ -223,10 +386,28 @@ export class LyraChart extends LyraElement {
|
|
|
223
386
|
}
|
|
224
387
|
/** Reset any active zoom/pan back to the original view. */
|
|
225
388
|
resetZoom() {
|
|
226
|
-
this.
|
|
389
|
+
this.suppressZoomComplete = true;
|
|
390
|
+
try {
|
|
391
|
+
this.chart?.resetZoom?.();
|
|
392
|
+
}
|
|
393
|
+
finally {
|
|
394
|
+
this.suppressZoomComplete = false;
|
|
395
|
+
}
|
|
227
396
|
this.zoomed = false;
|
|
228
397
|
this.emit('lyra-zoom', { zoomed: false });
|
|
229
398
|
}
|
|
399
|
+
/**
|
|
400
|
+
* Forces a redraw so `themeColors()` re-reads the `--lyra-chart-*` custom
|
|
401
|
+
* properties from the current computed style. No global theme-broadcast
|
|
402
|
+
* event exists anywhere in lyra-ui (nothing to subscribe to here) — this
|
|
403
|
+
* is the escape hatch for a consumer's own theme-toggle handler to call
|
|
404
|
+
* directly when it flips e.g. a `data-theme` attribute upstream that
|
|
405
|
+
* doesn't otherwise change any `lyra-chart` property, so Lit's reactive
|
|
406
|
+
* update loop has nothing of its own to trigger `draw()` on.
|
|
407
|
+
*/
|
|
408
|
+
refreshTheme() {
|
|
409
|
+
this.draw();
|
|
410
|
+
}
|
|
230
411
|
render() {
|
|
231
412
|
if (this.loading) {
|
|
232
413
|
return html `
|
|
@@ -281,6 +462,12 @@ __decorate([
|
|
|
281
462
|
__decorate([
|
|
282
463
|
property({ type: Boolean, attribute: 'begin-at-zero' })
|
|
283
464
|
], LyraChart.prototype, "beginAtZero", void 0);
|
|
465
|
+
__decorate([
|
|
466
|
+
property({ type: Boolean })
|
|
467
|
+
], LyraChart.prototype, "horizontal", void 0);
|
|
468
|
+
__decorate([
|
|
469
|
+
property({ type: Boolean })
|
|
470
|
+
], LyraChart.prototype, "stacked", void 0);
|
|
284
471
|
__decorate([
|
|
285
472
|
property({ attribute: false })
|
|
286
473
|
], LyraChart.prototype, "config", void 0);
|
|
@@ -290,6 +477,9 @@ __decorate([
|
|
|
290
477
|
__decorate([
|
|
291
478
|
state()
|
|
292
479
|
], LyraChart.prototype, "zoomed", void 0);
|
|
480
|
+
__decorate([
|
|
481
|
+
state()
|
|
482
|
+
], LyraChart.prototype, "visible", void 0);
|
|
293
483
|
__decorate([
|
|
294
484
|
query('canvas')
|
|
295
485
|
], LyraChart.prototype, "canvasEl", void 0);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/web-components-vite';
|
|
2
|
+
declare const meta: Meta;
|
|
3
|
+
export default meta;
|
|
4
|
+
type Story = StoryObj;
|
|
5
|
+
export declare const Default: Story;
|
|
6
|
+
/**
|
|
7
|
+
* The `config` property is the raw Chart.js passthrough escape hatch — it is
|
|
8
|
+
* deep-merged over the `Series`-generated config, so a nested key like
|
|
9
|
+
* `options.plugins.title` can be set without discarding the rest of the
|
|
10
|
+
* generated config the `type`/`labels`/`datasets` attributes produce.
|
|
11
|
+
*/
|
|
12
|
+
export declare const ConfigPassthrough: Story;
|
|
13
|
+
/** `horizontal` sets Chart.js's `indexAxis: 'y'`, flipping bars onto a horizontal axis. */
|
|
14
|
+
export declare const Horizontal: Story;
|
|
15
|
+
/** `stacked` stacks every dataset sharing an axis on top of each other instead of side by side. */
|
|
16
|
+
export declare const Stacked: Story;
|
|
17
|
+
/**
|
|
18
|
+
* The `--lyra-chart-grid-color`/`-tick-color`/`-legend-color`/`-tooltip-bg`/
|
|
19
|
+
* `-tooltip-text` custom properties retheme Chart.js's canvas-drawn chrome
|
|
20
|
+
* (grid lines, axis ticks/titles, legend labels, tooltip). Chart.js can't
|
|
21
|
+
* consume `var()` directly, so these are resolved via `getComputedStyle`
|
|
22
|
+
* once per draw — see `themeColors()` in `chart.ts`.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ThemedTokens: Story;
|
|
25
|
+
/**
|
|
26
|
+
* `lyra-point-click` fires whenever a click lands on (or nearest,
|
|
27
|
+
* intersect-only) a data point/segment — covers any `type`, not just bars.
|
|
28
|
+
* `refreshTheme()` forces a redraw so an out-of-band theme change (e.g. a
|
|
29
|
+
* host-level dark-mode toggle that doesn't touch any `lyra-chart` property)
|
|
30
|
+
* is picked up immediately, rather than waiting for the next reactive update.
|
|
31
|
+
*/
|
|
32
|
+
export declare const PointClickAndRefreshTheme: Story;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { html } from 'lit';
|
|
2
|
+
const meta = {
|
|
3
|
+
title: 'Charts/Chart',
|
|
4
|
+
component: 'lyra-chart',
|
|
5
|
+
tags: ['autodocs'],
|
|
6
|
+
};
|
|
7
|
+
export default meta;
|
|
8
|
+
export const Default = {
|
|
9
|
+
render: () => {
|
|
10
|
+
const series = [{ label: 'Revenue', data: [12, 19, 14, 22] }];
|
|
11
|
+
return html `
|
|
12
|
+
<lyra-chart
|
|
13
|
+
type="bar"
|
|
14
|
+
height="16rem"
|
|
15
|
+
style="width: 22rem"
|
|
16
|
+
legend
|
|
17
|
+
.labels=${['Q1', 'Q2', 'Q3', 'Q4']}
|
|
18
|
+
.datasets=${series}
|
|
19
|
+
></lyra-chart>
|
|
20
|
+
`;
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The `config` property is the raw Chart.js passthrough escape hatch — it is
|
|
25
|
+
* deep-merged over the `Series`-generated config, so a nested key like
|
|
26
|
+
* `options.plugins.title` can be set without discarding the rest of the
|
|
27
|
+
* generated config the `type`/`labels`/`datasets` attributes produce.
|
|
28
|
+
*/
|
|
29
|
+
export const ConfigPassthrough = {
|
|
30
|
+
render: () => {
|
|
31
|
+
const series = [{ label: 'Revenue', data: [12, 19, 14, 22] }];
|
|
32
|
+
return html `
|
|
33
|
+
<lyra-chart
|
|
34
|
+
type="bar"
|
|
35
|
+
height="16rem"
|
|
36
|
+
style="width: 22rem"
|
|
37
|
+
.labels=${['Q1', 'Q2', 'Q3', 'Q4']}
|
|
38
|
+
.datasets=${series}
|
|
39
|
+
.config=${{
|
|
40
|
+
options: { plugins: { title: { display: true, text: 'Quarterly revenue' } } },
|
|
41
|
+
}}
|
|
42
|
+
></lyra-chart>
|
|
43
|
+
`;
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
/** `horizontal` sets Chart.js's `indexAxis: 'y'`, flipping bars onto a horizontal axis. */
|
|
47
|
+
export const Horizontal = {
|
|
48
|
+
render: () => {
|
|
49
|
+
const series = [{ label: 'Revenue', data: [12, 19, 14, 22] }];
|
|
50
|
+
return html `
|
|
51
|
+
<lyra-chart
|
|
52
|
+
type="bar"
|
|
53
|
+
horizontal
|
|
54
|
+
height="16rem"
|
|
55
|
+
style="width: 22rem"
|
|
56
|
+
.labels=${['Q1', 'Q2', 'Q3', 'Q4']}
|
|
57
|
+
.datasets=${series}
|
|
58
|
+
></lyra-chart>
|
|
59
|
+
`;
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
/** `stacked` stacks every dataset sharing an axis on top of each other instead of side by side. */
|
|
63
|
+
export const Stacked = {
|
|
64
|
+
render: () => {
|
|
65
|
+
const series = [
|
|
66
|
+
{ label: 'Product A', data: [12, 19, 14, 22] },
|
|
67
|
+
{ label: 'Product B', data: [8, 11, 9, 15] },
|
|
68
|
+
];
|
|
69
|
+
return html `
|
|
70
|
+
<lyra-chart
|
|
71
|
+
type="bar"
|
|
72
|
+
stacked
|
|
73
|
+
legend
|
|
74
|
+
height="16rem"
|
|
75
|
+
style="width: 22rem"
|
|
76
|
+
.labels=${['Q1', 'Q2', 'Q3', 'Q4']}
|
|
77
|
+
.datasets=${series}
|
|
78
|
+
></lyra-chart>
|
|
79
|
+
`;
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* The `--lyra-chart-grid-color`/`-tick-color`/`-legend-color`/`-tooltip-bg`/
|
|
84
|
+
* `-tooltip-text` custom properties retheme Chart.js's canvas-drawn chrome
|
|
85
|
+
* (grid lines, axis ticks/titles, legend labels, tooltip). Chart.js can't
|
|
86
|
+
* consume `var()` directly, so these are resolved via `getComputedStyle`
|
|
87
|
+
* once per draw — see `themeColors()` in `chart.ts`.
|
|
88
|
+
*/
|
|
89
|
+
export const ThemedTokens = {
|
|
90
|
+
render: () => {
|
|
91
|
+
const series = [{ label: 'Revenue', data: [12, 19, 14, 22] }];
|
|
92
|
+
return html `
|
|
93
|
+
<lyra-chart
|
|
94
|
+
type="bar"
|
|
95
|
+
legend
|
|
96
|
+
height="16rem"
|
|
97
|
+
style="
|
|
98
|
+
width: 22rem;
|
|
99
|
+
--lyra-chart-grid-color: #e5484d;
|
|
100
|
+
--lyra-chart-tick-color: #e5484d;
|
|
101
|
+
--lyra-chart-legend-color: #e5484d;
|
|
102
|
+
--lyra-chart-tooltip-bg: #1a1a1a;
|
|
103
|
+
--lyra-chart-tooltip-text: #fff;
|
|
104
|
+
"
|
|
105
|
+
.labels=${['Q1', 'Q2', 'Q3', 'Q4']}
|
|
106
|
+
.datasets=${series}
|
|
107
|
+
></lyra-chart>
|
|
108
|
+
`;
|
|
109
|
+
},
|
|
110
|
+
};
|
|
111
|
+
/**
|
|
112
|
+
* `lyra-point-click` fires whenever a click lands on (or nearest,
|
|
113
|
+
* intersect-only) a data point/segment — covers any `type`, not just bars.
|
|
114
|
+
* `refreshTheme()` forces a redraw so an out-of-band theme change (e.g. a
|
|
115
|
+
* host-level dark-mode toggle that doesn't touch any `lyra-chart` property)
|
|
116
|
+
* is picked up immediately, rather than waiting for the next reactive update.
|
|
117
|
+
*/
|
|
118
|
+
export const PointClickAndRefreshTheme = {
|
|
119
|
+
render: () => {
|
|
120
|
+
const series = [{ label: 'Revenue', data: [12, 19, 14, 22] }];
|
|
121
|
+
return html `
|
|
122
|
+
<lyra-chart
|
|
123
|
+
type="bar"
|
|
124
|
+
height="16rem"
|
|
125
|
+
style="width: 22rem"
|
|
126
|
+
.labels=${['Q1', 'Q2', 'Q3', 'Q4']}
|
|
127
|
+
.datasets=${series}
|
|
128
|
+
@lyra-point-click=${(e) => console.log('lyra-point-click', e.detail)}
|
|
129
|
+
></lyra-chart>
|
|
130
|
+
<button
|
|
131
|
+
type="button"
|
|
132
|
+
@click=${(e) => {
|
|
133
|
+
const chart = e.target.previousElementSibling;
|
|
134
|
+
chart.refreshTheme();
|
|
135
|
+
}}
|
|
136
|
+
>
|
|
137
|
+
refreshTheme()
|
|
138
|
+
</button>
|
|
139
|
+
`;
|
|
140
|
+
},
|
|
141
|
+
};
|
|
@@ -4,6 +4,18 @@ export const styles = css `
|
|
|
4
4
|
display: block;
|
|
5
5
|
position: relative;
|
|
6
6
|
block-size: var(--lyra-chart-height, 280px);
|
|
7
|
+
/* Chart.js renders to canvas, not the DOM, so it can't consume CSS
|
|
8
|
+
var() directly — chart.ts's themeColors() resolves these once per
|
|
9
|
+
draw() via getComputedStyle, same pattern as heatmap.ts's scale-lo/-hi.
|
|
10
|
+
Each is its own token (rather than reusing the semantic ones directly)
|
|
11
|
+
so a host can retheme just the chart's grid/ticks/legend/tooltip
|
|
12
|
+
without affecting unrelated text/border/surface colors elsewhere in
|
|
13
|
+
the component, while still defaulting to those semantic tokens. */
|
|
14
|
+
--lyra-chart-grid-color: var(--lyra-color-border);
|
|
15
|
+
--lyra-chart-tick-color: var(--lyra-color-text-quiet);
|
|
16
|
+
--lyra-chart-legend-color: var(--lyra-color-text);
|
|
17
|
+
--lyra-chart-tooltip-bg: var(--lyra-color-surface);
|
|
18
|
+
--lyra-chart-tooltip-text: var(--lyra-color-text);
|
|
7
19
|
}
|
|
8
20
|
[part='base'] {
|
|
9
21
|
position: relative;
|
|
@@ -30,4 +42,8 @@ export const styles = css `
|
|
|
30
42
|
color: var(--lyra-color-text);
|
|
31
43
|
cursor: pointer;
|
|
32
44
|
}
|
|
45
|
+
[part='reset-zoom-button']:focus-visible {
|
|
46
|
+
outline: var(--lyra-focus-ring-width) solid var(--lyra-focus-ring-color);
|
|
47
|
+
outline-offset: var(--lyra-focus-ring-offset);
|
|
48
|
+
}
|
|
33
49
|
`;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { LyraChart } from './chart.js';
|
|
2
|
+
import { type HistogramBucket } from './histogram-bin.js';
|
|
2
3
|
/**
|
|
3
4
|
* `<lyra-histogram>` — bins `values` into `bins` equal-width buckets and
|
|
4
5
|
* renders them as a bar chart. Chart.js has no built-in histogram
|
|
@@ -13,6 +14,7 @@ export declare class LyraHistogram extends LyraChart {
|
|
|
13
14
|
values: number[];
|
|
14
15
|
label: string;
|
|
15
16
|
}
|
|
17
|
+
export declare function binnedBuckets(el: LyraHistogram): HistogramBucket[];
|
|
16
18
|
declare global {
|
|
17
19
|
interface HTMLElementTagNameMap {
|
|
18
20
|
'lyra-histogram': LyraHistogram;
|