cats-charts 0.0.84 → 0.0.86
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 +712 -712
- package/assets/images/headerIcon.svg +3 -3
- package/assets/images/infoIcon.svg +10 -10
- package/assets/images/leftArrow.svg +3 -3
- package/assets/images/legend_left.svg +3 -3
- package/assets/images/legend_right.svg +3 -3
- package/assets/images/rightArrow.svg +3 -3
- package/fesm2022/cats-charts.mjs +509 -299
- package/fesm2022/cats-charts.mjs.map +1 -1
- package/index.d.ts +21 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,712 +1,712 @@
|
|
|
1
|
-
# CATS4U Charts
|
|
2
|
-
|
|
3
|
-

|
|
4
|
-

|
|
5
|
-

|
|
6
|
-

|
|
7
|
-
|
|
8
|
-
**CATS4U Charts** is a reusable Angular chart library built on **Apache ECharts** and **ngx-echarts**.
|
|
9
|
-
It provides easy-to-use components for rendering interactive charts such as **Bar, Line, Area, Pie, Doughnut, Sankey, Timeline**, and more.
|
|
10
|
-
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
# ✨ Features
|
|
14
|
-
|
|
15
|
-
- 📊 Multiple chart types
|
|
16
|
-
- ⚡ Powered by Apache ECharts
|
|
17
|
-
- 🔌 Angular Standalone Components
|
|
18
|
-
- 🎨 Built-in theme support
|
|
19
|
-
- 🖱 Click & drill-down events
|
|
20
|
-
- 🧩 Easy integration
|
|
21
|
-
- 📦 Lightweight and reusable
|
|
22
|
-
|
|
23
|
-
---
|
|
24
|
-
|
|
25
|
-
# 📦 Installation
|
|
26
|
-
|
|
27
|
-
Install the package along with required dependencies:
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
npm install cats-charts
|
|
31
|
-
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
# 🚀 Usage
|
|
35
|
-
|
|
36
|
-
## Import Library
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
import { ChartsLib } from 'cats-charts';
|
|
40
|
-
```
|
|
41
|
-
|
|
42
|
-
## TS Syntax
|
|
43
|
-
|
|
44
|
-
```ts
|
|
45
|
-
import {
|
|
46
|
-
BarChart,
|
|
47
|
-
CustomChartComponent,
|
|
48
|
-
DoughnutChart,
|
|
49
|
-
LinesChart,
|
|
50
|
-
PieChart,
|
|
51
|
-
SankeyChart
|
|
52
|
-
} from 'cats-charts';
|
|
53
|
-
|
|
54
|
-
@Component({
|
|
55
|
-
...,
|
|
56
|
-
imports: [
|
|
57
|
-
BarChart,
|
|
58
|
-
CustomChartComponent,
|
|
59
|
-
DoughnutChart,
|
|
60
|
-
LinesChart,
|
|
61
|
-
PieChart,
|
|
62
|
-
SankeyChart
|
|
63
|
-
],
|
|
64
|
-
})
|
|
65
|
-
export class App {}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
# ⚙️ Inputs
|
|
71
|
-
|
|
72
|
-
| Input | Type | Description |
|
|
73
|
-
| ------------------ | ------------------------------------------------- | -------------------------------------------------------------- |
|
|
74
|
-
| config | | Configuration options to customize chart and pass dynamic data |
|
|
75
|
-
| theme | string | default \| dark \| vintage \| essos \| chalk \| roma |
|
|
76
|
-
| contextMenuOptions | { label: string; value: string; icon?: string }[] | Context menu options |
|
|
77
|
-
| events | string[] | ['click', 'contextmenu', 'dblclick'] |
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
# 📤 Outputs
|
|
82
|
-
|
|
83
|
-
| Output | Description |
|
|
84
|
-
| ---------------- | ---------------------- |
|
|
85
|
-
| contextMenuClick | ( event: any ) => void |
|
|
86
|
-
| chartEvent | ( event: any ) => void |
|
|
87
|
-
|
|
88
|
-
## Bar chart config
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
BarChartConfig {
|
|
92
|
-
series: {
|
|
93
|
-
name: string;
|
|
94
|
-
data: number[];
|
|
95
|
-
[key: string]: any;
|
|
96
|
-
}[];
|
|
97
|
-
xAxisData: string[];
|
|
98
|
-
colors?: string[];
|
|
99
|
-
backgroundColor?: string;
|
|
100
|
-
|
|
101
|
-
// --------------- Title configs ---------------
|
|
102
|
-
title?: string;
|
|
103
|
-
titlePosition?: string;
|
|
104
|
-
showTitle?: boolean;
|
|
105
|
-
|
|
106
|
-
// --------------- Tooltip configs ---------------
|
|
107
|
-
showTooltip?: boolean;
|
|
108
|
-
tooltipFormatter?: (params: any) => void;
|
|
109
|
-
|
|
110
|
-
// --------------- Grid configs ---------------
|
|
111
|
-
gridLeft?: string | number;
|
|
112
|
-
gridRight?: string | number;
|
|
113
|
-
gridBottom?: string | number;
|
|
114
|
-
gridTop?: string | number;
|
|
115
|
-
|
|
116
|
-
// --------------- Zoom Slider configs ---------------
|
|
117
|
-
showZoomSlider?: boolean;
|
|
118
|
-
zoomStart?: number;
|
|
119
|
-
zoomEnd?: number;
|
|
120
|
-
zoomControlButtonStyle?: any;
|
|
121
|
-
|
|
122
|
-
yAxis?: any;
|
|
123
|
-
xAxis?: any;
|
|
124
|
-
stacked?: boolean;
|
|
125
|
-
|
|
126
|
-
barWidth?: string | number;
|
|
127
|
-
|
|
128
|
-
borderRadius?: number;
|
|
129
|
-
showLabel?: boolean;
|
|
130
|
-
labelPosition?: string;
|
|
131
|
-
showXAxisLine?: boolean;
|
|
132
|
-
showYAxisLine?: boolean;
|
|
133
|
-
// Legend
|
|
134
|
-
hideLegend?: boolean;
|
|
135
|
-
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
136
|
-
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
137
|
-
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
138
|
-
legendTextColor?: string;
|
|
139
|
-
legendFontSize?: number;
|
|
140
|
-
legendContainerWidth?: number; // 0-1
|
|
141
|
-
legendIndicatorHeight?: number; // number value is in px
|
|
142
|
-
}
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
## Line and Area Chart config
|
|
146
|
-
|
|
147
|
-
```ts
|
|
148
|
-
LineChartConfig {
|
|
149
|
-
isTrendChart?: boolean;
|
|
150
|
-
title?: string;
|
|
151
|
-
showTitle?: boolean;
|
|
152
|
-
titlePosition?: string;
|
|
153
|
-
xAxisData: string[];
|
|
154
|
-
tooltipFormatter?: (params: any) => void;
|
|
155
|
-
colors?: string[];
|
|
156
|
-
series: {
|
|
157
|
-
name: string;
|
|
158
|
-
data: number[];
|
|
159
|
-
areaColor?: string;
|
|
160
|
-
smooth?: boolean;
|
|
161
|
-
area?: boolean;
|
|
162
|
-
[key: string]: any;
|
|
163
|
-
}[];
|
|
164
|
-
// --------------- Grid configs ---------------
|
|
165
|
-
gridLeft?: string | number;
|
|
166
|
-
gridRight?: string | number;
|
|
167
|
-
gridBottom?: string | number;
|
|
168
|
-
gridTop?: string | number;
|
|
169
|
-
|
|
170
|
-
borderRadius?: number;
|
|
171
|
-
showLabel?: boolean;
|
|
172
|
-
labelPosition?: string;
|
|
173
|
-
|
|
174
|
-
yAxis?: any;
|
|
175
|
-
xAxis?: any;
|
|
176
|
-
showXAxisLine?: boolean;
|
|
177
|
-
showYAxisLine?: boolean;
|
|
178
|
-
showTooltip?: boolean;
|
|
179
|
-
|
|
180
|
-
backgroundColor?: string;
|
|
181
|
-
|
|
182
|
-
// Legend
|
|
183
|
-
hideLegend?: boolean;
|
|
184
|
-
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
185
|
-
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
186
|
-
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
187
|
-
legendTextColor?: string;
|
|
188
|
-
legendFontSize?: number;
|
|
189
|
-
legendContainerWidth?: number; // 0-1
|
|
190
|
-
legendIndicatorHeight?: number; // number value is in px
|
|
191
|
-
|
|
192
|
-
customLegend?: ChartLegendConfig<LineChartConfig['series'][number]>;
|
|
193
|
-
|
|
194
|
-
}
|
|
195
|
-
```
|
|
196
|
-
|
|
197
|
-
### CustomLegend
|
|
198
|
-
|
|
199
|
-
```ts
|
|
200
|
-
type customLegend = {
|
|
201
|
-
enabled?: boolean;
|
|
202
|
-
|
|
203
|
-
// layout/positioning
|
|
204
|
-
layout?: 'horizontal' | 'vertical';
|
|
205
|
-
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
206
|
-
align?: 'start' | 'center' | 'end';
|
|
207
|
-
|
|
208
|
-
// selection behavior
|
|
209
|
-
selectionMode?: 'multiple' | 'single' | 'exclusive';
|
|
210
|
-
|
|
211
|
-
// scrolling / pagination
|
|
212
|
-
scrollable?: boolean;
|
|
213
|
-
maxHeight?: string;
|
|
214
|
-
maxWidth?: string;
|
|
215
|
-
pageSize?: number;
|
|
216
|
-
showPagination?: boolean;
|
|
217
|
-
|
|
218
|
-
// disabling items
|
|
219
|
-
disabled?: boolean;
|
|
220
|
-
disabledNames?: string[];
|
|
221
|
-
|
|
222
|
-
// accessibility / styling
|
|
223
|
-
className?: string;
|
|
224
|
-
ariaLabel?: string;
|
|
225
|
-
legendTextColor?: string;
|
|
226
|
-
legendFontSize?: number;
|
|
227
|
-
|
|
228
|
-
// icon rendering
|
|
229
|
-
icon?: ChartLegendIcon | ((series: TSeries, index: number) => ChartLegendIcon);
|
|
230
|
-
|
|
231
|
-
icons?: Record<string, ChartLegendIcon>;
|
|
232
|
-
|
|
233
|
-
// label formatting
|
|
234
|
-
formatter?: (name: string, item: ChartLegendItem) => string;
|
|
235
|
-
tooltipFormatter?: (item: ChartLegendItem) => string;
|
|
236
|
-
|
|
237
|
-
// grouping
|
|
238
|
-
groupBy?: (item: ChartLegendItem) => string | undefined;
|
|
239
|
-
|
|
240
|
-
// custom Angular template
|
|
241
|
-
itemTemplate?: TemplateRef<ChartLegendTemplateContext>;
|
|
242
|
-
|
|
243
|
-
// virtualization (advanced)
|
|
244
|
-
virtualize?: boolean;
|
|
245
|
-
virtualItemHeight?: number;
|
|
246
|
-
|
|
247
|
-
// hover behavior linking
|
|
248
|
-
hoverLink?: boolean;
|
|
249
|
-
};
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### CustomLegend Example
|
|
253
|
-
|
|
254
|
-
```ts
|
|
255
|
-
customLegend?: {
|
|
256
|
-
// enable/disable legend UI
|
|
257
|
-
enabled?: boolean;
|
|
258
|
-
|
|
259
|
-
// layout
|
|
260
|
-
layout?: 'horizontal' | 'vertical';
|
|
261
|
-
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
262
|
-
align?: 'start' | 'center' | 'end';
|
|
263
|
-
|
|
264
|
-
// selection behavior
|
|
265
|
-
selectionMode?: 'multiple' | 'single' | 'exclusive';
|
|
266
|
-
|
|
267
|
-
// scrolling/pagination
|
|
268
|
-
scrollable?: boolean;
|
|
269
|
-
maxHeight?: string;
|
|
270
|
-
maxWidth?: string;
|
|
271
|
-
pageSize?: number;
|
|
272
|
-
showPagination?: boolean;
|
|
273
|
-
|
|
274
|
-
// disabling items
|
|
275
|
-
disabled?: boolean;
|
|
276
|
-
disabledNames?: string[];
|
|
277
|
-
|
|
278
|
-
// styling & accessibility
|
|
279
|
-
className?: string;
|
|
280
|
-
ariaLabel?: string;
|
|
281
|
-
legendTextColor?: string;
|
|
282
|
-
legendFontSize?: number;
|
|
283
|
-
|
|
284
|
-
// icon configuration
|
|
285
|
-
// - either a static icon
|
|
286
|
-
// - or a function that returns an icon per series/index
|
|
287
|
-
icon?:
|
|
288
|
-
| ChartLegendIcon
|
|
289
|
-
| ((series: TSeries, index: number) => ChartLegendIcon);
|
|
290
|
-
|
|
291
|
-
// mapping of icon names -> icon types
|
|
292
|
-
icons?: Record<string, ChartLegendIcon>;
|
|
293
|
-
|
|
294
|
-
// text formatting
|
|
295
|
-
formatter?: (name: string, item: ChartLegendItem) => string;
|
|
296
|
-
|
|
297
|
-
// tooltip formatting
|
|
298
|
-
tooltipFormatter?: (item: ChartLegendItem) => string;
|
|
299
|
-
|
|
300
|
-
// grouping
|
|
301
|
-
groupBy?: (item: ChartLegendItem) => string | undefined;
|
|
302
|
-
|
|
303
|
-
// custom Angular template (advanced)
|
|
304
|
-
itemTemplate?: TemplateRef<ChartLegendTemplateContext>;
|
|
305
|
-
|
|
306
|
-
// virtualization (advanced)
|
|
307
|
-
virtualize?: boolean;
|
|
308
|
-
virtualItemHeight?: number;
|
|
309
|
-
|
|
310
|
-
// hover linking (advanced)
|
|
311
|
-
hoverLink?: boolean;
|
|
312
|
-
};
|
|
313
|
-
|
|
314
|
-
```
|
|
315
|
-
|
|
316
|
-
## Pie and Donut chart config
|
|
317
|
-
|
|
318
|
-
```ts
|
|
319
|
-
DoughnutChartConfig {
|
|
320
|
-
title?: string;
|
|
321
|
-
showTitle?: boolean;
|
|
322
|
-
titlePosition?: 'left' | 'center' | 'right';
|
|
323
|
-
top?: any;
|
|
324
|
-
bottom?: any;
|
|
325
|
-
backgroundColor?: string;
|
|
326
|
-
series?: any;
|
|
327
|
-
data: {
|
|
328
|
-
name: string;
|
|
329
|
-
value: number;
|
|
330
|
-
[key: string]: any;
|
|
331
|
-
}[];
|
|
332
|
-
|
|
333
|
-
colors?: string[];
|
|
334
|
-
|
|
335
|
-
// Doughnut
|
|
336
|
-
innerRadius?: string;
|
|
337
|
-
outerRadius?: string;
|
|
338
|
-
center?: string[];
|
|
339
|
-
// Center Text
|
|
340
|
-
showCenterText?: boolean;
|
|
341
|
-
centerLabel?: any;
|
|
342
|
-
centerValue?: string;
|
|
343
|
-
centerValueFromTotal?: boolean;
|
|
344
|
-
|
|
345
|
-
// Tooltip
|
|
346
|
-
showTooltip?: boolean;
|
|
347
|
-
showTooltipPercent?: boolean;
|
|
348
|
-
tooltipFormatter?: (params: any, config: DoughnutChartConfig) => void;
|
|
349
|
-
valueFormatter?: (value: number) => string;
|
|
350
|
-
|
|
351
|
-
// Legend
|
|
352
|
-
hideLegend?: boolean;
|
|
353
|
-
legendBottom?: number;
|
|
354
|
-
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
355
|
-
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
356
|
-
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
357
|
-
legendTextColor?: string;
|
|
358
|
-
legendFontSize?: number;
|
|
359
|
-
legendContainerWidth?: number; // 0-1
|
|
360
|
-
// Labels
|
|
361
|
-
showLabel?: boolean;
|
|
362
|
-
labelPosition?: 'inside' | 'outside' | 'center';
|
|
363
|
-
showLabelValue?: boolean;
|
|
364
|
-
showLabelPercentage?: boolean;
|
|
365
|
-
|
|
366
|
-
// Emphasis
|
|
367
|
-
emphasisScale?: boolean;
|
|
368
|
-
|
|
369
|
-
// Style
|
|
370
|
-
borderRadius?: number;
|
|
371
|
-
borderColor?: string;
|
|
372
|
-
borderWidth?: number;
|
|
373
|
-
|
|
374
|
-
enableHoverEffect?: boolean;
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
## Custom chart config
|
|
379
|
-
|
|
380
|
-
```ts
|
|
381
|
-
CustomChartConfig {
|
|
382
|
-
startHour?: string;
|
|
383
|
-
endHour?: string;
|
|
384
|
-
|
|
385
|
-
shiftColor?: string;
|
|
386
|
-
chartMode: 'weekly' | 'daily' | string;
|
|
387
|
-
|
|
388
|
-
yAxisData: string[];
|
|
389
|
-
categories: string[];
|
|
390
|
-
legends: TimeLineLegends;
|
|
391
|
-
|
|
392
|
-
barHeight?: number;
|
|
393
|
-
shiftHeight?: number;
|
|
394
|
-
|
|
395
|
-
data: TimelineData[];
|
|
396
|
-
hideLegendCategory?: boolean;
|
|
397
|
-
}
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## Scatter Chart config
|
|
401
|
-
|
|
402
|
-
```ts
|
|
403
|
-
ScatterChartConfig {
|
|
404
|
-
title?: string;
|
|
405
|
-
showTitle?: boolean;
|
|
406
|
-
titlePosition?: string;
|
|
407
|
-
tooltipFormatter?: (params: any) => void;
|
|
408
|
-
colors?: string[];
|
|
409
|
-
series: {
|
|
410
|
-
name: string;
|
|
411
|
-
data: number[];
|
|
412
|
-
[key: string]: any;
|
|
413
|
-
}[];
|
|
414
|
-
// --------------- Grid configs ---------------
|
|
415
|
-
gridLeft?: string | number;
|
|
416
|
-
gridRight?: string | number;
|
|
417
|
-
gridBottom?: string | number;
|
|
418
|
-
gridTop?: string | number;
|
|
419
|
-
|
|
420
|
-
labelPosition?: string;
|
|
421
|
-
|
|
422
|
-
yAxis?: any;
|
|
423
|
-
xAxis?: any;
|
|
424
|
-
showXAxisLine?: boolean;
|
|
425
|
-
showYAxisLine?: boolean;
|
|
426
|
-
showTooltip?: boolean;
|
|
427
|
-
|
|
428
|
-
backgroundColor?: string;
|
|
429
|
-
|
|
430
|
-
// Legend
|
|
431
|
-
hideLegend?: boolean;
|
|
432
|
-
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
433
|
-
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
434
|
-
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
435
|
-
legendTextColor?: string;
|
|
436
|
-
legendFontSize?: number;
|
|
437
|
-
legendContainerWidth?: number; // 0-1
|
|
438
|
-
legendIndicatorHeight?: number; // number value is in px
|
|
439
|
-
xAxisName?: string;
|
|
440
|
-
yAxisName?: string;
|
|
441
|
-
}
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
## Sankey Chart config
|
|
445
|
-
|
|
446
|
-
```ts
|
|
447
|
-
SankeyChartConfig {
|
|
448
|
-
title?: string;
|
|
449
|
-
showTitle?: boolean;
|
|
450
|
-
backgroundColor?: string;
|
|
451
|
-
colors?: string[];
|
|
452
|
-
showTooltip?: boolean;
|
|
453
|
-
tooltipFormatter?: (params: any) => string;
|
|
454
|
-
nodes: SankeyNode[];
|
|
455
|
-
links: SankeyLink[];
|
|
456
|
-
seriesOption?: SankeySeriesOption;
|
|
457
|
-
lineCurveness?: number;
|
|
458
|
-
}
|
|
459
|
-
```
|
|
460
|
-
|
|
461
|
-
### For `SankeySeriesOption` refer echarts Sankey series documentation
|
|
462
|
-
|
|
463
|
-
https://echarts.apache.org/en/option.html#series-sankey
|
|
464
|
-
|
|
465
|
-
# 📊 Supported Charts
|
|
466
|
-
|
|
467
|
-
- Bar Chart
|
|
468
|
-
- Line Chart
|
|
469
|
-
- Area Chart
|
|
470
|
-
- Pie Chart
|
|
471
|
-
- Doughnut Chart
|
|
472
|
-
- Stacked Area Chart
|
|
473
|
-
- Sankey Chart
|
|
474
|
-
- Heatmap Chart
|
|
475
|
-
- Custom Charts
|
|
476
|
-
|
|
477
|
-
* Bar Chart
|
|
478
|
-
* Line Chart
|
|
479
|
-
* Area Chart
|
|
480
|
-
* Pie Chart
|
|
481
|
-
* Doughnut Chart
|
|
482
|
-
* Stacked Area Chart
|
|
483
|
-
* Sankey Chart
|
|
484
|
-
* Custom Charts
|
|
485
|
-
|
|
486
|
-
---
|
|
487
|
-
|
|
488
|
-
# Heatmap Chart
|
|
489
|
-
|
|
490
|
-
The heatmap component renders category-based intensity data using Apache ECharts.
|
|
491
|
-
Use `[xIndex, yIndex, value]` tuples, where `xIndex` points to `xAxisData` and `yIndex` points to `yAxisData`.
|
|
492
|
-
|
|
493
|
-
## Import
|
|
494
|
-
|
|
495
|
-
```ts
|
|
496
|
-
import { Heatmap } from 'cats-charts';
|
|
497
|
-
|
|
498
|
-
@Component({
|
|
499
|
-
selector: 'app-root',
|
|
500
|
-
standalone: true,
|
|
501
|
-
imports: [Heatmap],
|
|
502
|
-
templateUrl: './app.html',
|
|
503
|
-
})
|
|
504
|
-
export class App {}
|
|
505
|
-
```
|
|
506
|
-
|
|
507
|
-
## HTML
|
|
508
|
-
|
|
509
|
-
```html
|
|
510
|
-
<div style="width: 100%; height: 340px">
|
|
511
|
-
<lib-heatmap
|
|
512
|
-
[config]="heatmapConfig"
|
|
513
|
-
[theme]="selectedTheme"
|
|
514
|
-
[events]="['click', 'contextmenu']"
|
|
515
|
-
(chartEvent)="handleChartEvent($event)"
|
|
516
|
-
></lib-heatmap>
|
|
517
|
-
</div>
|
|
518
|
-
```
|
|
519
|
-
|
|
520
|
-
## TypeScript
|
|
521
|
-
|
|
522
|
-
```ts
|
|
523
|
-
heatmapConfig = {
|
|
524
|
-
xAxisData: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00'],
|
|
525
|
-
yAxisData: ['eth0', 'eth1', 'wlan0', 'vlan10', 'vlan20'],
|
|
526
|
-
|
|
527
|
-
data: [
|
|
528
|
-
[0, 0, 20],
|
|
529
|
-
[1, 0, 60],
|
|
530
|
-
[2, 0, 0],
|
|
531
|
-
[3, 0, 40],
|
|
532
|
-
[4, 0, 80],
|
|
533
|
-
[5, 0, 100],
|
|
534
|
-
|
|
535
|
-
[0, 1, 40],
|
|
536
|
-
[1, 1, 0],
|
|
537
|
-
[2, 1, 20],
|
|
538
|
-
[3, 1, 60],
|
|
539
|
-
[4, 1, 100],
|
|
540
|
-
[5, 1, 80],
|
|
541
|
-
] as [number, number, number][],
|
|
542
|
-
|
|
543
|
-
min: 0,
|
|
544
|
-
max: 100,
|
|
545
|
-
showTooltip: true,
|
|
546
|
-
|
|
547
|
-
grid: {
|
|
548
|
-
left: 58,
|
|
549
|
-
right: 18,
|
|
550
|
-
top: 20,
|
|
551
|
-
bottom: 46,
|
|
552
|
-
containLabel: false,
|
|
553
|
-
},
|
|
554
|
-
|
|
555
|
-
xAxis: {
|
|
556
|
-
axisLabel: { color: '#6b7280' },
|
|
557
|
-
axisLine: { lineStyle: { color: '#9ca3af' } },
|
|
558
|
-
axisTick: { show: true },
|
|
559
|
-
},
|
|
560
|
-
|
|
561
|
-
yAxis: {
|
|
562
|
-
inverse: true,
|
|
563
|
-
axisLabel: { color: '#6b7280' },
|
|
564
|
-
axisLine: { show: false },
|
|
565
|
-
axisTick: { show: true },
|
|
566
|
-
},
|
|
567
|
-
|
|
568
|
-
visualMap: {
|
|
569
|
-
type: 'piecewise',
|
|
570
|
-
pieces: [
|
|
571
|
-
{ min: 0, max: 20, label: '20%', color: '#fde6bd' },
|
|
572
|
-
{ min: 21, max: 40, label: '40%', color: '#ffd85a' },
|
|
573
|
-
{ min: 41, max: 60, label: '60%', color: '#ffb247' },
|
|
574
|
-
{ min: 61, max: 80, label: '80%', color: '#ff0b1f' },
|
|
575
|
-
{ min: 81, max: 100, label: '100%', color: '#a51d29' },
|
|
576
|
-
],
|
|
577
|
-
},
|
|
578
|
-
|
|
579
|
-
series: {
|
|
580
|
-
itemStyle: {
|
|
581
|
-
borderWidth: 0,
|
|
582
|
-
},
|
|
583
|
-
},
|
|
584
|
-
};
|
|
585
|
-
```
|
|
586
|
-
|
|
587
|
-
## Heatmap Config Options
|
|
588
|
-
|
|
589
|
-
| Option | Type | Description |
|
|
590
|
-
| ---------------- | -------------------------- | ----------------------------------------------------------------------- |
|
|
591
|
-
| xAxisData | string[] | Labels for the x-axis |
|
|
592
|
-
| yAxisData | string[] | Labels for the y-axis |
|
|
593
|
-
| data | [number, number, number][] | Heatmap cells as `[xIndex, yIndex, value]` |
|
|
594
|
-
| min | number | Minimum value for color mapping |
|
|
595
|
-
| max | number | Maximum value for color mapping |
|
|
596
|
-
| colors | string[] | Continuous color range when `visualMap.pieces` is not used |
|
|
597
|
-
| visualMap | any | ECharts visual map config. `pieces` also drives the custom legend pills |
|
|
598
|
-
| grid | object | ECharts grid config |
|
|
599
|
-
| xAxis | any | Extra ECharts x-axis config |
|
|
600
|
-
| yAxis | any | Extra ECharts y-axis config |
|
|
601
|
-
| showTooltip | boolean | Enables or disables tooltip |
|
|
602
|
-
| tooltipFormatter | function | Custom tooltip formatter |
|
|
603
|
-
| showLabel | boolean | Shows value labels inside cells |
|
|
604
|
-
| labelFormatter | string \| function | Cell label formatter |
|
|
605
|
-
| series | any \| any[] | Extra ECharts heatmap series config |
|
|
606
|
-
|
|
607
|
-
---
|
|
608
|
-
|
|
609
|
-
# 🎨 Themes
|
|
610
|
-
|
|
611
|
-
Available chart themes:
|
|
612
|
-
|
|
613
|
-
- default
|
|
614
|
-
- dark
|
|
615
|
-
- vintage
|
|
616
|
-
- essos
|
|
617
|
-
- chalk
|
|
618
|
-
- roma
|
|
619
|
-
|
|
620
|
-
---
|
|
621
|
-
|
|
622
|
-
# 📚 Documentation
|
|
623
|
-
|
|
624
|
-
Apache ECharts documentation:
|
|
625
|
-
|
|
626
|
-
https://echarts.apache.org/en/api.html#echarts
|
|
627
|
-
|
|
628
|
-
---
|
|
629
|
-
|
|
630
|
-
# 🤝 Contributing
|
|
631
|
-
|
|
632
|
-
Contributions, issues, and feature requests are welcome.
|
|
633
|
-
Feel free to submit a pull request.
|
|
634
|
-
|
|
635
|
-
---
|
|
636
|
-
|
|
637
|
-
# 📄 License
|
|
638
|
-
|
|
639
|
-
MIT License
|
|
640
|
-
|
|
641
|
-
---
|
|
642
|
-
|
|
643
|
-
# Status Timeline
|
|
644
|
-
|
|
645
|
-
`StatusTimelineComponent` renders generic categorical intervals in chronological order. Segment
|
|
646
|
-
widths are proportional to duration, and dense datasets scroll horizontally without aggregation.
|
|
647
|
-
|
|
648
|
-
## Import and usage
|
|
649
|
-
|
|
650
|
-
```ts
|
|
651
|
-
import { StatusTimelineComponent, type StatusTimelineConfig } from 'cats-charts';
|
|
652
|
-
|
|
653
|
-
@Component({
|
|
654
|
-
standalone: true,
|
|
655
|
-
imports: [StatusTimelineComponent],
|
|
656
|
-
template: `
|
|
657
|
-
<lib-status-timeline
|
|
658
|
-
[config]="timelineConfig"
|
|
659
|
-
(chartEvent)="onTimelineEvent($event)"
|
|
660
|
-
/>
|
|
661
|
-
`,
|
|
662
|
-
})
|
|
663
|
-
export class ExampleComponent {
|
|
664
|
-
timelineConfig: StatusTimelineConfig = {
|
|
665
|
-
startLabel: 'Monday',
|
|
666
|
-
endLabel: 'Today',
|
|
667
|
-
statuses: [
|
|
668
|
-
{ value: 'ready', label: 'Ready', color: '#2f8f3a' },
|
|
669
|
-
{ value: 'deploying', label: 'Deploying', color: '#d0a020' },
|
|
670
|
-
{ value: 'blocked', label: 'Blocked', color: '#a43b35' },
|
|
671
|
-
],
|
|
672
|
-
data: [
|
|
673
|
-
{ start: '2026-08-24T00:00:00Z', end: '2026-08-25T00:00:00Z', status: 'ready' },
|
|
674
|
-
{
|
|
675
|
-
start: '2026-08-25T00:00:00Z',
|
|
676
|
-
end: '2026-08-25T06:00:00Z',
|
|
677
|
-
status: 'deploying',
|
|
678
|
-
label: 'Release deployment',
|
|
679
|
-
},
|
|
680
|
-
{ start: '2026-08-25T06:00:00Z', end: '2026-08-26T00:00:00Z', status: 'ready' },
|
|
681
|
-
],
|
|
682
|
-
};
|
|
683
|
-
}
|
|
684
|
-
```
|
|
685
|
-
|
|
686
|
-
## Configuration
|
|
687
|
-
|
|
688
|
-
| Option | Description |
|
|
689
|
-
| --- | --- |
|
|
690
|
-
| `data` | Dynamic intervals with `start`, `end`, `status`, and optional `label`/`metadata` |
|
|
691
|
-
| `statuses` | Text and optional color for each status value |
|
|
692
|
-
| `showLegend`, `showTooltip` | Toggle supporting UI (both default to `true`) |
|
|
693
|
-
| `legendPosition` | Places the legend at `top`, `bottom`, `left`, or `right` |
|
|
694
|
-
| `legendLayout` | Arranges legend items `horizontal` or `vertical` |
|
|
695
|
-
| `legendAlign` | Aligns the legend at `start`/`left`, `center`, `end`/`right`, or `space-between` |
|
|
696
|
-
| `legendLabelAlign` | Aligns text within vertical legend items to `left`, `center`, or `right` |
|
|
697
|
-
| `legendInteractive` | Enables clicking legend labels to dim/restore matching intervals; defaults to `true` |
|
|
698
|
-
| `legendDimmedOpacity` | Opacity used for inactive legend items and intervals; defaults to `0.3` |
|
|
699
|
-
| `legendScrollable` | Enables bounded legend overflow scrolling; defaults to `true` |
|
|
700
|
-
| `legendMaxWidth`, `legendMaxHeight` | Optional scroll viewport limits |
|
|
701
|
-
| `legendNote` | Optional explanatory text displayed beside the legend |
|
|
702
|
-
| `startLabel`, `endLabel` | Endpoint text; dates are derived when omitted |
|
|
703
|
-
| `showEndpointLabels` | Shows or hides the endpoint-label row; defaults to `true` |
|
|
704
|
-
| `endpointLabelsAlign` | Aligns endpoint labels at `start`/`left`, `center`, `end`/`right`, or `space-between` |
|
|
705
|
-
| `loading`, `loadingLabel`, `emptyLabel`, `error` | Timeline state presentation |
|
|
706
|
-
| `minSegmentWidth`, `segmentGap` | Dense-data and spacing controls in pixels |
|
|
707
|
-
| `dateFormatter`, `durationFormatter`, `tooltipFormatter` | Display customization hooks |
|
|
708
|
-
| `unknownStatus` | Fallback label/color for unconfigured status values |
|
|
709
|
-
| `ariaLabel` | Accessible name for the timeline |
|
|
710
|
-
|
|
711
|
-
The component emits `chartEvent` with `{ type: 'itemClick', item, index }`. Its appearance can be
|
|
712
|
-
themed with the `--status-timeline-*` CSS custom properties defined in the component stylesheet.
|
|
1
|
+
# CATS4U Charts
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+
|
|
8
|
+
**CATS4U Charts** is a reusable Angular chart library built on **Apache ECharts** and **ngx-echarts**.
|
|
9
|
+
It provides easy-to-use components for rendering interactive charts such as **Bar, Line, Area, Pie, Doughnut, Sankey, Timeline**, and more.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# ✨ Features
|
|
14
|
+
|
|
15
|
+
- 📊 Multiple chart types
|
|
16
|
+
- ⚡ Powered by Apache ECharts
|
|
17
|
+
- 🔌 Angular Standalone Components
|
|
18
|
+
- 🎨 Built-in theme support
|
|
19
|
+
- 🖱 Click & drill-down events
|
|
20
|
+
- 🧩 Easy integration
|
|
21
|
+
- 📦 Lightweight and reusable
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# 📦 Installation
|
|
26
|
+
|
|
27
|
+
Install the package along with required dependencies:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm install cats-charts
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
# 🚀 Usage
|
|
35
|
+
|
|
36
|
+
## Import Library
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
import { ChartsLib } from 'cats-charts';
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## TS Syntax
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import {
|
|
46
|
+
BarChart,
|
|
47
|
+
CustomChartComponent,
|
|
48
|
+
DoughnutChart,
|
|
49
|
+
LinesChart,
|
|
50
|
+
PieChart,
|
|
51
|
+
SankeyChart
|
|
52
|
+
} from 'cats-charts';
|
|
53
|
+
|
|
54
|
+
@Component({
|
|
55
|
+
...,
|
|
56
|
+
imports: [
|
|
57
|
+
BarChart,
|
|
58
|
+
CustomChartComponent,
|
|
59
|
+
DoughnutChart,
|
|
60
|
+
LinesChart,
|
|
61
|
+
PieChart,
|
|
62
|
+
SankeyChart
|
|
63
|
+
],
|
|
64
|
+
})
|
|
65
|
+
export class App {}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# ⚙️ Inputs
|
|
71
|
+
|
|
72
|
+
| Input | Type | Description |
|
|
73
|
+
| ------------------ | ------------------------------------------------- | -------------------------------------------------------------- |
|
|
74
|
+
| config | | Configuration options to customize chart and pass dynamic data |
|
|
75
|
+
| theme | string | default \| dark \| vintage \| essos \| chalk \| roma |
|
|
76
|
+
| contextMenuOptions | { label: string; value: string; icon?: string }[] | Context menu options |
|
|
77
|
+
| events | string[] | ['click', 'contextmenu', 'dblclick'] |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
# 📤 Outputs
|
|
82
|
+
|
|
83
|
+
| Output | Description |
|
|
84
|
+
| ---------------- | ---------------------- |
|
|
85
|
+
| contextMenuClick | ( event: any ) => void |
|
|
86
|
+
| chartEvent | ( event: any ) => void |
|
|
87
|
+
|
|
88
|
+
## Bar chart config
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
BarChartConfig {
|
|
92
|
+
series: {
|
|
93
|
+
name: string;
|
|
94
|
+
data: number[];
|
|
95
|
+
[key: string]: any;
|
|
96
|
+
}[];
|
|
97
|
+
xAxisData: string[];
|
|
98
|
+
colors?: string[];
|
|
99
|
+
backgroundColor?: string;
|
|
100
|
+
|
|
101
|
+
// --------------- Title configs ---------------
|
|
102
|
+
title?: string;
|
|
103
|
+
titlePosition?: string;
|
|
104
|
+
showTitle?: boolean;
|
|
105
|
+
|
|
106
|
+
// --------------- Tooltip configs ---------------
|
|
107
|
+
showTooltip?: boolean;
|
|
108
|
+
tooltipFormatter?: (params: any) => void;
|
|
109
|
+
|
|
110
|
+
// --------------- Grid configs ---------------
|
|
111
|
+
gridLeft?: string | number;
|
|
112
|
+
gridRight?: string | number;
|
|
113
|
+
gridBottom?: string | number;
|
|
114
|
+
gridTop?: string | number;
|
|
115
|
+
|
|
116
|
+
// --------------- Zoom Slider configs ---------------
|
|
117
|
+
showZoomSlider?: boolean;
|
|
118
|
+
zoomStart?: number;
|
|
119
|
+
zoomEnd?: number;
|
|
120
|
+
zoomControlButtonStyle?: any;
|
|
121
|
+
|
|
122
|
+
yAxis?: any;
|
|
123
|
+
xAxis?: any;
|
|
124
|
+
stacked?: boolean;
|
|
125
|
+
|
|
126
|
+
barWidth?: string | number;
|
|
127
|
+
|
|
128
|
+
borderRadius?: number;
|
|
129
|
+
showLabel?: boolean;
|
|
130
|
+
labelPosition?: string;
|
|
131
|
+
showXAxisLine?: boolean;
|
|
132
|
+
showYAxisLine?: boolean;
|
|
133
|
+
// Legend
|
|
134
|
+
hideLegend?: boolean;
|
|
135
|
+
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
136
|
+
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
137
|
+
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
138
|
+
legendTextColor?: string;
|
|
139
|
+
legendFontSize?: number;
|
|
140
|
+
legendContainerWidth?: number; // 0-1
|
|
141
|
+
legendIndicatorHeight?: number; // number value is in px
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Line and Area Chart config
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
LineChartConfig {
|
|
149
|
+
isTrendChart?: boolean;
|
|
150
|
+
title?: string;
|
|
151
|
+
showTitle?: boolean;
|
|
152
|
+
titlePosition?: string;
|
|
153
|
+
xAxisData: string[];
|
|
154
|
+
tooltipFormatter?: (params: any) => void;
|
|
155
|
+
colors?: string[];
|
|
156
|
+
series: {
|
|
157
|
+
name: string;
|
|
158
|
+
data: number[];
|
|
159
|
+
areaColor?: string;
|
|
160
|
+
smooth?: boolean;
|
|
161
|
+
area?: boolean;
|
|
162
|
+
[key: string]: any;
|
|
163
|
+
}[];
|
|
164
|
+
// --------------- Grid configs ---------------
|
|
165
|
+
gridLeft?: string | number;
|
|
166
|
+
gridRight?: string | number;
|
|
167
|
+
gridBottom?: string | number;
|
|
168
|
+
gridTop?: string | number;
|
|
169
|
+
|
|
170
|
+
borderRadius?: number;
|
|
171
|
+
showLabel?: boolean;
|
|
172
|
+
labelPosition?: string;
|
|
173
|
+
|
|
174
|
+
yAxis?: any;
|
|
175
|
+
xAxis?: any;
|
|
176
|
+
showXAxisLine?: boolean;
|
|
177
|
+
showYAxisLine?: boolean;
|
|
178
|
+
showTooltip?: boolean;
|
|
179
|
+
|
|
180
|
+
backgroundColor?: string;
|
|
181
|
+
|
|
182
|
+
// Legend
|
|
183
|
+
hideLegend?: boolean;
|
|
184
|
+
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
185
|
+
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
186
|
+
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
187
|
+
legendTextColor?: string;
|
|
188
|
+
legendFontSize?: number;
|
|
189
|
+
legendContainerWidth?: number; // 0-1
|
|
190
|
+
legendIndicatorHeight?: number; // number value is in px
|
|
191
|
+
|
|
192
|
+
customLegend?: ChartLegendConfig<LineChartConfig['series'][number]>;
|
|
193
|
+
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### CustomLegend
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
type customLegend = {
|
|
201
|
+
enabled?: boolean;
|
|
202
|
+
|
|
203
|
+
// layout/positioning
|
|
204
|
+
layout?: 'horizontal' | 'vertical';
|
|
205
|
+
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
206
|
+
align?: 'start' | 'center' | 'end';
|
|
207
|
+
|
|
208
|
+
// selection behavior
|
|
209
|
+
selectionMode?: 'multiple' | 'single' | 'exclusive';
|
|
210
|
+
|
|
211
|
+
// scrolling / pagination
|
|
212
|
+
scrollable?: boolean;
|
|
213
|
+
maxHeight?: string;
|
|
214
|
+
maxWidth?: string;
|
|
215
|
+
pageSize?: number;
|
|
216
|
+
showPagination?: boolean;
|
|
217
|
+
|
|
218
|
+
// disabling items
|
|
219
|
+
disabled?: boolean;
|
|
220
|
+
disabledNames?: string[];
|
|
221
|
+
|
|
222
|
+
// accessibility / styling
|
|
223
|
+
className?: string;
|
|
224
|
+
ariaLabel?: string;
|
|
225
|
+
legendTextColor?: string;
|
|
226
|
+
legendFontSize?: number;
|
|
227
|
+
|
|
228
|
+
// icon rendering
|
|
229
|
+
icon?: ChartLegendIcon | ((series: TSeries, index: number) => ChartLegendIcon);
|
|
230
|
+
|
|
231
|
+
icons?: Record<string, ChartLegendIcon>;
|
|
232
|
+
|
|
233
|
+
// label formatting
|
|
234
|
+
formatter?: (name: string, item: ChartLegendItem) => string;
|
|
235
|
+
tooltipFormatter?: (item: ChartLegendItem) => string;
|
|
236
|
+
|
|
237
|
+
// grouping
|
|
238
|
+
groupBy?: (item: ChartLegendItem) => string | undefined;
|
|
239
|
+
|
|
240
|
+
// custom Angular template
|
|
241
|
+
itemTemplate?: TemplateRef<ChartLegendTemplateContext>;
|
|
242
|
+
|
|
243
|
+
// virtualization (advanced)
|
|
244
|
+
virtualize?: boolean;
|
|
245
|
+
virtualItemHeight?: number;
|
|
246
|
+
|
|
247
|
+
// hover behavior linking
|
|
248
|
+
hoverLink?: boolean;
|
|
249
|
+
};
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### CustomLegend Example
|
|
253
|
+
|
|
254
|
+
```ts
|
|
255
|
+
customLegend?: {
|
|
256
|
+
// enable/disable legend UI
|
|
257
|
+
enabled?: boolean;
|
|
258
|
+
|
|
259
|
+
// layout
|
|
260
|
+
layout?: 'horizontal' | 'vertical';
|
|
261
|
+
position?: 'top' | 'bottom' | 'left' | 'right';
|
|
262
|
+
align?: 'start' | 'center' | 'end';
|
|
263
|
+
|
|
264
|
+
// selection behavior
|
|
265
|
+
selectionMode?: 'multiple' | 'single' | 'exclusive';
|
|
266
|
+
|
|
267
|
+
// scrolling/pagination
|
|
268
|
+
scrollable?: boolean;
|
|
269
|
+
maxHeight?: string;
|
|
270
|
+
maxWidth?: string;
|
|
271
|
+
pageSize?: number;
|
|
272
|
+
showPagination?: boolean;
|
|
273
|
+
|
|
274
|
+
// disabling items
|
|
275
|
+
disabled?: boolean;
|
|
276
|
+
disabledNames?: string[];
|
|
277
|
+
|
|
278
|
+
// styling & accessibility
|
|
279
|
+
className?: string;
|
|
280
|
+
ariaLabel?: string;
|
|
281
|
+
legendTextColor?: string;
|
|
282
|
+
legendFontSize?: number;
|
|
283
|
+
|
|
284
|
+
// icon configuration
|
|
285
|
+
// - either a static icon
|
|
286
|
+
// - or a function that returns an icon per series/index
|
|
287
|
+
icon?:
|
|
288
|
+
| ChartLegendIcon
|
|
289
|
+
| ((series: TSeries, index: number) => ChartLegendIcon);
|
|
290
|
+
|
|
291
|
+
// mapping of icon names -> icon types
|
|
292
|
+
icons?: Record<string, ChartLegendIcon>;
|
|
293
|
+
|
|
294
|
+
// text formatting
|
|
295
|
+
formatter?: (name: string, item: ChartLegendItem) => string;
|
|
296
|
+
|
|
297
|
+
// tooltip formatting
|
|
298
|
+
tooltipFormatter?: (item: ChartLegendItem) => string;
|
|
299
|
+
|
|
300
|
+
// grouping
|
|
301
|
+
groupBy?: (item: ChartLegendItem) => string | undefined;
|
|
302
|
+
|
|
303
|
+
// custom Angular template (advanced)
|
|
304
|
+
itemTemplate?: TemplateRef<ChartLegendTemplateContext>;
|
|
305
|
+
|
|
306
|
+
// virtualization (advanced)
|
|
307
|
+
virtualize?: boolean;
|
|
308
|
+
virtualItemHeight?: number;
|
|
309
|
+
|
|
310
|
+
// hover linking (advanced)
|
|
311
|
+
hoverLink?: boolean;
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Pie and Donut chart config
|
|
317
|
+
|
|
318
|
+
```ts
|
|
319
|
+
DoughnutChartConfig {
|
|
320
|
+
title?: string;
|
|
321
|
+
showTitle?: boolean;
|
|
322
|
+
titlePosition?: 'left' | 'center' | 'right';
|
|
323
|
+
top?: any;
|
|
324
|
+
bottom?: any;
|
|
325
|
+
backgroundColor?: string;
|
|
326
|
+
series?: any;
|
|
327
|
+
data: {
|
|
328
|
+
name: string;
|
|
329
|
+
value: number;
|
|
330
|
+
[key: string]: any;
|
|
331
|
+
}[];
|
|
332
|
+
|
|
333
|
+
colors?: string[];
|
|
334
|
+
|
|
335
|
+
// Doughnut
|
|
336
|
+
innerRadius?: string;
|
|
337
|
+
outerRadius?: string;
|
|
338
|
+
center?: string[];
|
|
339
|
+
// Center Text
|
|
340
|
+
showCenterText?: boolean;
|
|
341
|
+
centerLabel?: any;
|
|
342
|
+
centerValue?: string;
|
|
343
|
+
centerValueFromTotal?: boolean;
|
|
344
|
+
|
|
345
|
+
// Tooltip
|
|
346
|
+
showTooltip?: boolean;
|
|
347
|
+
showTooltipPercent?: boolean;
|
|
348
|
+
tooltipFormatter?: (params: any, config: DoughnutChartConfig) => void;
|
|
349
|
+
valueFormatter?: (value: number) => string;
|
|
350
|
+
|
|
351
|
+
// Legend
|
|
352
|
+
hideLegend?: boolean;
|
|
353
|
+
legendBottom?: number;
|
|
354
|
+
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
355
|
+
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
356
|
+
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
357
|
+
legendTextColor?: string;
|
|
358
|
+
legendFontSize?: number;
|
|
359
|
+
legendContainerWidth?: number; // 0-1
|
|
360
|
+
// Labels
|
|
361
|
+
showLabel?: boolean;
|
|
362
|
+
labelPosition?: 'inside' | 'outside' | 'center';
|
|
363
|
+
showLabelValue?: boolean;
|
|
364
|
+
showLabelPercentage?: boolean;
|
|
365
|
+
|
|
366
|
+
// Emphasis
|
|
367
|
+
emphasisScale?: boolean;
|
|
368
|
+
|
|
369
|
+
// Style
|
|
370
|
+
borderRadius?: number;
|
|
371
|
+
borderColor?: string;
|
|
372
|
+
borderWidth?: number;
|
|
373
|
+
|
|
374
|
+
enableHoverEffect?: boolean;
|
|
375
|
+
}
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
## Custom chart config
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
CustomChartConfig {
|
|
382
|
+
startHour?: string;
|
|
383
|
+
endHour?: string;
|
|
384
|
+
|
|
385
|
+
shiftColor?: string;
|
|
386
|
+
chartMode: 'weekly' | 'daily' | string;
|
|
387
|
+
|
|
388
|
+
yAxisData: string[];
|
|
389
|
+
categories: string[];
|
|
390
|
+
legends: TimeLineLegends;
|
|
391
|
+
|
|
392
|
+
barHeight?: number;
|
|
393
|
+
shiftHeight?: number;
|
|
394
|
+
|
|
395
|
+
data: TimelineData[];
|
|
396
|
+
hideLegendCategory?: boolean;
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
## Scatter Chart config
|
|
401
|
+
|
|
402
|
+
```ts
|
|
403
|
+
ScatterChartConfig {
|
|
404
|
+
title?: string;
|
|
405
|
+
showTitle?: boolean;
|
|
406
|
+
titlePosition?: string;
|
|
407
|
+
tooltipFormatter?: (params: any) => void;
|
|
408
|
+
colors?: string[];
|
|
409
|
+
series: {
|
|
410
|
+
name: string;
|
|
411
|
+
data: number[];
|
|
412
|
+
[key: string]: any;
|
|
413
|
+
}[];
|
|
414
|
+
// --------------- Grid configs ---------------
|
|
415
|
+
gridLeft?: string | number;
|
|
416
|
+
gridRight?: string | number;
|
|
417
|
+
gridBottom?: string | number;
|
|
418
|
+
gridTop?: string | number;
|
|
419
|
+
|
|
420
|
+
labelPosition?: string;
|
|
421
|
+
|
|
422
|
+
yAxis?: any;
|
|
423
|
+
xAxis?: any;
|
|
424
|
+
showXAxisLine?: boolean;
|
|
425
|
+
showYAxisLine?: boolean;
|
|
426
|
+
showTooltip?: boolean;
|
|
427
|
+
|
|
428
|
+
backgroundColor?: string;
|
|
429
|
+
|
|
430
|
+
// Legend
|
|
431
|
+
hideLegend?: boolean;
|
|
432
|
+
legendPosition?: 'top' | 'bottom' | 'left' | 'right' | string;
|
|
433
|
+
legendAlign?: 'left' | 'center' | 'right' | string;
|
|
434
|
+
legendDirection?: 'horizontal' | 'vertical' | string;
|
|
435
|
+
legendTextColor?: string;
|
|
436
|
+
legendFontSize?: number;
|
|
437
|
+
legendContainerWidth?: number; // 0-1
|
|
438
|
+
legendIndicatorHeight?: number; // number value is in px
|
|
439
|
+
xAxisName?: string;
|
|
440
|
+
yAxisName?: string;
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
## Sankey Chart config
|
|
445
|
+
|
|
446
|
+
```ts
|
|
447
|
+
SankeyChartConfig {
|
|
448
|
+
title?: string;
|
|
449
|
+
showTitle?: boolean;
|
|
450
|
+
backgroundColor?: string;
|
|
451
|
+
colors?: string[];
|
|
452
|
+
showTooltip?: boolean;
|
|
453
|
+
tooltipFormatter?: (params: any) => string;
|
|
454
|
+
nodes: SankeyNode[];
|
|
455
|
+
links: SankeyLink[];
|
|
456
|
+
seriesOption?: SankeySeriesOption;
|
|
457
|
+
lineCurveness?: number;
|
|
458
|
+
}
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
### For `SankeySeriesOption` refer echarts Sankey series documentation
|
|
462
|
+
|
|
463
|
+
https://echarts.apache.org/en/option.html#series-sankey
|
|
464
|
+
|
|
465
|
+
# 📊 Supported Charts
|
|
466
|
+
|
|
467
|
+
- Bar Chart
|
|
468
|
+
- Line Chart
|
|
469
|
+
- Area Chart
|
|
470
|
+
- Pie Chart
|
|
471
|
+
- Doughnut Chart
|
|
472
|
+
- Stacked Area Chart
|
|
473
|
+
- Sankey Chart
|
|
474
|
+
- Heatmap Chart
|
|
475
|
+
- Custom Charts
|
|
476
|
+
|
|
477
|
+
* Bar Chart
|
|
478
|
+
* Line Chart
|
|
479
|
+
* Area Chart
|
|
480
|
+
* Pie Chart
|
|
481
|
+
* Doughnut Chart
|
|
482
|
+
* Stacked Area Chart
|
|
483
|
+
* Sankey Chart
|
|
484
|
+
* Custom Charts
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
# Heatmap Chart
|
|
489
|
+
|
|
490
|
+
The heatmap component renders category-based intensity data using Apache ECharts.
|
|
491
|
+
Use `[xIndex, yIndex, value]` tuples, where `xIndex` points to `xAxisData` and `yIndex` points to `yAxisData`.
|
|
492
|
+
|
|
493
|
+
## Import
|
|
494
|
+
|
|
495
|
+
```ts
|
|
496
|
+
import { Heatmap } from 'cats-charts';
|
|
497
|
+
|
|
498
|
+
@Component({
|
|
499
|
+
selector: 'app-root',
|
|
500
|
+
standalone: true,
|
|
501
|
+
imports: [Heatmap],
|
|
502
|
+
templateUrl: './app.html',
|
|
503
|
+
})
|
|
504
|
+
export class App {}
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
## HTML
|
|
508
|
+
|
|
509
|
+
```html
|
|
510
|
+
<div style="width: 100%; height: 340px">
|
|
511
|
+
<lib-heatmap
|
|
512
|
+
[config]="heatmapConfig"
|
|
513
|
+
[theme]="selectedTheme"
|
|
514
|
+
[events]="['click', 'contextmenu']"
|
|
515
|
+
(chartEvent)="handleChartEvent($event)"
|
|
516
|
+
></lib-heatmap>
|
|
517
|
+
</div>
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
## TypeScript
|
|
521
|
+
|
|
522
|
+
```ts
|
|
523
|
+
heatmapConfig = {
|
|
524
|
+
xAxisData: ['00:00', '01:00', '02:00', '03:00', '04:00', '05:00'],
|
|
525
|
+
yAxisData: ['eth0', 'eth1', 'wlan0', 'vlan10', 'vlan20'],
|
|
526
|
+
|
|
527
|
+
data: [
|
|
528
|
+
[0, 0, 20],
|
|
529
|
+
[1, 0, 60],
|
|
530
|
+
[2, 0, 0],
|
|
531
|
+
[3, 0, 40],
|
|
532
|
+
[4, 0, 80],
|
|
533
|
+
[5, 0, 100],
|
|
534
|
+
|
|
535
|
+
[0, 1, 40],
|
|
536
|
+
[1, 1, 0],
|
|
537
|
+
[2, 1, 20],
|
|
538
|
+
[3, 1, 60],
|
|
539
|
+
[4, 1, 100],
|
|
540
|
+
[5, 1, 80],
|
|
541
|
+
] as [number, number, number][],
|
|
542
|
+
|
|
543
|
+
min: 0,
|
|
544
|
+
max: 100,
|
|
545
|
+
showTooltip: true,
|
|
546
|
+
|
|
547
|
+
grid: {
|
|
548
|
+
left: 58,
|
|
549
|
+
right: 18,
|
|
550
|
+
top: 20,
|
|
551
|
+
bottom: 46,
|
|
552
|
+
containLabel: false,
|
|
553
|
+
},
|
|
554
|
+
|
|
555
|
+
xAxis: {
|
|
556
|
+
axisLabel: { color: '#6b7280' },
|
|
557
|
+
axisLine: { lineStyle: { color: '#9ca3af' } },
|
|
558
|
+
axisTick: { show: true },
|
|
559
|
+
},
|
|
560
|
+
|
|
561
|
+
yAxis: {
|
|
562
|
+
inverse: true,
|
|
563
|
+
axisLabel: { color: '#6b7280' },
|
|
564
|
+
axisLine: { show: false },
|
|
565
|
+
axisTick: { show: true },
|
|
566
|
+
},
|
|
567
|
+
|
|
568
|
+
visualMap: {
|
|
569
|
+
type: 'piecewise',
|
|
570
|
+
pieces: [
|
|
571
|
+
{ min: 0, max: 20, label: '20%', color: '#fde6bd' },
|
|
572
|
+
{ min: 21, max: 40, label: '40%', color: '#ffd85a' },
|
|
573
|
+
{ min: 41, max: 60, label: '60%', color: '#ffb247' },
|
|
574
|
+
{ min: 61, max: 80, label: '80%', color: '#ff0b1f' },
|
|
575
|
+
{ min: 81, max: 100, label: '100%', color: '#a51d29' },
|
|
576
|
+
],
|
|
577
|
+
},
|
|
578
|
+
|
|
579
|
+
series: {
|
|
580
|
+
itemStyle: {
|
|
581
|
+
borderWidth: 0,
|
|
582
|
+
},
|
|
583
|
+
},
|
|
584
|
+
};
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
## Heatmap Config Options
|
|
588
|
+
|
|
589
|
+
| Option | Type | Description |
|
|
590
|
+
| ---------------- | -------------------------- | ----------------------------------------------------------------------- |
|
|
591
|
+
| xAxisData | string[] | Labels for the x-axis |
|
|
592
|
+
| yAxisData | string[] | Labels for the y-axis |
|
|
593
|
+
| data | [number, number, number][] | Heatmap cells as `[xIndex, yIndex, value]` |
|
|
594
|
+
| min | number | Minimum value for color mapping |
|
|
595
|
+
| max | number | Maximum value for color mapping |
|
|
596
|
+
| colors | string[] | Continuous color range when `visualMap.pieces` is not used |
|
|
597
|
+
| visualMap | any | ECharts visual map config. `pieces` also drives the custom legend pills |
|
|
598
|
+
| grid | object | ECharts grid config |
|
|
599
|
+
| xAxis | any | Extra ECharts x-axis config |
|
|
600
|
+
| yAxis | any | Extra ECharts y-axis config |
|
|
601
|
+
| showTooltip | boolean | Enables or disables tooltip |
|
|
602
|
+
| tooltipFormatter | function | Custom tooltip formatter |
|
|
603
|
+
| showLabel | boolean | Shows value labels inside cells |
|
|
604
|
+
| labelFormatter | string \| function | Cell label formatter |
|
|
605
|
+
| series | any \| any[] | Extra ECharts heatmap series config |
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
# 🎨 Themes
|
|
610
|
+
|
|
611
|
+
Available chart themes:
|
|
612
|
+
|
|
613
|
+
- default
|
|
614
|
+
- dark
|
|
615
|
+
- vintage
|
|
616
|
+
- essos
|
|
617
|
+
- chalk
|
|
618
|
+
- roma
|
|
619
|
+
|
|
620
|
+
---
|
|
621
|
+
|
|
622
|
+
# 📚 Documentation
|
|
623
|
+
|
|
624
|
+
Apache ECharts documentation:
|
|
625
|
+
|
|
626
|
+
https://echarts.apache.org/en/api.html#echarts
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
# 🤝 Contributing
|
|
631
|
+
|
|
632
|
+
Contributions, issues, and feature requests are welcome.
|
|
633
|
+
Feel free to submit a pull request.
|
|
634
|
+
|
|
635
|
+
---
|
|
636
|
+
|
|
637
|
+
# 📄 License
|
|
638
|
+
|
|
639
|
+
MIT License
|
|
640
|
+
|
|
641
|
+
---
|
|
642
|
+
|
|
643
|
+
# Status Timeline
|
|
644
|
+
|
|
645
|
+
`StatusTimelineComponent` renders generic categorical intervals in chronological order. Segment
|
|
646
|
+
widths are proportional to duration, and dense datasets scroll horizontally without aggregation.
|
|
647
|
+
|
|
648
|
+
## Import and usage
|
|
649
|
+
|
|
650
|
+
```ts
|
|
651
|
+
import { StatusTimelineComponent, type StatusTimelineConfig } from 'cats-charts';
|
|
652
|
+
|
|
653
|
+
@Component({
|
|
654
|
+
standalone: true,
|
|
655
|
+
imports: [StatusTimelineComponent],
|
|
656
|
+
template: `
|
|
657
|
+
<lib-status-timeline
|
|
658
|
+
[config]="timelineConfig"
|
|
659
|
+
(chartEvent)="onTimelineEvent($event)"
|
|
660
|
+
/>
|
|
661
|
+
`,
|
|
662
|
+
})
|
|
663
|
+
export class ExampleComponent {
|
|
664
|
+
timelineConfig: StatusTimelineConfig = {
|
|
665
|
+
startLabel: 'Monday',
|
|
666
|
+
endLabel: 'Today',
|
|
667
|
+
statuses: [
|
|
668
|
+
{ value: 'ready', label: 'Ready', color: '#2f8f3a' },
|
|
669
|
+
{ value: 'deploying', label: 'Deploying', color: '#d0a020' },
|
|
670
|
+
{ value: 'blocked', label: 'Blocked', color: '#a43b35' },
|
|
671
|
+
],
|
|
672
|
+
data: [
|
|
673
|
+
{ start: '2026-08-24T00:00:00Z', end: '2026-08-25T00:00:00Z', status: 'ready' },
|
|
674
|
+
{
|
|
675
|
+
start: '2026-08-25T00:00:00Z',
|
|
676
|
+
end: '2026-08-25T06:00:00Z',
|
|
677
|
+
status: 'deploying',
|
|
678
|
+
label: 'Release deployment',
|
|
679
|
+
},
|
|
680
|
+
{ start: '2026-08-25T06:00:00Z', end: '2026-08-26T00:00:00Z', status: 'ready' },
|
|
681
|
+
],
|
|
682
|
+
};
|
|
683
|
+
}
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
## Configuration
|
|
687
|
+
|
|
688
|
+
| Option | Description |
|
|
689
|
+
| --- | --- |
|
|
690
|
+
| `data` | Dynamic intervals with `start`, `end`, `status`, and optional `label`/`metadata` |
|
|
691
|
+
| `statuses` | Text and optional color for each status value |
|
|
692
|
+
| `showLegend`, `showTooltip` | Toggle supporting UI (both default to `true`) |
|
|
693
|
+
| `legendPosition` | Places the legend at `top`, `bottom`, `left`, or `right` |
|
|
694
|
+
| `legendLayout` | Arranges legend items `horizontal` or `vertical` |
|
|
695
|
+
| `legendAlign` | Aligns the legend at `start`/`left`, `center`, `end`/`right`, or `space-between` |
|
|
696
|
+
| `legendLabelAlign` | Aligns text within vertical legend items to `left`, `center`, or `right` |
|
|
697
|
+
| `legendInteractive` | Enables clicking legend labels to dim/restore matching intervals; defaults to `true` |
|
|
698
|
+
| `legendDimmedOpacity` | Opacity used for inactive legend items and intervals; defaults to `0.3` |
|
|
699
|
+
| `legendScrollable` | Enables bounded legend overflow scrolling; defaults to `true` |
|
|
700
|
+
| `legendMaxWidth`, `legendMaxHeight` | Optional scroll viewport limits |
|
|
701
|
+
| `legendNote` | Optional explanatory text displayed beside the legend |
|
|
702
|
+
| `startLabel`, `endLabel` | Endpoint text; dates are derived when omitted |
|
|
703
|
+
| `showEndpointLabels` | Shows or hides the endpoint-label row; defaults to `true` |
|
|
704
|
+
| `endpointLabelsAlign` | Aligns endpoint labels at `start`/`left`, `center`, `end`/`right`, or `space-between` |
|
|
705
|
+
| `loading`, `loadingLabel`, `emptyLabel`, `error` | Timeline state presentation |
|
|
706
|
+
| `minSegmentWidth`, `segmentGap` | Dense-data and spacing controls in pixels |
|
|
707
|
+
| `dateFormatter`, `durationFormatter`, `tooltipFormatter` | Display customization hooks |
|
|
708
|
+
| `unknownStatus` | Fallback label/color for unconfigured status values |
|
|
709
|
+
| `ariaLabel` | Accessible name for the timeline |
|
|
710
|
+
|
|
711
|
+
The component emits `chartEvent` with `{ type: 'itemClick', item, index }`. Its appearance can be
|
|
712
|
+
themed with the `--status-timeline-*` CSS custom properties defined in the component stylesheet.
|