@ojiepermana/angular-chart 22.0.27
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 +249 -0
- package/fesm2022/ojiepermana-angular-chart-area.mjs +266 -0
- package/fesm2022/ojiepermana-angular-chart-area.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-bar.mjs +674 -0
- package/fesm2022/ojiepermana-angular-chart-bar.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-core.mjs +764 -0
- package/fesm2022/ojiepermana-angular-chart-core.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-line.mjs +281 -0
- package/fesm2022/ojiepermana-angular-chart-line.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-pie.mjs +248 -0
- package/fesm2022/ojiepermana-angular-chart-pie.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-primitives.mjs +1186 -0
- package/fesm2022/ojiepermana-angular-chart-primitives.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-radar.mjs +329 -0
- package/fesm2022/ojiepermana-angular-chart-radar.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-radial.mjs +255 -0
- package/fesm2022/ojiepermana-angular-chart-radial.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart-scatter.mjs +253 -0
- package/fesm2022/ojiepermana-angular-chart-scatter.mjs.map +1 -0
- package/fesm2022/ojiepermana-angular-chart.mjs +20 -0
- package/fesm2022/ojiepermana-angular-chart.mjs.map +1 -0
- package/package.json +76 -0
- package/types/ojiepermana-angular-chart-area.d.ts +58 -0
- package/types/ojiepermana-angular-chart-bar.d.ts +171 -0
- package/types/ojiepermana-angular-chart-core.d.ts +369 -0
- package/types/ojiepermana-angular-chart-line.d.ts +57 -0
- package/types/ojiepermana-angular-chart-pie.d.ts +93 -0
- package/types/ojiepermana-angular-chart-primitives.d.ts +265 -0
- package/types/ojiepermana-angular-chart-radar.d.ts +89 -0
- package/types/ojiepermana-angular-chart-radial.d.ts +86 -0
- package/types/ojiepermana-angular-chart-scatter.d.ts +95 -0
- package/types/ojiepermana-angular-chart.d.ts +2 -0
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, output, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { seriesColorVar, ChartContext, CartesianContext, elementClientCenter } from '@ojiepermana/angular-chart/core';
|
|
4
|
+
import { scaleBand, scaleLinear } from 'd3-scale';
|
|
5
|
+
import { min, max } from 'd3-array';
|
|
6
|
+
import { stack } from 'd3-shape';
|
|
7
|
+
import { ChartPointerTracker } from '@ojiepermana/angular-chart/primitives';
|
|
8
|
+
|
|
9
|
+
/** Read a numeric value from a datum, tolerating strings. */
|
|
10
|
+
function readNumber(datum, key) {
|
|
11
|
+
const raw = datum[key];
|
|
12
|
+
if (typeof raw === 'number' && Number.isFinite(raw)) {
|
|
13
|
+
return raw;
|
|
14
|
+
}
|
|
15
|
+
if (typeof raw === 'string') {
|
|
16
|
+
const n = Number(raw);
|
|
17
|
+
return Number.isFinite(n) ? n : 0;
|
|
18
|
+
}
|
|
19
|
+
return 0;
|
|
20
|
+
}
|
|
21
|
+
function resolveBarColor(datum, seriesKey, colorKey) {
|
|
22
|
+
if (!colorKey) {
|
|
23
|
+
return seriesColorVar(seriesKey);
|
|
24
|
+
}
|
|
25
|
+
const raw = datum[colorKey];
|
|
26
|
+
if (typeof raw !== 'string' || raw.length === 0) {
|
|
27
|
+
return seriesColorVar(seriesKey);
|
|
28
|
+
}
|
|
29
|
+
if (raw.startsWith('var(') ||
|
|
30
|
+
raw.startsWith('#') ||
|
|
31
|
+
raw.startsWith('rgb') ||
|
|
32
|
+
raw.startsWith('hsl') ||
|
|
33
|
+
raw.includes('(')) {
|
|
34
|
+
return raw;
|
|
35
|
+
}
|
|
36
|
+
return seriesColorVar(raw);
|
|
37
|
+
}
|
|
38
|
+
function isActiveBar(datum, activeKey, activeValue) {
|
|
39
|
+
if (!activeKey || activeValue === undefined) {
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
const value = datum[activeKey];
|
|
43
|
+
if (typeof value === 'number' && typeof activeValue === 'number') {
|
|
44
|
+
return value === activeValue;
|
|
45
|
+
}
|
|
46
|
+
return String(value ?? '') === String(activeValue);
|
|
47
|
+
}
|
|
48
|
+
/** Build all bar rectangles for the given config. */
|
|
49
|
+
function computeBarLayout(input) {
|
|
50
|
+
const { data, xKey, seriesKeys, variant, orientation, innerWidth, innerHeight, bandPadding, groupPadding, colorKey, activeKey, activeValue, } = input;
|
|
51
|
+
const categories = data.map((d) => String(d[xKey] ?? ''));
|
|
52
|
+
const isVertical = orientation === 'vertical';
|
|
53
|
+
const categoryScale = scaleBand()
|
|
54
|
+
.domain(categories)
|
|
55
|
+
.range(isVertical ? [0, innerWidth] : [0, innerHeight])
|
|
56
|
+
.padding(bandPadding);
|
|
57
|
+
const valueScale = scaleLinear();
|
|
58
|
+
if (variant === 'stacked' && seriesKeys.length > 0) {
|
|
59
|
+
return stackedLayout({
|
|
60
|
+
data,
|
|
61
|
+
xKey,
|
|
62
|
+
seriesKeys,
|
|
63
|
+
orientation,
|
|
64
|
+
innerWidth,
|
|
65
|
+
innerHeight,
|
|
66
|
+
categoryScale,
|
|
67
|
+
valueScale,
|
|
68
|
+
categories,
|
|
69
|
+
colorKey,
|
|
70
|
+
activeKey,
|
|
71
|
+
activeValue,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return groupedLayout({
|
|
75
|
+
data,
|
|
76
|
+
xKey,
|
|
77
|
+
seriesKeys,
|
|
78
|
+
orientation,
|
|
79
|
+
innerWidth,
|
|
80
|
+
innerHeight,
|
|
81
|
+
categoryScale,
|
|
82
|
+
valueScale,
|
|
83
|
+
groupPadding,
|
|
84
|
+
categories,
|
|
85
|
+
colorKey,
|
|
86
|
+
activeKey,
|
|
87
|
+
activeValue,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function groupedLayout(input) {
|
|
91
|
+
const { data, seriesKeys, orientation, innerWidth, innerHeight, categoryScale, valueScale, groupPadding, categories, colorKey, activeKey, activeValue, } = input;
|
|
92
|
+
const isVertical = orientation === 'vertical';
|
|
93
|
+
const minValue = min(data, (d) => min(seriesKeys, (k) => readNumber(d, k)) ?? 0) ?? 0;
|
|
94
|
+
const maxValue = max(data, (d) => max(seriesKeys, (k) => readNumber(d, k)) ?? 0) ?? 0;
|
|
95
|
+
const domainMin = Math.min(0, minValue);
|
|
96
|
+
const domainMax = Math.max(0, maxValue, domainMin === 0 ? 1 : 0);
|
|
97
|
+
valueScale
|
|
98
|
+
.domain([domainMin, domainMax])
|
|
99
|
+
.nice()
|
|
100
|
+
.range(isVertical ? [innerHeight, 0] : [0, innerWidth]);
|
|
101
|
+
const baseline = valueScale(0);
|
|
102
|
+
const subScale = scaleBand()
|
|
103
|
+
.domain(seriesKeys)
|
|
104
|
+
.range([0, categoryScale.bandwidth()])
|
|
105
|
+
.padding(groupPadding);
|
|
106
|
+
const bars = [];
|
|
107
|
+
data.forEach((datum, datumIndex) => {
|
|
108
|
+
const category = categories[datumIndex];
|
|
109
|
+
const bandStart = categoryScale(category) ?? 0;
|
|
110
|
+
seriesKeys.forEach((seriesKey) => {
|
|
111
|
+
const value = readNumber(datum, seriesKey);
|
|
112
|
+
const sub = subScale(seriesKey) ?? 0;
|
|
113
|
+
const scaledValue = valueScale(value);
|
|
114
|
+
const color = resolveBarColor(datum, seriesKey, colorKey);
|
|
115
|
+
const active = isActiveBar(datum, activeKey, activeValue);
|
|
116
|
+
const rect = isVertical
|
|
117
|
+
? {
|
|
118
|
+
key: `${datumIndex}-${seriesKey}`,
|
|
119
|
+
seriesKey,
|
|
120
|
+
datumIndex,
|
|
121
|
+
category,
|
|
122
|
+
value,
|
|
123
|
+
x: bandStart + sub,
|
|
124
|
+
y: Math.min(scaledValue, baseline),
|
|
125
|
+
width: subScale.bandwidth(),
|
|
126
|
+
height: Math.abs(baseline - scaledValue),
|
|
127
|
+
color,
|
|
128
|
+
active,
|
|
129
|
+
}
|
|
130
|
+
: {
|
|
131
|
+
key: `${datumIndex}-${seriesKey}`,
|
|
132
|
+
seriesKey,
|
|
133
|
+
datumIndex,
|
|
134
|
+
category,
|
|
135
|
+
value,
|
|
136
|
+
x: Math.min(scaledValue, baseline),
|
|
137
|
+
y: bandStart + sub,
|
|
138
|
+
width: Math.abs(baseline - scaledValue),
|
|
139
|
+
height: subScale.bandwidth(),
|
|
140
|
+
color,
|
|
141
|
+
active,
|
|
142
|
+
};
|
|
143
|
+
bars.push(rect);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
return { bars, categoryScale, valueScale, categories };
|
|
147
|
+
}
|
|
148
|
+
function stackedLayout(input) {
|
|
149
|
+
const { data, seriesKeys, orientation, innerWidth, innerHeight, categoryScale, valueScale, categories, colorKey, activeKey, activeValue, } = input;
|
|
150
|
+
const isVertical = orientation === 'vertical';
|
|
151
|
+
const normalized = data.map((d) => {
|
|
152
|
+
const out = {};
|
|
153
|
+
for (const k of seriesKeys) {
|
|
154
|
+
out[k] = readNumber(d, k);
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
});
|
|
158
|
+
const series = stack().keys(seriesKeys)(normalized);
|
|
159
|
+
const maxTotal = max(series[series.length - 1] ?? [], (p) => p[1]) ?? 0;
|
|
160
|
+
valueScale
|
|
161
|
+
.domain([0, maxTotal === 0 ? 1 : maxTotal])
|
|
162
|
+
.nice()
|
|
163
|
+
.range(isVertical ? [innerHeight, 0] : [0, innerWidth]);
|
|
164
|
+
const bars = [];
|
|
165
|
+
series.forEach((layer) => {
|
|
166
|
+
const seriesKey = layer.key;
|
|
167
|
+
layer.forEach((point, datumIndex) => {
|
|
168
|
+
const [lower, upper] = point;
|
|
169
|
+
const value = upper - lower;
|
|
170
|
+
const category = categories[datumIndex];
|
|
171
|
+
const bandStart = categoryScale(category) ?? 0;
|
|
172
|
+
const color = resolveBarColor(data[datumIndex], seriesKey, colorKey);
|
|
173
|
+
const active = isActiveBar(data[datumIndex], activeKey, activeValue);
|
|
174
|
+
const rect = isVertical
|
|
175
|
+
? {
|
|
176
|
+
key: `${datumIndex}-${seriesKey}`,
|
|
177
|
+
seriesKey,
|
|
178
|
+
datumIndex,
|
|
179
|
+
category,
|
|
180
|
+
value,
|
|
181
|
+
x: bandStart,
|
|
182
|
+
y: valueScale(upper),
|
|
183
|
+
width: categoryScale.bandwidth(),
|
|
184
|
+
height: valueScale(lower) - valueScale(upper),
|
|
185
|
+
color,
|
|
186
|
+
active,
|
|
187
|
+
}
|
|
188
|
+
: {
|
|
189
|
+
key: `${datumIndex}-${seriesKey}`,
|
|
190
|
+
seriesKey,
|
|
191
|
+
datumIndex,
|
|
192
|
+
category,
|
|
193
|
+
value,
|
|
194
|
+
x: valueScale(lower),
|
|
195
|
+
y: bandStart,
|
|
196
|
+
width: valueScale(upper) - valueScale(lower),
|
|
197
|
+
height: categoryScale.bandwidth(),
|
|
198
|
+
color,
|
|
199
|
+
active,
|
|
200
|
+
};
|
|
201
|
+
bars.push(rect);
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
return { bars, categoryScale, valueScale, categories };
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/** Hard cap so degenerate inputs (tiny `dotSize`) cannot explode the DOM. */
|
|
208
|
+
const MAX_ROWS_PER_COLUMN = 400;
|
|
209
|
+
const EDGE_TOLERANCE = 0.5;
|
|
210
|
+
/**
|
|
211
|
+
* Build the dot-matrix cells for the `dot` bar style.
|
|
212
|
+
*
|
|
213
|
+
* Cells tile a global grid anchored at the value baseline, so stacked
|
|
214
|
+
* segments snap to the same rows and never overlap. A bar fills every cell
|
|
215
|
+
* whose center lies inside its value range; bars too short to cover a center
|
|
216
|
+
* still claim the cell nearest their midpoint when it is free.
|
|
217
|
+
*/
|
|
218
|
+
function computeBarDotCells(input) {
|
|
219
|
+
const { bars, orientation, innerWidth, innerHeight, baseline, dotSize, dotGap } = input;
|
|
220
|
+
const isVertical = orientation === 'vertical';
|
|
221
|
+
const innerLength = isVertical ? innerHeight : innerWidth;
|
|
222
|
+
const track = [];
|
|
223
|
+
const values = [];
|
|
224
|
+
if (innerLength <= 0 || bars.length === 0) {
|
|
225
|
+
return { track, values };
|
|
226
|
+
}
|
|
227
|
+
const columns = groupColumns(bars, isVertical);
|
|
228
|
+
columns.forEach((column, columnIndex) => {
|
|
229
|
+
const cellLength = dotSize ?? column.thickness;
|
|
230
|
+
const step = cellLength + dotGap;
|
|
231
|
+
if (cellLength <= 0 || step <= EDGE_TOLERANCE) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
// Signed row index r anchored at the baseline: r = 0 is the first cell on
|
|
235
|
+
// the positive-value side, negative r tiles the negative side.
|
|
236
|
+
// `rowStart(r)` is the cell's lower main-axis coordinate (top edge for
|
|
237
|
+
// vertical, left edge for horizontal); `rowAt(c)` is the fractional row
|
|
238
|
+
// whose cell center sits at coordinate c.
|
|
239
|
+
const rowStart = (r) => (isVertical ? baseline - r * step - cellLength : baseline + r * step);
|
|
240
|
+
const rowAt = (c) => isVertical ? (baseline - c - cellLength / 2) / step : (c - baseline - cellLength / 2) / step;
|
|
241
|
+
// Rows whose cell lies fully inside the plot area.
|
|
242
|
+
let rMin = Math.ceil(isVertical ? (baseline - innerLength - EDGE_TOLERANCE) / step : (-baseline - EDGE_TOLERANCE) / step);
|
|
243
|
+
let rMax = Math.floor(isVertical
|
|
244
|
+
? (baseline - cellLength + EDGE_TOLERANCE) / step
|
|
245
|
+
: (innerLength - baseline - cellLength + EDGE_TOLERANCE) / step);
|
|
246
|
+
if (rMax - rMin + 1 > MAX_ROWS_PER_COLUMN) {
|
|
247
|
+
rMax = rMin + MAX_ROWS_PER_COLUMN - 1;
|
|
248
|
+
}
|
|
249
|
+
const cellRect = (r) => isVertical
|
|
250
|
+
? { x: column.pos, y: rowStart(r), width: column.thickness, height: cellLength }
|
|
251
|
+
: { x: rowStart(r), y: column.pos, width: cellLength, height: column.thickness };
|
|
252
|
+
for (let r = rMin; r <= rMax; r++) {
|
|
253
|
+
track.push({ key: `${columnIndex}:${r}`, ...cellRect(r) });
|
|
254
|
+
}
|
|
255
|
+
const usedRows = new Set();
|
|
256
|
+
for (const bar of column.bars) {
|
|
257
|
+
const barLength = isVertical ? bar.height : bar.width;
|
|
258
|
+
if (barLength <= EDGE_TOLERANCE) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
const barStart = isVertical ? bar.y : bar.x;
|
|
262
|
+
const barEnd = barStart + barLength;
|
|
263
|
+
// Rows whose cell center falls inside [barStart, barEnd] (± tolerance).
|
|
264
|
+
const rA = rowAt(barStart);
|
|
265
|
+
const rB = rowAt(barEnd);
|
|
266
|
+
const first = Math.max(Math.ceil(Math.min(rA, rB) - EDGE_TOLERANCE / step), rMin);
|
|
267
|
+
const last = Math.min(Math.floor(Math.max(rA, rB) + EDGE_TOLERANCE / step), rMax);
|
|
268
|
+
const rows = [];
|
|
269
|
+
for (let r = first; r <= last; r++) {
|
|
270
|
+
rows.push(r);
|
|
271
|
+
}
|
|
272
|
+
// Guarantee visibility: a non-zero bar shorter than one cell claims the
|
|
273
|
+
// row nearest its midpoint when that row is still free.
|
|
274
|
+
if (rows.length === 0) {
|
|
275
|
+
const r = Math.round(rowAt(barStart + barLength / 2));
|
|
276
|
+
if (r >= rMin && r <= rMax && !usedRows.has(r)) {
|
|
277
|
+
rows.push(r);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
for (const r of rows) {
|
|
281
|
+
if (usedRows.has(r)) {
|
|
282
|
+
continue;
|
|
283
|
+
}
|
|
284
|
+
usedRows.add(r);
|
|
285
|
+
values.push({
|
|
286
|
+
key: `${bar.key}:${r}`,
|
|
287
|
+
...cellRect(r),
|
|
288
|
+
seriesKey: bar.seriesKey,
|
|
289
|
+
datumIndex: bar.datumIndex,
|
|
290
|
+
color: bar.color,
|
|
291
|
+
active: bar.active,
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
return { track, values };
|
|
297
|
+
}
|
|
298
|
+
/** Group bars sharing the same cross-axis band into one cell column. */
|
|
299
|
+
function groupColumns(bars, isVertical) {
|
|
300
|
+
const map = new Map();
|
|
301
|
+
for (const bar of bars) {
|
|
302
|
+
const pos = isVertical ? bar.x : bar.y;
|
|
303
|
+
const thickness = isVertical ? bar.width : bar.height;
|
|
304
|
+
if (thickness <= 0) {
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
const key = `${pos.toFixed(2)}:${thickness.toFixed(2)}`;
|
|
308
|
+
const existing = map.get(key);
|
|
309
|
+
if (existing) {
|
|
310
|
+
existing.bars.push(bar);
|
|
311
|
+
}
|
|
312
|
+
else {
|
|
313
|
+
map.set(key, { pos, thickness, bars: [bar] });
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return [...map.values()];
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const DEFAULT_MARGIN = { top: 8, right: 8, bottom: 24, left: 40 };
|
|
320
|
+
const defaultBarValueFormatter = (value) => `${value}`;
|
|
321
|
+
/**
|
|
322
|
+
* Bar chart — composable within `<Chart>`.
|
|
323
|
+
*
|
|
324
|
+
* Layout variants (via inputs):
|
|
325
|
+
* - `orientation`: `'vertical'` (default) or `'horizontal'`
|
|
326
|
+
* - `variant`: `'grouped'` (default) or `'stacked'`
|
|
327
|
+
* - `styles`: `'base'` (default) or `'dot'` (dot-matrix cells)
|
|
328
|
+
*/
|
|
329
|
+
class BarChart {
|
|
330
|
+
root = inject(ChartContext);
|
|
331
|
+
cart = inject(CartesianContext);
|
|
332
|
+
data = input.required(/* @ts-ignore */
|
|
333
|
+
...(ngDevMode ? [{ debugName: "data" }] : /* istanbul ignore next */ []));
|
|
334
|
+
xKey = input.required(/* @ts-ignore */
|
|
335
|
+
...(ngDevMode ? [{ debugName: "xKey" }] : /* istanbul ignore next */ []));
|
|
336
|
+
orientation = input('vertical', /* @ts-ignore */
|
|
337
|
+
...(ngDevMode ? [{ debugName: "orientation" }] : /* istanbul ignore next */ []));
|
|
338
|
+
variant = input('grouped', /* @ts-ignore */
|
|
339
|
+
...(ngDevMode ? [{ debugName: "variant" }] : /* istanbul ignore next */ []));
|
|
340
|
+
styles = input('base', /* @ts-ignore */
|
|
341
|
+
...(ngDevMode ? [{ debugName: "styles" }] : /* istanbul ignore next */ []));
|
|
342
|
+
margin = input(DEFAULT_MARGIN, /* @ts-ignore */
|
|
343
|
+
...(ngDevMode ? [{ debugName: "margin" }] : /* istanbul ignore next */ []));
|
|
344
|
+
bandPadding = input(0.2, /* @ts-ignore */
|
|
345
|
+
...(ngDevMode ? [{ debugName: "bandPadding" }] : /* istanbul ignore next */ []));
|
|
346
|
+
groupPadding = input(0.05, /* @ts-ignore */
|
|
347
|
+
...(ngDevMode ? [{ debugName: "groupPadding" }] : /* istanbul ignore next */ []));
|
|
348
|
+
cornerRadius = input(4, /* @ts-ignore */
|
|
349
|
+
...(ngDevMode ? [{ debugName: "cornerRadius" }] : /* istanbul ignore next */ []));
|
|
350
|
+
colorKey = input(undefined, /* @ts-ignore */
|
|
351
|
+
...(ngDevMode ? [{ debugName: "colorKey" }] : /* istanbul ignore next */ []));
|
|
352
|
+
activeKey = input(undefined, /* @ts-ignore */
|
|
353
|
+
...(ngDevMode ? [{ debugName: "activeKey" }] : /* istanbul ignore next */ []));
|
|
354
|
+
activeValue = input(undefined, /* @ts-ignore */
|
|
355
|
+
...(ngDevMode ? [{ debugName: "activeValue" }] : /* istanbul ignore next */ []));
|
|
356
|
+
showValueLabels = input(false, /* @ts-ignore */
|
|
357
|
+
...(ngDevMode ? [{ debugName: "showValueLabels" }] : /* istanbul ignore next */ []));
|
|
358
|
+
valueLabelFormat = input(defaultBarValueFormatter, /* @ts-ignore */
|
|
359
|
+
...(ngDevMode ? [{ debugName: "valueLabelFormat" }] : /* istanbul ignore next */ []));
|
|
360
|
+
/** Cell length along the value axis for the `dot` style; defaults to the bar thickness. */
|
|
361
|
+
dotSize = input(undefined, /* @ts-ignore */
|
|
362
|
+
...(ngDevMode ? [{ debugName: "dotSize" }] : /* istanbul ignore next */ []));
|
|
363
|
+
/** Gap between consecutive cells along the value axis for the `dot` style. */
|
|
364
|
+
dotGap = input(2, /* @ts-ignore */
|
|
365
|
+
...(ngDevMode ? [{ debugName: "dotGap" }] : /* istanbul ignore next */ []));
|
|
366
|
+
/** Corner radius of each `dot` cell. */
|
|
367
|
+
dotCornerRadius = input(2, /* @ts-ignore */
|
|
368
|
+
...(ngDevMode ? [{ debugName: "dotCornerRadius" }] : /* istanbul ignore next */ []));
|
|
369
|
+
/** Render the faint full-height cell track behind the `dot` values. */
|
|
370
|
+
showDotTrack = input(true, /* @ts-ignore */
|
|
371
|
+
...(ngDevMode ? [{ debugName: "showDotTrack" }] : /* istanbul ignore next */ []));
|
|
372
|
+
barClick = output();
|
|
373
|
+
innerWidth = computed(() => Math.max(0, this.root.dimensions().width - this.margin().left - this.margin().right), /* @ts-ignore */
|
|
374
|
+
...(ngDevMode ? [{ debugName: "innerWidth" }] : /* istanbul ignore next */ []));
|
|
375
|
+
innerHeight = computed(() => Math.max(0, this.root.dimensions().height - this.margin().top - this.margin().bottom), /* @ts-ignore */
|
|
376
|
+
...(ngDevMode ? [{ debugName: "innerHeight" }] : /* istanbul ignore next */ []));
|
|
377
|
+
layout = computed(() => computeBarLayout({
|
|
378
|
+
data: this.data(),
|
|
379
|
+
xKey: this.xKey(),
|
|
380
|
+
seriesKeys: this.root.visibleSeriesKeys(),
|
|
381
|
+
variant: this.variant(),
|
|
382
|
+
orientation: this.orientation(),
|
|
383
|
+
innerWidth: this.innerWidth(),
|
|
384
|
+
innerHeight: this.innerHeight(),
|
|
385
|
+
bandPadding: this.bandPadding(),
|
|
386
|
+
groupPadding: this.groupPadding(),
|
|
387
|
+
colorKey: this.colorKey(),
|
|
388
|
+
activeKey: this.activeKey(),
|
|
389
|
+
activeValue: this.activeValue(),
|
|
390
|
+
}), /* @ts-ignore */
|
|
391
|
+
...(ngDevMode ? [{ debugName: "layout" }] : /* istanbul ignore next */ []));
|
|
392
|
+
bars = computed(() => this.layout().bars, /* @ts-ignore */
|
|
393
|
+
...(ngDevMode ? [{ debugName: "bars" }] : /* istanbul ignore next */ []));
|
|
394
|
+
dotLayout = computed(() => {
|
|
395
|
+
if (this.styles() !== 'dot') {
|
|
396
|
+
return null;
|
|
397
|
+
}
|
|
398
|
+
const layout = this.layout();
|
|
399
|
+
return computeBarDotCells({
|
|
400
|
+
bars: layout.bars,
|
|
401
|
+
orientation: this.orientation(),
|
|
402
|
+
innerWidth: this.innerWidth(),
|
|
403
|
+
innerHeight: this.innerHeight(),
|
|
404
|
+
baseline: layout.valueScale(0),
|
|
405
|
+
dotSize: this.dotSize(),
|
|
406
|
+
dotGap: this.dotGap(),
|
|
407
|
+
});
|
|
408
|
+
}, /* @ts-ignore */
|
|
409
|
+
...(ngDevMode ? [{ debugName: "dotLayout" }] : /* istanbul ignore next */ []));
|
|
410
|
+
dotTrackCells = computed(() => (this.showDotTrack() ? (this.dotLayout()?.track ?? []) : []), /* @ts-ignore */
|
|
411
|
+
...(ngDevMode ? [{ debugName: "dotTrackCells" }] : /* istanbul ignore next */ []));
|
|
412
|
+
dotValueCells = computed(() => this.dotLayout()?.values ?? [], /* @ts-ignore */
|
|
413
|
+
...(ngDevMode ? [{ debugName: "dotValueCells" }] : /* istanbul ignore next */ []));
|
|
414
|
+
viewBox = computed(() => {
|
|
415
|
+
const { width, height } = this.root.dimensions();
|
|
416
|
+
return `0 0 ${Math.max(0, width)} ${Math.max(0, height)}`;
|
|
417
|
+
}, /* @ts-ignore */
|
|
418
|
+
...(ngDevMode ? [{ debugName: "viewBox" }] : /* istanbul ignore next */ []));
|
|
419
|
+
innerTransform = computed(() => `translate(${this.margin().left},${this.margin().top})`, /* @ts-ignore */
|
|
420
|
+
...(ngDevMode ? [{ debugName: "innerTransform" }] : /* istanbul ignore next */ []));
|
|
421
|
+
ariaSummary = computed(() => {
|
|
422
|
+
const keys = this.root.visibleSeriesKeys();
|
|
423
|
+
const n = this.data().length;
|
|
424
|
+
return `Bar chart, ${n} categories, ${keys.length} series: ${keys.join(', ')}.`;
|
|
425
|
+
}, /* @ts-ignore */
|
|
426
|
+
...(ngDevMode ? [{ debugName: "ariaSummary" }] : /* istanbul ignore next */ []));
|
|
427
|
+
constructor() {
|
|
428
|
+
effect(() => {
|
|
429
|
+
const layout = this.layout();
|
|
430
|
+
this.cart.orientation.set(this.orientation());
|
|
431
|
+
this.cart.margin.set(this.margin());
|
|
432
|
+
this.cart.innerWidth.set(this.innerWidth());
|
|
433
|
+
this.cart.innerHeight.set(this.innerHeight());
|
|
434
|
+
this.cart.categoryScale.set(layout.categoryScale);
|
|
435
|
+
this.cart.valueScale.set(layout.valueScale);
|
|
436
|
+
this.cart.categories.set(layout.categories);
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
emitClick(bar) {
|
|
440
|
+
this.barClick.emit({
|
|
441
|
+
seriesKey: bar.seriesKey,
|
|
442
|
+
datumIndex: bar.datumIndex,
|
|
443
|
+
category: bar.category,
|
|
444
|
+
value: bar.value,
|
|
445
|
+
datum: this.data()[bar.datumIndex],
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
setActivePoint(event, bar) {
|
|
449
|
+
const center = elementClientCenter(event.currentTarget);
|
|
450
|
+
this.root.activePoint.set({
|
|
451
|
+
index: bar.datumIndex,
|
|
452
|
+
seriesKey: bar.seriesKey,
|
|
453
|
+
clientX: center?.clientX,
|
|
454
|
+
clientY: center?.clientY,
|
|
455
|
+
});
|
|
456
|
+
}
|
|
457
|
+
clearActivePoint() {
|
|
458
|
+
this.root.activePoint.set(null);
|
|
459
|
+
}
|
|
460
|
+
barOpacity(bar) {
|
|
461
|
+
return this.emphasisOpacity(bar.active);
|
|
462
|
+
}
|
|
463
|
+
dotCellOpacity(cell) {
|
|
464
|
+
return this.emphasisOpacity(cell.active);
|
|
465
|
+
}
|
|
466
|
+
/** In `dot` style the bar rect stays as an invisible interaction target. */
|
|
467
|
+
barFill(bar) {
|
|
468
|
+
return this.styles() === 'dot' ? 'transparent' : bar.color;
|
|
469
|
+
}
|
|
470
|
+
emphasisOpacity(active) {
|
|
471
|
+
return this.activeKey() && this.activeValue() !== undefined ? (active ? 1 : 0.42) : 1;
|
|
472
|
+
}
|
|
473
|
+
formatValueLabel(bar) {
|
|
474
|
+
return this.valueLabelFormat()(bar.value);
|
|
475
|
+
}
|
|
476
|
+
barLabelX(bar) {
|
|
477
|
+
if (this.orientation() === 'vertical') {
|
|
478
|
+
return bar.x + bar.width / 2;
|
|
479
|
+
}
|
|
480
|
+
return bar.value >= 0 ? bar.x + bar.width + 6 : bar.x - 6;
|
|
481
|
+
}
|
|
482
|
+
barLabelY(bar) {
|
|
483
|
+
if (this.orientation() === 'vertical') {
|
|
484
|
+
return bar.value >= 0 ? bar.y - 8 : bar.y + bar.height + 10;
|
|
485
|
+
}
|
|
486
|
+
return bar.y + bar.height / 2;
|
|
487
|
+
}
|
|
488
|
+
barLabelAnchor(bar) {
|
|
489
|
+
if (this.orientation() === 'vertical') {
|
|
490
|
+
return 'middle';
|
|
491
|
+
}
|
|
492
|
+
return bar.value >= 0 ? 'start' : 'end';
|
|
493
|
+
}
|
|
494
|
+
barAriaLabel(bar) {
|
|
495
|
+
const label = this.root.config()[bar.seriesKey]?.label ?? bar.seriesKey;
|
|
496
|
+
return `${label} in ${bar.category}: ${bar.value}`;
|
|
497
|
+
}
|
|
498
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BarChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
499
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.2", type: BarChart, isStandalone: true, selector: "ChartBar", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, xKey: { classPropertyName: "xKey", publicName: "xKey", isSignal: true, isRequired: true, transformFunction: null }, orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, variant: { classPropertyName: "variant", publicName: "variant", isSignal: true, isRequired: false, transformFunction: null }, styles: { classPropertyName: "styles", publicName: "styles", isSignal: true, isRequired: false, transformFunction: null }, margin: { classPropertyName: "margin", publicName: "margin", isSignal: true, isRequired: false, transformFunction: null }, bandPadding: { classPropertyName: "bandPadding", publicName: "bandPadding", isSignal: true, isRequired: false, transformFunction: null }, groupPadding: { classPropertyName: "groupPadding", publicName: "groupPadding", isSignal: true, isRequired: false, transformFunction: null }, cornerRadius: { classPropertyName: "cornerRadius", publicName: "cornerRadius", isSignal: true, isRequired: false, transformFunction: null }, colorKey: { classPropertyName: "colorKey", publicName: "colorKey", isSignal: true, isRequired: false, transformFunction: null }, activeKey: { classPropertyName: "activeKey", publicName: "activeKey", isSignal: true, isRequired: false, transformFunction: null }, activeValue: { classPropertyName: "activeValue", publicName: "activeValue", isSignal: true, isRequired: false, transformFunction: null }, showValueLabels: { classPropertyName: "showValueLabels", publicName: "showValueLabels", isSignal: true, isRequired: false, transformFunction: null }, valueLabelFormat: { classPropertyName: "valueLabelFormat", publicName: "valueLabelFormat", isSignal: true, isRequired: false, transformFunction: null }, dotSize: { classPropertyName: "dotSize", publicName: "dotSize", isSignal: true, isRequired: false, transformFunction: null }, dotGap: { classPropertyName: "dotGap", publicName: "dotGap", isSignal: true, isRequired: false, transformFunction: null }, dotCornerRadius: { classPropertyName: "dotCornerRadius", publicName: "dotCornerRadius", isSignal: true, isRequired: false, transformFunction: null }, showDotTrack: { classPropertyName: "showDotTrack", publicName: "showDotTrack", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { barClick: "barClick" }, host: { properties: { "attr.data-style": "styles()" }, classAttribute: "relative block h-full w-full" }, providers: [CartesianContext], ngImport: i0, template: `
|
|
500
|
+
<svg:svg
|
|
501
|
+
ChartPointerTracker
|
|
502
|
+
class="block h-full w-full overflow-visible"
|
|
503
|
+
[attr.viewBox]="viewBox()"
|
|
504
|
+
preserveAspectRatio="none"
|
|
505
|
+
role="img"
|
|
506
|
+
[attr.aria-label]="ariaSummary()">
|
|
507
|
+
<svg:g [attr.transform]="innerTransform()">
|
|
508
|
+
<ng-content select="svg\\:g[ChartGrid]" />
|
|
509
|
+
<svg:g class="chart-bars">
|
|
510
|
+
@if (styles() === 'dot') {
|
|
511
|
+
<svg:g class="chart-bar-dots" aria-hidden="true">
|
|
512
|
+
@for (cell of dotTrackCells(); track cell.key) {
|
|
513
|
+
<svg:rect
|
|
514
|
+
class="chart-bar-dot-track"
|
|
515
|
+
[attr.x]="cell.x"
|
|
516
|
+
[attr.y]="cell.y"
|
|
517
|
+
[attr.width]="cell.width"
|
|
518
|
+
[attr.height]="cell.height"
|
|
519
|
+
[attr.rx]="dotCornerRadius()"
|
|
520
|
+
[attr.ry]="dotCornerRadius()"
|
|
521
|
+
fill="hsl(var(--muted))" />
|
|
522
|
+
}
|
|
523
|
+
@for (cell of dotValueCells(); track cell.key) {
|
|
524
|
+
<svg:rect
|
|
525
|
+
class="chart-bar-dot-value"
|
|
526
|
+
[attr.x]="cell.x"
|
|
527
|
+
[attr.y]="cell.y"
|
|
528
|
+
[attr.width]="cell.width"
|
|
529
|
+
[attr.height]="cell.height"
|
|
530
|
+
[attr.rx]="dotCornerRadius()"
|
|
531
|
+
[attr.ry]="dotCornerRadius()"
|
|
532
|
+
[attr.fill]="cell.color"
|
|
533
|
+
[attr.opacity]="dotCellOpacity(cell)" />
|
|
534
|
+
}
|
|
535
|
+
</svg:g>
|
|
536
|
+
}
|
|
537
|
+
@for (bar of bars(); track bar.key) {
|
|
538
|
+
<svg:rect
|
|
539
|
+
class="chart-bar cursor-pointer outline-none transition-opacity hover:opacity-80"
|
|
540
|
+
[attr.x]="bar.x"
|
|
541
|
+
[attr.y]="bar.y"
|
|
542
|
+
[attr.width]="bar.width"
|
|
543
|
+
[attr.height]="bar.height"
|
|
544
|
+
[attr.rx]="cornerRadius()"
|
|
545
|
+
[attr.ry]="cornerRadius()"
|
|
546
|
+
[attr.fill]="barFill(bar)"
|
|
547
|
+
[attr.opacity]="barOpacity(bar)"
|
|
548
|
+
[attr.stroke]="bar.active ? 'hsl(var(--foreground))' : null"
|
|
549
|
+
[attr.stroke-width]="bar.active ? 1.5 : null"
|
|
550
|
+
[attr.aria-label]="barAriaLabel(bar)"
|
|
551
|
+
tabindex="0"
|
|
552
|
+
(focus)="setActivePoint($event, bar)"
|
|
553
|
+
(blur)="clearActivePoint()"
|
|
554
|
+
(click)="emitClick(bar)"
|
|
555
|
+
(keydown.enter)="emitClick(bar)"
|
|
556
|
+
(keydown.space)="emitClick(bar); $event.preventDefault()" />
|
|
557
|
+
@if (showValueLabels() && bar.height > 0 && bar.width > 0) {
|
|
558
|
+
<svg:text
|
|
559
|
+
class="chart-bar-value pointer-events-none fill-muted-foreground text-2xs"
|
|
560
|
+
[attr.x]="barLabelX(bar)"
|
|
561
|
+
[attr.y]="barLabelY(bar)"
|
|
562
|
+
[attr.text-anchor]="barLabelAnchor(bar)"
|
|
563
|
+
dominant-baseline="middle">
|
|
564
|
+
{{ formatValueLabel(bar) }}
|
|
565
|
+
</svg:text>
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
</svg:g>
|
|
569
|
+
<ng-content select="svg\\:g[ChartAxisX]" />
|
|
570
|
+
<ng-content select="svg\\:g[ChartAxisY]" />
|
|
571
|
+
<ng-content select="svg\\:g[ChartCrosshair]" />
|
|
572
|
+
<ng-content />
|
|
573
|
+
</svg:g>
|
|
574
|
+
</svg:svg>
|
|
575
|
+
<ng-content select="ChartTooltip" />
|
|
576
|
+
<ng-content select="ChartLegend" />
|
|
577
|
+
`, isInline: true, dependencies: [{ kind: "directive", type: ChartPointerTracker, selector: "svg:svg[ChartPointerTracker]" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
578
|
+
}
|
|
579
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.2", ngImport: i0, type: BarChart, decorators: [{
|
|
580
|
+
type: Component,
|
|
581
|
+
args: [{
|
|
582
|
+
selector: 'ChartBar',
|
|
583
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
584
|
+
providers: [CartesianContext],
|
|
585
|
+
imports: [ChartPointerTracker],
|
|
586
|
+
host: { class: 'relative block h-full w-full', '[attr.data-style]': 'styles()' },
|
|
587
|
+
template: `
|
|
588
|
+
<svg:svg
|
|
589
|
+
ChartPointerTracker
|
|
590
|
+
class="block h-full w-full overflow-visible"
|
|
591
|
+
[attr.viewBox]="viewBox()"
|
|
592
|
+
preserveAspectRatio="none"
|
|
593
|
+
role="img"
|
|
594
|
+
[attr.aria-label]="ariaSummary()">
|
|
595
|
+
<svg:g [attr.transform]="innerTransform()">
|
|
596
|
+
<ng-content select="svg\\:g[ChartGrid]" />
|
|
597
|
+
<svg:g class="chart-bars">
|
|
598
|
+
@if (styles() === 'dot') {
|
|
599
|
+
<svg:g class="chart-bar-dots" aria-hidden="true">
|
|
600
|
+
@for (cell of dotTrackCells(); track cell.key) {
|
|
601
|
+
<svg:rect
|
|
602
|
+
class="chart-bar-dot-track"
|
|
603
|
+
[attr.x]="cell.x"
|
|
604
|
+
[attr.y]="cell.y"
|
|
605
|
+
[attr.width]="cell.width"
|
|
606
|
+
[attr.height]="cell.height"
|
|
607
|
+
[attr.rx]="dotCornerRadius()"
|
|
608
|
+
[attr.ry]="dotCornerRadius()"
|
|
609
|
+
fill="hsl(var(--muted))" />
|
|
610
|
+
}
|
|
611
|
+
@for (cell of dotValueCells(); track cell.key) {
|
|
612
|
+
<svg:rect
|
|
613
|
+
class="chart-bar-dot-value"
|
|
614
|
+
[attr.x]="cell.x"
|
|
615
|
+
[attr.y]="cell.y"
|
|
616
|
+
[attr.width]="cell.width"
|
|
617
|
+
[attr.height]="cell.height"
|
|
618
|
+
[attr.rx]="dotCornerRadius()"
|
|
619
|
+
[attr.ry]="dotCornerRadius()"
|
|
620
|
+
[attr.fill]="cell.color"
|
|
621
|
+
[attr.opacity]="dotCellOpacity(cell)" />
|
|
622
|
+
}
|
|
623
|
+
</svg:g>
|
|
624
|
+
}
|
|
625
|
+
@for (bar of bars(); track bar.key) {
|
|
626
|
+
<svg:rect
|
|
627
|
+
class="chart-bar cursor-pointer outline-none transition-opacity hover:opacity-80"
|
|
628
|
+
[attr.x]="bar.x"
|
|
629
|
+
[attr.y]="bar.y"
|
|
630
|
+
[attr.width]="bar.width"
|
|
631
|
+
[attr.height]="bar.height"
|
|
632
|
+
[attr.rx]="cornerRadius()"
|
|
633
|
+
[attr.ry]="cornerRadius()"
|
|
634
|
+
[attr.fill]="barFill(bar)"
|
|
635
|
+
[attr.opacity]="barOpacity(bar)"
|
|
636
|
+
[attr.stroke]="bar.active ? 'hsl(var(--foreground))' : null"
|
|
637
|
+
[attr.stroke-width]="bar.active ? 1.5 : null"
|
|
638
|
+
[attr.aria-label]="barAriaLabel(bar)"
|
|
639
|
+
tabindex="0"
|
|
640
|
+
(focus)="setActivePoint($event, bar)"
|
|
641
|
+
(blur)="clearActivePoint()"
|
|
642
|
+
(click)="emitClick(bar)"
|
|
643
|
+
(keydown.enter)="emitClick(bar)"
|
|
644
|
+
(keydown.space)="emitClick(bar); $event.preventDefault()" />
|
|
645
|
+
@if (showValueLabels() && bar.height > 0 && bar.width > 0) {
|
|
646
|
+
<svg:text
|
|
647
|
+
class="chart-bar-value pointer-events-none fill-muted-foreground text-2xs"
|
|
648
|
+
[attr.x]="barLabelX(bar)"
|
|
649
|
+
[attr.y]="barLabelY(bar)"
|
|
650
|
+
[attr.text-anchor]="barLabelAnchor(bar)"
|
|
651
|
+
dominant-baseline="middle">
|
|
652
|
+
{{ formatValueLabel(bar) }}
|
|
653
|
+
</svg:text>
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
</svg:g>
|
|
657
|
+
<ng-content select="svg\\:g[ChartAxisX]" />
|
|
658
|
+
<ng-content select="svg\\:g[ChartAxisY]" />
|
|
659
|
+
<ng-content select="svg\\:g[ChartCrosshair]" />
|
|
660
|
+
<ng-content />
|
|
661
|
+
</svg:g>
|
|
662
|
+
</svg:svg>
|
|
663
|
+
<ng-content select="ChartTooltip" />
|
|
664
|
+
<ng-content select="ChartLegend" />
|
|
665
|
+
`,
|
|
666
|
+
}]
|
|
667
|
+
}], ctorParameters: () => [], propDecorators: { data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], xKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "xKey", required: true }] }], orientation: [{ type: i0.Input, args: [{ isSignal: true, alias: "orientation", required: false }] }], variant: [{ type: i0.Input, args: [{ isSignal: true, alias: "variant", required: false }] }], styles: [{ type: i0.Input, args: [{ isSignal: true, alias: "styles", required: false }] }], margin: [{ type: i0.Input, args: [{ isSignal: true, alias: "margin", required: false }] }], bandPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "bandPadding", required: false }] }], groupPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "groupPadding", required: false }] }], cornerRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "cornerRadius", required: false }] }], colorKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "colorKey", required: false }] }], activeKey: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeKey", required: false }] }], activeValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeValue", required: false }] }], showValueLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "showValueLabels", required: false }] }], valueLabelFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "valueLabelFormat", required: false }] }], dotSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "dotSize", required: false }] }], dotGap: [{ type: i0.Input, args: [{ isSignal: true, alias: "dotGap", required: false }] }], dotCornerRadius: [{ type: i0.Input, args: [{ isSignal: true, alias: "dotCornerRadius", required: false }] }], showDotTrack: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDotTrack", required: false }] }], barClick: [{ type: i0.Output, args: ["barClick"] }] } });
|
|
668
|
+
|
|
669
|
+
/**
|
|
670
|
+
* Generated bundle index. Do not edit.
|
|
671
|
+
*/
|
|
672
|
+
|
|
673
|
+
export { BarChart, computeBarDotCells, computeBarLayout };
|
|
674
|
+
//# sourceMappingURL=ojiepermana-angular-chart-bar.mjs.map
|