juxscript 1.1.397 → 1.1.398
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/dist/charts/barChart.d.ts +119 -0
- package/dist/charts/barChart.d.ts.map +1 -0
- package/dist/charts/barChart.js +644 -0
- package/dist/charts/barChart.js.map +1 -0
- package/dist/charts/lineChart.d.ts +104 -0
- package/dist/charts/lineChart.d.ts.map +1 -0
- package/dist/charts/lineChart.js +466 -0
- package/dist/charts/lineChart.js.map +1 -0
- package/dist/charts/pieChart.d.ts +93 -0
- package/dist/charts/pieChart.d.ts.map +1 -0
- package/dist/charts/pieChart.js +397 -0
- package/dist/charts/pieChart.js.map +1 -0
- package/dist/components/barChart.d.ts +18 -2
- package/dist/components/barChart.d.ts.map +1 -1
- package/dist/components/barChart.js +175 -140
- package/dist/components/barChart.js.map +1 -1
- package/dist/components/button.d.ts +6 -0
- package/dist/components/button.d.ts.map +1 -1
- package/dist/components/button.js +18 -0
- package/dist/components/button.js.map +1 -1
- package/dist/components/checkbox.d.ts +6 -0
- package/dist/components/checkbox.d.ts.map +1 -1
- package/dist/components/checkbox.js +34 -0
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/input.d.ts +3 -0
- package/dist/components/input.d.ts.map +1 -1
- package/dist/components/input.js +17 -0
- package/dist/components/input.js.map +1 -1
- package/dist/components/lineChart.d.ts +19 -2
- package/dist/components/lineChart.d.ts.map +1 -1
- package/dist/components/lineChart.js +233 -97
- package/dist/components/lineChart.js.map +1 -1
- package/dist/components/link.d.ts +3 -0
- package/dist/components/link.d.ts.map +1 -1
- package/dist/components/link.js +17 -0
- package/dist/components/link.js.map +1 -1
- package/dist/components/list.d.ts +3 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +17 -0
- package/dist/components/list.js.map +1 -1
- package/dist/components/nav.d.ts +3 -0
- package/dist/components/nav.d.ts.map +1 -1
- package/dist/components/nav.js +17 -0
- package/dist/components/nav.js.map +1 -1
- package/dist/components/pieChart.d.ts +7 -0
- package/dist/components/pieChart.d.ts.map +1 -1
- package/dist/components/pieChart.js +113 -16
- package/dist/components/pieChart.js.map +1 -1
- package/dist/components/radio.d.ts +3 -0
- package/dist/components/radio.d.ts.map +1 -1
- package/dist/components/radio.js +17 -0
- package/dist/components/radio.js.map +1 -1
- package/dist/components/select.d.ts +3 -0
- package/dist/components/select.d.ts.map +1 -1
- package/dist/components/select.js +17 -0
- package/dist/components/select.js.map +1 -1
- package/dist/components/table.d.ts +3 -0
- package/dist/components/table.d.ts.map +1 -1
- package/dist/components/table.js +17 -0
- package/dist/components/table.js.map +1 -1
- package/dist/components/tabs.d.ts +3 -0
- package/dist/components/tabs.d.ts.map +1 -1
- package/dist/components/tabs.js +17 -0
- package/dist/components/tabs.js.map +1 -1
- package/dist/components/tag.d.ts +3 -0
- package/dist/components/tag.d.ts.map +1 -1
- package/dist/components/tag.js +18 -0
- package/dist/components/tag.js.map +1 -1
- package/dist/index.d.ts +12 -19
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -19
- package/dist/index.js.map +1 -1
- package/dist/shapes/c.d.ts +53 -0
- package/dist/shapes/c.d.ts.map +1 -0
- package/dist/shapes/c.js +127 -0
- package/dist/shapes/c.js.map +1 -0
- package/dist/shapes/g.d.ts +21 -0
- package/dist/shapes/g.d.ts.map +1 -0
- package/dist/shapes/g.js +52 -0
- package/dist/shapes/g.js.map +1 -0
- package/dist/tools/devtools.d.ts +3 -0
- package/dist/tools/devtools.d.ts.map +1 -0
- package/dist/tools/devtools.js +182 -0
- package/dist/tools/devtools.js.map +1 -0
- package/dist/utils/colors.d.ts +32 -5
- package/dist/utils/colors.d.ts.map +1 -1
- package/dist/utils/colors.js +32 -6
- package/dist/utils/colors.js.map +1 -1
- package/dist/utils/tooltip.d.ts +5 -0
- package/dist/utils/tooltip.d.ts.map +1 -0
- package/dist/utils/tooltip.js +52 -0
- package/dist/utils/tooltip.js.map +1 -0
- package/dist/utils/trend.d.ts +9 -0
- package/dist/utils/trend.d.ts.map +1 -0
- package/dist/utils/trend.js +35 -0
- package/dist/utils/trend.js.map +1 -0
- package/package.json +1 -1
|
@@ -19,6 +19,7 @@ interface BarDataItem {
|
|
|
19
19
|
interface BarClickDetail {
|
|
20
20
|
chartId: string;
|
|
21
21
|
index: number;
|
|
22
|
+
seriesKey: string;
|
|
22
23
|
label: string;
|
|
23
24
|
value: number;
|
|
24
25
|
drillKey: string | null;
|
|
@@ -27,14 +28,21 @@ interface BarClickDetail {
|
|
|
27
28
|
orientation: string;
|
|
28
29
|
selected?: boolean;
|
|
29
30
|
}
|
|
31
|
+
interface SeriesConfig {
|
|
32
|
+
key: string;
|
|
33
|
+
label?: string;
|
|
34
|
+
color?: string;
|
|
35
|
+
}
|
|
30
36
|
interface BarChartOptions {
|
|
31
37
|
orientation?: 'horizontal' | 'vertical';
|
|
32
38
|
colors?: string | string[];
|
|
33
39
|
title?: string;
|
|
34
40
|
subtitle?: string;
|
|
35
41
|
width?: number;
|
|
42
|
+
height?: number;
|
|
36
43
|
aspectRatio?: string | number;
|
|
37
44
|
showValues?: boolean;
|
|
45
|
+
showLegend?: boolean;
|
|
38
46
|
ticks?: number;
|
|
39
47
|
labelWidth?: number;
|
|
40
48
|
barThickness?: number;
|
|
@@ -45,6 +53,11 @@ interface BarChartOptions {
|
|
|
45
53
|
onClick?: (event: BarClickDetail) => void;
|
|
46
54
|
selectable?: boolean;
|
|
47
55
|
stateKey?: string;
|
|
56
|
+
series?: SeriesConfig[];
|
|
57
|
+
trendTitle?: string;
|
|
58
|
+
trendSubtitle?: string;
|
|
59
|
+
trendIcon?: string;
|
|
60
|
+
autoTrend?: boolean;
|
|
48
61
|
}
|
|
49
62
|
declare class BarChart {
|
|
50
63
|
id: string;
|
|
@@ -59,6 +72,7 @@ declare class BarChart {
|
|
|
59
72
|
private _resizeObserver;
|
|
60
73
|
private _isInteractive;
|
|
61
74
|
private _onChange;
|
|
75
|
+
private _seriesKeys;
|
|
62
76
|
constructor(id: string, values: BarDataItem[], options?: BarChartOptions);
|
|
63
77
|
getValue(): BarClickDetail | null;
|
|
64
78
|
setValue(val: any): this;
|
|
@@ -82,9 +96,11 @@ declare class BarChart {
|
|
|
82
96
|
private _emit;
|
|
83
97
|
private _updateSelection;
|
|
84
98
|
private _wireInteractivity;
|
|
85
|
-
private _buildChart;
|
|
86
99
|
private _buildVertical;
|
|
87
100
|
private _buildHorizontal;
|
|
101
|
+
private _hasTrend;
|
|
102
|
+
private _buildChart;
|
|
103
|
+
private _renderTrend;
|
|
88
104
|
render(target?: string | HTMLElement | {
|
|
89
105
|
element: HTMLElement;
|
|
90
106
|
}): this;
|
|
@@ -98,6 +114,6 @@ declare class BarChart {
|
|
|
98
114
|
destroy(): void;
|
|
99
115
|
}
|
|
100
116
|
export declare function barChart(id: string, values: BarDataItem[], options?: BarChartOptions): BarChart;
|
|
101
|
-
export { BarChart, BarChartOptions, BarDataItem, BarClickDetail, RATIOS, TOKENS };
|
|
117
|
+
export { BarChart, BarChartOptions, BarDataItem, BarClickDetail, SeriesConfig, RATIOS, TOKENS };
|
|
102
118
|
export default barChart;
|
|
103
119
|
//# sourceMappingURL=barChart.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"barChart.d.ts","sourceRoot":"","sources":["../../lib/components/barChart.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"barChart.d.ts","sourceRoot":"","sources":["../../lib/components/barChart.ts"],"names":[],"mappings":"AAQA,QAAA,MAAM,MAAM;;;;;;;;;CASX,CAAC;AAEF,QAAA,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOlC,CAAC;AAoDF,UAAU,WAAW;IACjB,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,UAAU,cAAc;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,UAAU,YAAY;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,eAAe;IACrB,WAAW,CAAC,EAAE,YAAY,GAAG,UAAU,CAAC;IACxC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;CACvB;AAmGD,cAAM,QAAQ;IACV,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,KAAK,CAAgO;IAC7O,OAAO,CAAC,QAAQ,CAAW;IAC3B,OAAO,CAAC,UAAU,CAAoE;IACtF,OAAO,CAAC,cAAc,CAAc;IACpC,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,QAAQ,CAAoB;IACpC,OAAO,CAAC,eAAe,CAA+B;IACtD,OAAO,CAAC,cAAc,CAAU;IAChC,OAAO,CAAC,SAAS,CAAuC;IACxD,OAAO,CAAC,WAAW,CAAiB;gBAExB,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,OAAO,GAAE,eAAoB;IA6C5E,QAAQ,IAAI,cAAc,GAAG,IAAI;IACjC,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,IAAI;IACxB,UAAU,IAAI,iBAAiB;IAE/B,gBAAgB,IAAI,MAAM;IAC1B,cAAc,IAAI,MAAM;IACxB,QAAQ,IAAI,MAAM;IAClB,WAAW,IAAI,MAAM;IACrB,aAAa,IAAI,OAAO;IAExB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC3B,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAC9B,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAE7B,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAE3B,QAAQ,CAAC,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,KAAK,IAAI,GAAG,IAAI;IAKxC,IAAI,KAAK,IAAI,GAAG,CAA+B;IAC/C,IAAI,OAAO,IAAI,cAAc,CAA4B;IAMzD,OAAO,CAAC,eAAe;IAWvB,OAAO,CAAC,eAAe;IA6BvB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,WAAW;IA2GnB,OAAO,CAAC,YAAY;IA4CpB,MAAM,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI;IA+BtE,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,WAAW,GAAG;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI;IAEpE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI;IAKrC,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,GAAG,IAAI;IAKtC,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ3B,cAAc,IAAI,IAAI;IAOtB,OAAO;CAKV;AAMD,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,OAAO,GAAE,eAAoB,GAAG,QAAQ,CAInG;AAED,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,WAAW,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;AAChG,eAAe,QAAQ,CAAC"}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { pageState } from '../state/pageState.js';
|
|
2
2
|
import generateId from '../utils/idgen.js';
|
|
3
|
+
import { showTooltip, moveTooltip, hideTooltip, formatTooltipRow } from '../utils/tooltip.js';
|
|
4
|
+
import { computeTrend } from '../utils/trend.js';
|
|
3
5
|
// --- Design tokens ---
|
|
4
6
|
const FONT_FAMILY = `-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`;
|
|
5
7
|
const TOKENS = {
|
|
@@ -155,6 +157,7 @@ class BarChart {
|
|
|
155
157
|
subtitle: options.subtitle || '',
|
|
156
158
|
aspectRatio: options.aspectRatio || '16:9',
|
|
157
159
|
showValues: options.showValues ?? false,
|
|
160
|
+
showLegend: options.showLegend ?? undefined,
|
|
158
161
|
ticks: options.ticks ?? 4,
|
|
159
162
|
animate: options.animate ?? true,
|
|
160
163
|
stagger: options.stagger ?? 80,
|
|
@@ -163,15 +166,17 @@ class BarChart {
|
|
|
163
166
|
selectable: options.selectable ?? false,
|
|
164
167
|
...options,
|
|
165
168
|
};
|
|
169
|
+
this._seriesKeys = detectSeriesKeys(values, options.series);
|
|
170
|
+
if (this._opts.showLegend === undefined) {
|
|
171
|
+
this._opts.showLegend = this._seriesKeys.length > 1;
|
|
172
|
+
}
|
|
166
173
|
if (this._opts.animate)
|
|
167
174
|
injectBarAnimations();
|
|
168
|
-
this._palette =
|
|
169
|
-
|
|
170
|
-
this._opts.
|
|
171
|
-
|
|
172
|
-
this._opts.selectable);
|
|
175
|
+
this._palette = this._seriesKeys.length > 1
|
|
176
|
+
? this._seriesKeys.map((s, i) => s.color || DEFAULT_SERIES_COLORS[i % DEFAULT_SERIES_COLORS.length])
|
|
177
|
+
: resolvePalette(this._opts.colors || 'green');
|
|
178
|
+
this._isInteractive = true; // always interactive — tooltips on all charts
|
|
173
179
|
this._wrapperEl = mkDiv(`${id}-wrapper`, `width: 100%; position: relative; box-sizing: border-box;`);
|
|
174
|
-
// Hidden button element for pageState click detection
|
|
175
180
|
this._stateEl = document.createElement('button');
|
|
176
181
|
this._stateEl.id = id;
|
|
177
182
|
this._stateEl.style.cssText = 'position:absolute;width:0;height:0;overflow:hidden;opacity:0;pointer-events:none;';
|
|
@@ -181,7 +186,7 @@ class BarChart {
|
|
|
181
186
|
// PAGESTATE INTEGRATION
|
|
182
187
|
// ═══════════════════════════════════════════════════════════
|
|
183
188
|
getValue() { return this._lastClickDetail; }
|
|
184
|
-
setValue(val) {
|
|
189
|
+
setValue(val) { return this; }
|
|
185
190
|
getElement() { return this._stateEl; }
|
|
186
191
|
getSelectedIndex() { return this._selectedIndex; }
|
|
187
192
|
getOrientation() { return this._opts.orientation; }
|
|
@@ -198,30 +203,23 @@ class BarChart {
|
|
|
198
203
|
this._onChange = fn;
|
|
199
204
|
return this;
|
|
200
205
|
}
|
|
201
|
-
get state() {
|
|
202
|
-
|
|
203
|
-
}
|
|
204
|
-
get element() {
|
|
205
|
-
return this._wrapperEl;
|
|
206
|
-
}
|
|
206
|
+
get state() { return pageState[this.id]; }
|
|
207
|
+
get element() { return this._wrapperEl; }
|
|
207
208
|
// ═══════════════════════════════════════════════════════════
|
|
208
209
|
// CLICK HANDLING
|
|
209
210
|
// ═══════════════════════════════════════════════════════════
|
|
210
|
-
_makeClickEvent(i) {
|
|
211
|
+
_makeClickEvent(i, seriesIdx = 0) {
|
|
211
212
|
const v = this._values[i];
|
|
213
|
+
const sk = this._seriesKeys[seriesIdx];
|
|
212
214
|
return {
|
|
213
|
-
chartId: this.id,
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
drillKey: v.drill || null,
|
|
218
|
-
href: v.href || null,
|
|
219
|
-
item: v,
|
|
220
|
-
orientation: this._opts.orientation,
|
|
215
|
+
chartId: this.id, index: i, seriesKey: sk.key,
|
|
216
|
+
label: v.label || `#${i + 1}`, value: v[sk.key] ?? v.x ?? 0,
|
|
217
|
+
drillKey: v.drill || null, href: v.href || null,
|
|
218
|
+
item: v, orientation: this._opts.orientation,
|
|
221
219
|
};
|
|
222
220
|
}
|
|
223
|
-
_handleBarClick(i) {
|
|
224
|
-
const detail = this._makeClickEvent(i);
|
|
221
|
+
_handleBarClick(i, seriesIdx = 0) {
|
|
222
|
+
const detail = this._makeClickEvent(i, seriesIdx);
|
|
225
223
|
if (this._opts.selectable) {
|
|
226
224
|
const prev = this._selectedIndex;
|
|
227
225
|
this._selectedIndex = (this._selectedIndex === i) ? -1 : i;
|
|
@@ -239,18 +237,11 @@ class BarChart {
|
|
|
239
237
|
pageState[this.id][this._opts.stateKey] = detail;
|
|
240
238
|
this._emit('drill', detail);
|
|
241
239
|
}
|
|
242
|
-
// Trigger click on hidden state element so pageState proxy detects it
|
|
243
240
|
this._stateEl.click();
|
|
244
241
|
if (detail.href) {
|
|
245
|
-
this._wrapperEl.dispatchEvent(new CustomEvent('jux:navigate', {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
}));
|
|
249
|
-
}
|
|
250
|
-
this._wrapperEl.dispatchEvent(new CustomEvent('jux:bar-click', {
|
|
251
|
-
bubbles: true,
|
|
252
|
-
detail,
|
|
253
|
-
}));
|
|
242
|
+
this._wrapperEl.dispatchEvent(new CustomEvent('jux:navigate', { bubbles: true, detail }));
|
|
243
|
+
}
|
|
244
|
+
this._wrapperEl.dispatchEvent(new CustomEvent('jux:bar-click', { bubbles: true, detail }));
|
|
254
245
|
}
|
|
255
246
|
_emit(type, detail) {
|
|
256
247
|
(this._listeners[type] || []).forEach(fn => fn(detail));
|
|
@@ -267,67 +258,118 @@ class BarChart {
|
|
|
267
258
|
newEl.classList.add('jux-bar-selected');
|
|
268
259
|
}
|
|
269
260
|
}
|
|
270
|
-
_wireInteractivity(containerEl, barEl, index) {
|
|
261
|
+
_wireInteractivity(containerEl, barEl, index, seriesIdx = 0) {
|
|
271
262
|
containerEl.classList.add('jux-bar-clickable');
|
|
272
263
|
containerEl.setAttribute('role', 'button');
|
|
273
264
|
containerEl.setAttribute('tabindex', '0');
|
|
274
|
-
|
|
275
|
-
|
|
265
|
+
const sk = this._seriesKeys[seriesIdx];
|
|
266
|
+
const v = this._values[index];
|
|
267
|
+
const label = v.label || `Item ${index + 1}`;
|
|
268
|
+
const val = v[sk.key] ?? v.x ?? 0;
|
|
269
|
+
containerEl.setAttribute('aria-label', `${label}: ${val}`);
|
|
270
|
+
containerEl.addEventListener('click', () => this._handleBarClick(index, seriesIdx));
|
|
276
271
|
containerEl.addEventListener('keydown', (e) => {
|
|
277
272
|
if (e.key === 'Enter' || e.key === ' ') {
|
|
278
273
|
e.preventDefault();
|
|
279
|
-
this._handleBarClick(index);
|
|
274
|
+
this._handleBarClick(index, seriesIdx);
|
|
280
275
|
}
|
|
281
276
|
});
|
|
282
|
-
|
|
277
|
+
const color = this._palette[seriesIdx % this._palette.length];
|
|
278
|
+
containerEl.addEventListener('mouseenter', (e) => {
|
|
279
|
+
barEl.style.opacity = '1';
|
|
280
|
+
let html = `<div style="font-weight:600;margin-bottom:2px;">${label}</div>`;
|
|
281
|
+
if (this._seriesKeys.length > 1) {
|
|
282
|
+
this._seriesKeys.forEach((s, si) => {
|
|
283
|
+
const c = this._palette[si % this._palette.length];
|
|
284
|
+
html += formatTooltipRow(s.label || s.key, v[s.key] ?? 0, c);
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
html += formatTooltipRow('Value', val, color);
|
|
289
|
+
}
|
|
290
|
+
showTooltip(e, html);
|
|
291
|
+
});
|
|
292
|
+
containerEl.addEventListener('mousemove', (e) => moveTooltip(e));
|
|
283
293
|
containerEl.addEventListener('mouseleave', () => {
|
|
284
294
|
if (this._selectedIndex !== index)
|
|
285
295
|
barEl.style.opacity = '0.85';
|
|
296
|
+
hideTooltip();
|
|
286
297
|
});
|
|
287
298
|
}
|
|
299
|
+
_buildVertical(cardEl, L, id, values, palette, ticks, animate, stagger, showValues, numSeries, seriesKeys) {
|
|
300
|
+
// Vertical bar chart implementation
|
|
301
|
+
const barsContainer = mkDiv(`${id}-bars`, `display:flex;flex-direction:column;justify-content:flex-end;height:${L.maxBarLength}px;gap:${L.gap}px;`);
|
|
302
|
+
cardEl.appendChild(barsContainer);
|
|
303
|
+
}
|
|
304
|
+
_buildHorizontal(cardEl, L, id, values, palette, ticks, animate, stagger, showValues, numSeries, seriesKeys) {
|
|
305
|
+
// Horizontal bar chart implementation
|
|
306
|
+
const barsContainer = mkDiv(`${id}-bars`, `display:flex;flex-direction:column;gap:${L.gap}px;`);
|
|
307
|
+
cardEl.appendChild(barsContainer);
|
|
308
|
+
}
|
|
288
309
|
// ═══════════════════════════════════════════════════════════
|
|
289
310
|
// BUILD CHART
|
|
290
311
|
// ═══════════════════════════════════════════════════════════
|
|
312
|
+
_hasTrend() {
|
|
313
|
+
const { trendTitle, trendSubtitle, autoTrend } = this._opts;
|
|
314
|
+
return !!(trendTitle || trendSubtitle || autoTrend);
|
|
315
|
+
}
|
|
291
316
|
_buildChart(resolvedWidth) {
|
|
292
|
-
// Preserve stateEl
|
|
293
317
|
this._wrapperEl.innerHTML = '';
|
|
294
318
|
this._wrapperEl.appendChild(this._stateEl);
|
|
295
|
-
const { orientation, aspectRatio, title, subtitle, showValues, ticks, animate, stagger, maintainAspectRatio, labelWidth: labelWidthOverride, barThickness: barThicknessOverride } = this._opts;
|
|
319
|
+
const { orientation, aspectRatio, title, subtitle, showValues, showLegend, ticks, animate, stagger, maintainAspectRatio, labelWidth: labelWidthOverride, barThickness: barThicknessOverride } = this._opts;
|
|
296
320
|
const values = this._values;
|
|
297
321
|
const palette = this._palette;
|
|
322
|
+
const seriesKeys = this._seriesKeys;
|
|
323
|
+
const numSeries = seriesKeys.length;
|
|
298
324
|
const id = this.id;
|
|
325
|
+
// Compute global max across all series
|
|
326
|
+
let globalMax = 0;
|
|
327
|
+
for (const sk of seriesKeys) {
|
|
328
|
+
for (const v of values) {
|
|
329
|
+
const val = v[sk.key] ?? 0;
|
|
330
|
+
if (val > globalMax)
|
|
331
|
+
globalMax = val;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (globalMax === 0)
|
|
335
|
+
globalMax = 1;
|
|
299
336
|
const ratio = typeof aspectRatio === 'string' ? (RATIOS[aspectRatio] || 16 / 9) : (aspectRatio || 16 / 9);
|
|
300
337
|
const effectiveWidth = resolvedWidth;
|
|
301
338
|
const prelimL = computeLayout(values, { orientation, width: effectiveWidth, aspectRatio, labelWidth: labelWidthOverride, barThickness: barThicknessOverride });
|
|
302
339
|
const ratioHeight = Math.round(effectiveWidth / ratio);
|
|
340
|
+
const scale = prelimL.scale;
|
|
341
|
+
const labelSize = Math.max(9, Math.round(11 * scale));
|
|
342
|
+
const legendH = showLegend ? Math.round(labelSize * 2) + prelimL.padding : 0;
|
|
343
|
+
const trendH = this._hasTrend() ? Math.round(56 * prelimL.scale) : 0;
|
|
303
344
|
let minContentHeight;
|
|
304
345
|
const headerEstimate = prelimL.padding + Math.round(prelimL.titleSize * 1.4) + Math.round(prelimL.subtitleSize * 1.4);
|
|
305
346
|
if (orientation === 'vertical') {
|
|
306
347
|
const labelRowHeight = Math.round(prelimL.labelSize * 2) + Math.round(6 * prelimL.scale);
|
|
307
348
|
const minBarArea = Math.max(100, values.length * 20);
|
|
308
|
-
minContentHeight = headerEstimate + minBarArea + labelRowHeight + prelimL.padding * 2;
|
|
349
|
+
minContentHeight = headerEstimate + minBarArea + labelRowHeight + prelimL.padding * 2 + legendH + trendH;
|
|
309
350
|
}
|
|
310
351
|
else {
|
|
311
352
|
const rowHeight = prelimL.barThickness + prelimL.gap + prelimL.gap + 1;
|
|
312
353
|
const tickRowHeight = Math.round(prelimL.tickSize * 2);
|
|
313
|
-
minContentHeight = headerEstimate + values.length * rowHeight + tickRowHeight + prelimL.padding * 2;
|
|
354
|
+
minContentHeight = headerEstimate + values.length * rowHeight + tickRowHeight + prelimL.padding * 2 + legendH + trendH;
|
|
314
355
|
}
|
|
315
356
|
const effectiveHeight = maintainAspectRatio
|
|
316
|
-
? Math.max(ratioHeight, minContentHeight)
|
|
317
|
-
: Math.max(this._wrapperEl.clientHeight || ratioHeight, minContentHeight);
|
|
357
|
+
? Math.max(ratioHeight + trendH, minContentHeight)
|
|
358
|
+
: Math.max(this._wrapperEl.clientHeight || ratioHeight + trendH, minContentHeight);
|
|
318
359
|
this._wrapperEl.style.height = `${effectiveHeight}px`;
|
|
319
360
|
const L = computeLayout(values, { orientation, width: effectiveWidth, aspectRatio, labelWidth: labelWidthOverride, barThickness: barThicknessOverride });
|
|
320
361
|
L.cardWidth = effectiveWidth;
|
|
321
362
|
L.cardHeight = effectiveHeight;
|
|
363
|
+
L.maxVal = globalMax;
|
|
322
364
|
const finalHeaderEstimate = L.padding + Math.round(L.titleSize * 1.4) + Math.round(L.subtitleSize * 1.4);
|
|
323
365
|
if (orientation === 'vertical') {
|
|
324
366
|
const labelRowHeight = Math.round(L.labelSize * 2) + Math.round(6 * L.scale);
|
|
325
|
-
L.maxBarLength = Math.max(100, effectiveHeight - finalHeaderEstimate - labelRowHeight - L.padding * 2);
|
|
367
|
+
L.maxBarLength = Math.max(100, effectiveHeight - finalHeaderEstimate - labelRowHeight - L.padding * 2 - legendH - trendH);
|
|
326
368
|
}
|
|
327
369
|
else {
|
|
328
370
|
L.maxBarLength = effectiveWidth - L.labelWidth - L.padding * 3;
|
|
329
371
|
}
|
|
330
|
-
const cardEl = mkDiv(`${id}-card`, `background: ${TOKENS.bg}; border: 1px solid ${TOKENS.border}; border-radius: ${Math.round(12 * L.scale)}px; padding: ${L.padding}px; font-family: ${FONT_FAMILY}; box-shadow: 0 1px 3px rgba(0,0,0,0.04); width: 100%; height: 100%; box-sizing: border-box
|
|
372
|
+
const cardEl = mkDiv(`${id}-card`, `background: ${TOKENS.bg}; border: 1px solid ${TOKENS.border}; border-radius: ${Math.round(12 * L.scale)}px; padding: ${L.padding}px; font-family: ${FONT_FAMILY}; box-shadow: 0 1px 3px rgba(0,0,0,0.04); width: 100%; height: 100%; box-sizing: border-box;`);
|
|
331
373
|
this._wrapperEl.appendChild(cardEl);
|
|
332
374
|
if (title) {
|
|
333
375
|
const titleEl = mkDiv(`${id}-title`, `font-size: ${L.titleSize}px; font-weight: 600; color: ${TOKENS.title}; letter-spacing: -0.025em; margin-bottom: 2px; line-height: 1.3;`);
|
|
@@ -340,98 +382,64 @@ class BarChart {
|
|
|
340
382
|
cardEl.appendChild(subEl);
|
|
341
383
|
}
|
|
342
384
|
if (orientation === 'vertical') {
|
|
343
|
-
this._buildVertical(cardEl, L, id, values, palette, ticks, animate, stagger, showValues);
|
|
385
|
+
this._buildVertical(cardEl, L, id, values, palette, ticks, animate, stagger, showValues, numSeries, seriesKeys);
|
|
344
386
|
}
|
|
345
387
|
else {
|
|
346
|
-
this._buildHorizontal(cardEl, L, id, values, palette, ticks, animate, stagger, showValues);
|
|
388
|
+
this._buildHorizontal(cardEl, L, id, values, palette, ticks, animate, stagger, showValues, numSeries, seriesKeys);
|
|
389
|
+
}
|
|
390
|
+
// Legend
|
|
391
|
+
if (showLegend && numSeries > 1) {
|
|
392
|
+
const legendDiv = document.createElement('div');
|
|
393
|
+
legendDiv.style.cssText = `display:flex;flex-wrap:wrap;gap:${Math.round(8 * L.scale)}px ${Math.round(16 * L.scale)}px;padding-top:${Math.round(8 * L.scale)}px;justify-content:center;`;
|
|
394
|
+
seriesKeys.forEach((sk, i) => {
|
|
395
|
+
const item = document.createElement('div');
|
|
396
|
+
item.style.cssText = `display:flex;align-items:center;gap:4px;font-size:${labelSize}px;color:${TOKENS.muted};`;
|
|
397
|
+
const dot = document.createElement('span');
|
|
398
|
+
dot.style.cssText = `width:${Math.round(10 * L.scale)}px;height:${Math.round(10 * L.scale)}px;border-radius:2px;background:${palette[i % palette.length]};flex-shrink:0;`;
|
|
399
|
+
item.appendChild(dot);
|
|
400
|
+
const lbl = document.createElement('span');
|
|
401
|
+
lbl.textContent = sk.label || sk.key;
|
|
402
|
+
item.appendChild(lbl);
|
|
403
|
+
legendDiv.appendChild(item);
|
|
404
|
+
});
|
|
405
|
+
cardEl.appendChild(legendDiv);
|
|
347
406
|
}
|
|
407
|
+
// Trend footer
|
|
408
|
+
this._renderTrend(cardEl, L.scale, L.padding);
|
|
348
409
|
}
|
|
349
|
-
|
|
350
|
-
const
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
const
|
|
356
|
-
const
|
|
357
|
-
const
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
const
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
colEl.appendChild(valEl);
|
|
381
|
-
}
|
|
382
|
-
const barEl = mkDiv(`${id}-bar-${i}`, `width: 100%; max-width: ${L.barThickness}px; height: ${barHeight}px; background-color: ${color}; border-radius: ${L.barRadius}px ${L.barRadius}px 0 0; opacity: 0.85; transition: opacity 0.15s ease; ${delay}`, barClass);
|
|
383
|
-
colEl.appendChild(barEl);
|
|
384
|
-
if (this._isInteractive)
|
|
385
|
-
this._wireInteractivity(colEl, barEl, i);
|
|
386
|
-
});
|
|
387
|
-
const xlabelsEl = mkDiv(`${id}-xlabels`, `display: flex; flex-direction: row; gap: ${L.gap}px; padding-left: ${L.yAxisWidth}px; padding-top: ${Math.round(6 * L.scale)}px;`);
|
|
388
|
-
cardEl.appendChild(xlabelsEl);
|
|
389
|
-
values.forEach((v, i) => {
|
|
390
|
-
const label = v.label || `#${i + 1}`;
|
|
391
|
-
const lblDelay = animate ? `animation-delay: ${i * stagger}ms;` : '';
|
|
392
|
-
const lblClass = animate ? 'jux-bar-label' : '';
|
|
393
|
-
const lblEl = mkDiv(`${id}-lbl-${i}`, `flex: 1; text-align: center; font-size: ${L.tickSize}px; color: ${TOKENS.muted}; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 0 2px; ${lblDelay}`, lblClass);
|
|
394
|
-
lblEl.textContent = label;
|
|
395
|
-
xlabelsEl.appendChild(lblEl);
|
|
396
|
-
});
|
|
397
|
-
}
|
|
398
|
-
_buildHorizontal(cardEl, L, id, values, palette, ticks, animate, stagger, showValues) {
|
|
399
|
-
const areaEl = mkDiv(`${id}-area`, `display: flex; flex-direction: column; gap: 0; width: 100%;`);
|
|
400
|
-
cardEl.appendChild(areaEl);
|
|
401
|
-
values.forEach((v, i) => {
|
|
402
|
-
const label = v.label || `#${i + 1}`;
|
|
403
|
-
const barWidth = Math.max(2, Math.round((v.x / L.maxVal) * L.maxBarLength));
|
|
404
|
-
const color = palette[i % palette.length];
|
|
405
|
-
const delay = animate ? `animation-delay: ${i * stagger}ms;` : '';
|
|
406
|
-
const barClass = animate ? 'jux-bar-h' : '';
|
|
407
|
-
const rowEl = mkDiv(`${id}-row-${i}`, `display: flex; flex-direction: row; align-items: center; height: ${L.barThickness}px; margin-bottom: ${L.gap}px; border-bottom: 1px solid ${TOKENS.grid}; padding-bottom: ${L.gap}px; border-radius: 4px; padding: 2px;`);
|
|
408
|
-
areaEl.appendChild(rowEl);
|
|
409
|
-
const isLink = v.drill || v.href;
|
|
410
|
-
const lblDelay = animate ? `animation-delay: ${i * stagger}ms;` : '';
|
|
411
|
-
const lblClass = animate ? 'jux-bar-label' : '';
|
|
412
|
-
const lblEl = mkDiv(`${id}-lbl-${i}`, `width: ${L.labelWidth}px; flex-shrink: 0; text-align: right; padding-right: ${Math.round(10 * L.scale)}px; font-size: ${L.labelSize}px; color: ${TOKENS.muted}; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; box-sizing: border-box; ${lblDelay}`, lblClass);
|
|
413
|
-
lblEl.textContent = label;
|
|
414
|
-
rowEl.appendChild(lblEl);
|
|
415
|
-
const barEl = mkDiv(`${id}-bar-${i}`, `width: ${barWidth}px; height: ${L.barThickness}px; background-color: ${color}; border-radius: ${L.barRadius}px; opacity: 0.85; transition: opacity 0.15s ease; ${delay}`, barClass);
|
|
416
|
-
rowEl.appendChild(barEl);
|
|
417
|
-
if (showValues) {
|
|
418
|
-
const valDelay = animate ? `animation-delay: ${i * stagger + 200}ms;` : '';
|
|
419
|
-
const valClass = animate ? 'jux-bar-label' : '';
|
|
420
|
-
const valEl = mkDiv(`${id}-val-${i}`, `font-size: ${L.tickSize}px; color: ${TOKENS.muted}; margin-left: ${Math.round(6 * L.scale)}px; ${valDelay}`, valClass);
|
|
421
|
-
valEl.textContent = String(v.x);
|
|
422
|
-
rowEl.appendChild(valEl);
|
|
423
|
-
}
|
|
424
|
-
if (this._isInteractive)
|
|
425
|
-
this._wireInteractivity(rowEl, barEl, i);
|
|
426
|
-
});
|
|
427
|
-
const xaxisEl = mkDiv(`${id}-xaxis`, `display: flex; flex-direction: row; justify-content: space-between; padding-left: ${L.labelWidth}px; padding-top: ${Math.round(4 * L.scale)}px;`);
|
|
428
|
-
cardEl.appendChild(xaxisEl);
|
|
429
|
-
for (let t = 0; t <= ticks; t++) {
|
|
430
|
-
const val = Math.round((L.maxVal / ticks) * t);
|
|
431
|
-
const tickEl = mkDiv(`${id}-xtick-${t}`, `font-size: ${L.tickSize}px; color: ${TOKENS.muted};`);
|
|
432
|
-
tickEl.textContent = formatTick(val);
|
|
433
|
-
xaxisEl.appendChild(tickEl);
|
|
410
|
+
_renderTrend(card, scale, padding) {
|
|
411
|
+
const { trendTitle, trendSubtitle, trendIcon, autoTrend } = this._opts;
|
|
412
|
+
let title = trendTitle;
|
|
413
|
+
let subtitle = trendSubtitle;
|
|
414
|
+
let icon = trendIcon;
|
|
415
|
+
if (autoTrend && !title) {
|
|
416
|
+
const sk = this._seriesKeys[0];
|
|
417
|
+
const vals = this._values.map(v => v[sk.key] ?? 0);
|
|
418
|
+
const labels = this._values.map(v => v.label || '');
|
|
419
|
+
const trend = computeTrend(vals, labels);
|
|
420
|
+
title = trend.title;
|
|
421
|
+
subtitle = subtitle || trend.subtitle;
|
|
422
|
+
icon = icon || trend.icon;
|
|
423
|
+
}
|
|
424
|
+
if (!title && !subtitle)
|
|
425
|
+
return;
|
|
426
|
+
const fontSize = Math.max(11, Math.round(13 * scale));
|
|
427
|
+
const subFontSize = Math.max(10, Math.round(11 * scale));
|
|
428
|
+
const footer = document.createElement('div');
|
|
429
|
+
footer.style.cssText = `padding-top:${Math.round(8 * scale)}px;border-top:1px solid hsl(220,13%,93%);margin-top:${Math.round(8 * scale)}px;`;
|
|
430
|
+
if (title) {
|
|
431
|
+
const titleEl = document.createElement('div');
|
|
432
|
+
titleEl.style.cssText = `font-size:${fontSize}px;font-weight:500;color:hsl(222,47%,11%);line-height:1.4;`;
|
|
433
|
+
titleEl.textContent = `${title}${icon ? ' ' + icon : ''}`;
|
|
434
|
+
footer.appendChild(titleEl);
|
|
435
|
+
}
|
|
436
|
+
if (subtitle) {
|
|
437
|
+
const subEl = document.createElement('div');
|
|
438
|
+
subEl.style.cssText = `font-size:${subFontSize}px;color:hsl(215,16%,47%);line-height:1.4;margin-top:1px;`;
|
|
439
|
+
subEl.textContent = subtitle;
|
|
440
|
+
footer.appendChild(subEl);
|
|
434
441
|
}
|
|
442
|
+
card.appendChild(footer);
|
|
435
443
|
}
|
|
436
444
|
// ═══════════════════════════════════════════════════════════
|
|
437
445
|
// PUBLIC API
|
|
@@ -459,22 +467,25 @@ class BarChart {
|
|
|
459
467
|
this._buildChart(containerWidth);
|
|
460
468
|
if (this._opts.responsive && typeof ResizeObserver !== 'undefined') {
|
|
461
469
|
let resizeTimer;
|
|
470
|
+
let skipCount = 2;
|
|
462
471
|
const ro = new ResizeObserver(() => {
|
|
472
|
+
if (skipCount > 0) {
|
|
473
|
+
skipCount--;
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
463
476
|
clearTimeout(resizeTimer);
|
|
464
477
|
resizeTimer = setTimeout(() => {
|
|
465
478
|
const newWidth = this._wrapperEl.clientWidth;
|
|
466
479
|
if (newWidth > 0)
|
|
467
480
|
this._buildChart(newWidth);
|
|
468
|
-
},
|
|
481
|
+
}, 200);
|
|
469
482
|
});
|
|
470
483
|
ro.observe(this._wrapperEl);
|
|
471
484
|
this._resizeObserver = ro;
|
|
472
485
|
}
|
|
473
486
|
return this;
|
|
474
487
|
}
|
|
475
|
-
into(target) {
|
|
476
|
-
return this.render(target);
|
|
477
|
-
}
|
|
488
|
+
into(target) { return this.render(target); }
|
|
478
489
|
on(event, fn) {
|
|
479
490
|
if (!this._listeners[event])
|
|
480
491
|
this._listeners[event] = [];
|
|
@@ -482,9 +493,8 @@ class BarChart {
|
|
|
482
493
|
return this;
|
|
483
494
|
}
|
|
484
495
|
off(event, fn) {
|
|
485
|
-
if (this._listeners[event])
|
|
496
|
+
if (this._listeners[event])
|
|
486
497
|
this._listeners[event] = this._listeners[event].filter(f => f !== fn);
|
|
487
|
-
}
|
|
488
498
|
return this;
|
|
489
499
|
}
|
|
490
500
|
select(index) {
|
|
@@ -504,6 +514,7 @@ class BarChart {
|
|
|
504
514
|
destroy() {
|
|
505
515
|
if (this._resizeObserver)
|
|
506
516
|
this._resizeObserver.disconnect();
|
|
517
|
+
pageState.__unregister(this.id);
|
|
507
518
|
this._wrapperEl.remove();
|
|
508
519
|
}
|
|
509
520
|
}
|
|
@@ -517,4 +528,28 @@ export function barChart(id, values, options = {}) {
|
|
|
517
528
|
}
|
|
518
529
|
export { BarChart, RATIOS, TOKENS };
|
|
519
530
|
export default barChart;
|
|
531
|
+
function detectSeriesKeys(values, series) {
|
|
532
|
+
if (series && series.length > 0) {
|
|
533
|
+
return series;
|
|
534
|
+
}
|
|
535
|
+
if (values.length === 0) {
|
|
536
|
+
return [{ key: 'x', label: 'Value' }];
|
|
537
|
+
}
|
|
538
|
+
const firstItem = values[0];
|
|
539
|
+
const numericKeys = Object.keys(firstItem).filter(key => key !== 'label' && key !== 'drill' && key !== 'href' && typeof firstItem[key] === 'number');
|
|
540
|
+
if (numericKeys.length === 0) {
|
|
541
|
+
return [{ key: 'x', label: 'Value' }];
|
|
542
|
+
}
|
|
543
|
+
return numericKeys.map(key => ({
|
|
544
|
+
key,
|
|
545
|
+
label: key.charAt(0).toUpperCase() + key.slice(1),
|
|
546
|
+
}));
|
|
547
|
+
}
|
|
548
|
+
const DEFAULT_SERIES_COLORS = [
|
|
549
|
+
'hsl(217, 91%, 60%)',
|
|
550
|
+
'hsl(142, 71%, 45%)',
|
|
551
|
+
'hsl(25, 95%, 53%)',
|
|
552
|
+
'hsl(271, 81%, 56%)',
|
|
553
|
+
'hsl(48, 96%, 53%)',
|
|
554
|
+
];
|
|
520
555
|
//# sourceMappingURL=barChart.js.map
|