cats-charts 0.0.6 → 0.0.8
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 +36 -40
- package/fesm2022/cats-charts.mjs +263 -1
- package/fesm2022/cats-charts.mjs.map +1 -1
- package/index.d.ts +9 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,63 +1,59 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CATS4U Charts
|
|
2
2
|
|
|
3
|
-
This
|
|
3
|
+
This library was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.0 and it also usages [Apache Echarts](https://www.npmjs.com/package/echarts) for charts.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Install
|
|
6
6
|
|
|
7
|
-
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
ng generate component component-name
|
|
11
7
|
```
|
|
12
|
-
|
|
13
|
-
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
ng generate --help
|
|
8
|
+
npm install cats-charts
|
|
17
9
|
```
|
|
18
10
|
|
|
19
|
-
##
|
|
11
|
+
## Usages
|
|
20
12
|
|
|
21
|
-
|
|
13
|
+
### TS file
|
|
22
14
|
|
|
23
|
-
```
|
|
24
|
-
|
|
15
|
+
```
|
|
16
|
+
import { ChartsLib } from 'cats-charts';
|
|
25
17
|
```
|
|
26
18
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
### Publishing the Library
|
|
19
|
+
### HTML template
|
|
30
20
|
|
|
31
|
-
|
|
21
|
+
```
|
|
22
|
+
<lib-charts-lib></lib-charts-lib>
|
|
23
|
+
```
|
|
32
24
|
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
cd dist/charts-lib
|
|
36
|
-
```
|
|
25
|
+
### Inputs
|
|
37
26
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
27
|
+
```
|
|
28
|
+
chartOptionsConfig: {} // accepts all options accepted by echarts
|
|
29
|
+
chartType: 'bar' | 'area' | 'line' | 'pie' // by default chart type is bar
|
|
30
|
+
columns: [] // list of columns
|
|
31
|
+
contextMenuList: [] // list of context menu
|
|
32
|
+
data: [] // list of set of data
|
|
33
|
+
themeName: "default" | "dark" | "vintage" | "essos" | "chalk" | "roma" // default theme is default
|
|
42
34
|
|
|
43
|
-
|
|
35
|
+
```
|
|
44
36
|
|
|
45
|
-
|
|
37
|
+
### Outputs
|
|
46
38
|
|
|
47
|
-
```
|
|
48
|
-
|
|
39
|
+
```
|
|
40
|
+
handleSingleClick: (params) => {}
|
|
41
|
+
handleDrillBy: (params) => {}
|
|
49
42
|
```
|
|
50
43
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
For end-to-end (e2e) testing, run:
|
|
44
|
+
### Inputs Types
|
|
54
45
|
|
|
55
|
-
```bash
|
|
56
|
-
ng e2e
|
|
57
46
|
```
|
|
58
|
-
|
|
59
|
-
|
|
47
|
+
import type { ChartsLibType, OptionsConfig } from 'cats-charts';
|
|
48
|
+
|
|
49
|
+
chartOptionsConfig: OptionsConfig
|
|
50
|
+
chartType: ChartsLibType['chartType']
|
|
51
|
+
columns: string[]
|
|
52
|
+
data: any[][]
|
|
53
|
+
themeName: ChartsLibType['themeName']
|
|
54
|
+
contextMenuList: ContextMenuListItem[]
|
|
55
|
+
```
|
|
60
56
|
|
|
61
57
|
## Additional Resources
|
|
62
58
|
|
|
63
|
-
For more information on
|
|
59
|
+
For more information on Echarts, including detailed references, visit the [Official Apache Echarts](https://echarts.apache.org/en/api.html#echarts) page.
|
package/fesm2022/cats-charts.mjs
CHANGED
|
@@ -66,6 +66,22 @@ class ContextMenuListItem {
|
|
|
66
66
|
action;
|
|
67
67
|
disabled = false;
|
|
68
68
|
}
|
|
69
|
+
class PieChartOptionsConfig {
|
|
70
|
+
title = {
|
|
71
|
+
show: true,
|
|
72
|
+
text: '',
|
|
73
|
+
left: 'center',
|
|
74
|
+
textStyle: { fontSize: 16 },
|
|
75
|
+
};
|
|
76
|
+
legend = { show: true };
|
|
77
|
+
tooltip = { trigger: 'item' };
|
|
78
|
+
series = [];
|
|
79
|
+
grid = {
|
|
80
|
+
left: '5%',
|
|
81
|
+
right: '5%',
|
|
82
|
+
containLabel: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
69
85
|
|
|
70
86
|
class ChartService {
|
|
71
87
|
themeSignal = signal('default', ...(ngDevMode ? [{ debugName: "themeSignal" }] : []));
|
|
@@ -3338,6 +3354,250 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
3338
3354
|
args: ['areaChartContainer', { static: false }]
|
|
3339
3355
|
}] } });
|
|
3340
3356
|
|
|
3357
|
+
class PieChart {
|
|
3358
|
+
cdr;
|
|
3359
|
+
title = '';
|
|
3360
|
+
height = '600px';
|
|
3361
|
+
enableSampling = true; // Sample data if > threshold for perf
|
|
3362
|
+
sampleThreshold = 10000; // Sample if data > 10k (keep full for 50k if hardware allows)
|
|
3363
|
+
isLoading = true;
|
|
3364
|
+
defaultConfig = new PieChartOptionsConfig();
|
|
3365
|
+
optionsConfig = {};
|
|
3366
|
+
chartContainer;
|
|
3367
|
+
chartInstance = null;
|
|
3368
|
+
chartService = inject(ChartService);
|
|
3369
|
+
destroy$ = new Subject();
|
|
3370
|
+
currentData = [];
|
|
3371
|
+
currentColumns = [];
|
|
3372
|
+
boundHandleContextMenu;
|
|
3373
|
+
constructor(cdr) {
|
|
3374
|
+
this.cdr = cdr;
|
|
3375
|
+
this.boundHandleContextMenu = this.handleContextMenu.bind(this);
|
|
3376
|
+
// Effect for theme changes
|
|
3377
|
+
effect(() => {
|
|
3378
|
+
this.chartService.theme(); // Read signal
|
|
3379
|
+
if (this.chartInstance) {
|
|
3380
|
+
this.reinitializeChart();
|
|
3381
|
+
}
|
|
3382
|
+
});
|
|
3383
|
+
// Effect for data changes
|
|
3384
|
+
effect(() => {
|
|
3385
|
+
const data = this.chartService.data(); // Read signal
|
|
3386
|
+
const columns = this.chartService.columns();
|
|
3387
|
+
this.currentColumns = columns;
|
|
3388
|
+
this.currentData = data;
|
|
3389
|
+
this.processAndUpdateData();
|
|
3390
|
+
});
|
|
3391
|
+
// Effect for chartOptionsConfig changes
|
|
3392
|
+
effect(() => {
|
|
3393
|
+
this.chartService.chartOptionsConfig();
|
|
3394
|
+
this.optionsConfig = this.chartService.chartOptionsConfig();
|
|
3395
|
+
this.reinitializeChart();
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
ngOnInit() {
|
|
3399
|
+
if (this.currentData.length > 0) {
|
|
3400
|
+
this.processAndUpdateData();
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
ngAfterViewInit() {
|
|
3404
|
+
this.initializeChart();
|
|
3405
|
+
if (this.currentData.length > 0) {
|
|
3406
|
+
this.updateChartWithData();
|
|
3407
|
+
}
|
|
3408
|
+
this.isLoading = false;
|
|
3409
|
+
this.cdr.markForCheck();
|
|
3410
|
+
}
|
|
3411
|
+
ngOnDestroy() {
|
|
3412
|
+
this.destroy$.next();
|
|
3413
|
+
this.destroy$.complete();
|
|
3414
|
+
this.chartService.hideContextMenu();
|
|
3415
|
+
this.disposeChart();
|
|
3416
|
+
if (this.chartInstance) {
|
|
3417
|
+
this.chartInstance.dispose(); // Clean up to free memory
|
|
3418
|
+
}
|
|
3419
|
+
if (this.chartContainer) {
|
|
3420
|
+
this.chartContainer.nativeElement.removeEventListener('contextmenu', this.boundHandleContextMenu);
|
|
3421
|
+
}
|
|
3422
|
+
document.removeEventListener('click', () => {
|
|
3423
|
+
this.chartService.hideContextMenu();
|
|
3424
|
+
this.chartService.resetContextEvent();
|
|
3425
|
+
});
|
|
3426
|
+
}
|
|
3427
|
+
reinitializeChart() {
|
|
3428
|
+
this.initializeChart();
|
|
3429
|
+
if (this.currentData.length > 0) {
|
|
3430
|
+
this.updateChartWithData();
|
|
3431
|
+
}
|
|
3432
|
+
this.cdr.markForCheck();
|
|
3433
|
+
}
|
|
3434
|
+
initializeChart() {
|
|
3435
|
+
if (!this.chartContainer) {
|
|
3436
|
+
return;
|
|
3437
|
+
}
|
|
3438
|
+
const chartDom = this.chartContainer.nativeElement;
|
|
3439
|
+
chartDom.innerHTML = '';
|
|
3440
|
+
if (this.chartInstance) {
|
|
3441
|
+
this.chartInstance.dispose();
|
|
3442
|
+
this.chartInstance = null;
|
|
3443
|
+
}
|
|
3444
|
+
this.chartInstance = echarts.init(chartDom, this.chartService.theme()); // Init ECharts
|
|
3445
|
+
this.chartInstance.setOption({
|
|
3446
|
+
...this.defaultConfig,
|
|
3447
|
+
...this.optionsConfig,
|
|
3448
|
+
title: {
|
|
3449
|
+
...this.defaultConfig.title,
|
|
3450
|
+
...this.optionsConfig.title,
|
|
3451
|
+
textStyle: {
|
|
3452
|
+
...this.defaultConfig.title?.textStyle,
|
|
3453
|
+
...this.optionsConfig.title?.textStyle,
|
|
3454
|
+
},
|
|
3455
|
+
},
|
|
3456
|
+
tooltip: {
|
|
3457
|
+
...this.defaultConfig.tooltip,
|
|
3458
|
+
...this.optionsConfig.tooltip,
|
|
3459
|
+
},
|
|
3460
|
+
legend: { ...this.defaultConfig.legend, ...this.optionsConfig.legend },
|
|
3461
|
+
// No dataZoom for pie charts
|
|
3462
|
+
grid: {
|
|
3463
|
+
...this.defaultConfig.grid,
|
|
3464
|
+
...this.optionsConfig.grid,
|
|
3465
|
+
},
|
|
3466
|
+
// No xAxis or yAxis for pie charts
|
|
3467
|
+
series: [],
|
|
3468
|
+
});
|
|
3469
|
+
// Responsive: Resize on window change
|
|
3470
|
+
window.addEventListener('resize', () => this.chartInstance?.resize(), { passive: true });
|
|
3471
|
+
this.chartInstance.on('rendered', () => {
|
|
3472
|
+
// console.log('Chart rendered successfully');
|
|
3473
|
+
});
|
|
3474
|
+
this.chartInstance.on('click', (params) => {
|
|
3475
|
+
this.chartService.hideContextMenu();
|
|
3476
|
+
this.chartService.resetContextEvent();
|
|
3477
|
+
this.chartService.handleClick(params);
|
|
3478
|
+
});
|
|
3479
|
+
this.chartInstance.on('contextmenu', (params) => {
|
|
3480
|
+
this.chartService.openContextMenu(params, this.chartContainer);
|
|
3481
|
+
});
|
|
3482
|
+
chartDom.addEventListener('contextmenu', this.boundHandleContextMenu);
|
|
3483
|
+
document.addEventListener('click', () => {
|
|
3484
|
+
this.chartService.hideContextMenu();
|
|
3485
|
+
this.chartService.resetContextEvent();
|
|
3486
|
+
}, {
|
|
3487
|
+
passive: true,
|
|
3488
|
+
});
|
|
3489
|
+
this.isLoading = false;
|
|
3490
|
+
this.cdr.markForCheck();
|
|
3491
|
+
}
|
|
3492
|
+
handleContextMenu(event) {
|
|
3493
|
+
event.preventDefault();
|
|
3494
|
+
setTimeout(() => {
|
|
3495
|
+
if (!this.chartService.contextMenuEvent().seriesName) {
|
|
3496
|
+
this.chartService.openContextMenu(null, this.chartContainer, event);
|
|
3497
|
+
}
|
|
3498
|
+
}, 0);
|
|
3499
|
+
}
|
|
3500
|
+
updateChartWithData() {
|
|
3501
|
+
this.processData(); // Process without updating yet
|
|
3502
|
+
if (this.chartInstance) {
|
|
3503
|
+
const updatedOptions = {
|
|
3504
|
+
series: this.getProcessedValues(),
|
|
3505
|
+
};
|
|
3506
|
+
this.chartInstance.setOption(updatedOptions, {
|
|
3507
|
+
notMerge: false,
|
|
3508
|
+
lazyUpdate: true,
|
|
3509
|
+
silent: false,
|
|
3510
|
+
replaceMerge: ['series'],
|
|
3511
|
+
});
|
|
3512
|
+
}
|
|
3513
|
+
}
|
|
3514
|
+
processedData = [];
|
|
3515
|
+
processedColumns = [];
|
|
3516
|
+
getProcessedValues() {
|
|
3517
|
+
// For pie chart, assume single series using the first value column (index 1)
|
|
3518
|
+
// If multiple value columns, you could sum them or create multiple pies, but here we use the first one
|
|
3519
|
+
const columnList = [...this.processedColumns];
|
|
3520
|
+
columnList.shift();
|
|
3521
|
+
const seriesData = columnList.map((column, index) => ({
|
|
3522
|
+
name: column, // Category from first column
|
|
3523
|
+
value: this.processedData[0][index + 1] || 0, // Value from second column
|
|
3524
|
+
}));
|
|
3525
|
+
return [
|
|
3526
|
+
{
|
|
3527
|
+
name: `${this.processedColumns[0]}: ${this.processedData[0][0]}`,
|
|
3528
|
+
type: 'pie',
|
|
3529
|
+
data: seriesData,
|
|
3530
|
+
radius: '50%', // Default radius, can be customized via optionsConfig
|
|
3531
|
+
// Add other pie-specific options as needed
|
|
3532
|
+
itemStyle: {
|
|
3533
|
+
// color: '#5470c6', // Slice color, can be customized
|
|
3534
|
+
},
|
|
3535
|
+
emphasis: {
|
|
3536
|
+
itemStyle: {
|
|
3537
|
+
shadowBlur: 10,
|
|
3538
|
+
shadowOffsetX: 0,
|
|
3539
|
+
shadowColor: 'rgba(0, 0, 0, 0.5)',
|
|
3540
|
+
},
|
|
3541
|
+
},
|
|
3542
|
+
animation: true,
|
|
3543
|
+
},
|
|
3544
|
+
];
|
|
3545
|
+
}
|
|
3546
|
+
processData() {
|
|
3547
|
+
let dataToProcess = this.currentData;
|
|
3548
|
+
// if (this.enableSampling && this.currentData.length > this.sampleThreshold) {
|
|
3549
|
+
// const step = Math.ceil(this.currentData.length / this.sampleThreshold);
|
|
3550
|
+
// dataToProcess = this.currentData.filter((_, index) => index % step === 0);
|
|
3551
|
+
// }
|
|
3552
|
+
this.processedData = dataToProcess; // Cache processed
|
|
3553
|
+
this.processedColumns = this.currentColumns;
|
|
3554
|
+
}
|
|
3555
|
+
processAndUpdateData() {
|
|
3556
|
+
this.processData();
|
|
3557
|
+
if (this.chartInstance) {
|
|
3558
|
+
this.updateChartWithData();
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
handleResize() {
|
|
3562
|
+
if (this.chartInstance) {
|
|
3563
|
+
this.chartInstance.resize();
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
disposeChart() {
|
|
3567
|
+
if (this.chartInstance) {
|
|
3568
|
+
this.chartInstance.dispose();
|
|
3569
|
+
this.chartInstance.off('click');
|
|
3570
|
+
this.chartInstance = null;
|
|
3571
|
+
// console.log('ECharts instance disposed');
|
|
3572
|
+
}
|
|
3573
|
+
window.removeEventListener('resize', this.handleResize.bind(this));
|
|
3574
|
+
}
|
|
3575
|
+
// Public method: Update data externally (e.g., from API)
|
|
3576
|
+
updateData(newData) {
|
|
3577
|
+
this.currentData = newData;
|
|
3578
|
+
this.processAndUpdateData();
|
|
3579
|
+
}
|
|
3580
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PieChart, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
3581
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.15", type: PieChart, isStandalone: true, selector: "lib-pie-chart", inputs: { title: "title", height: "height", enableSampling: "enableSampling", sampleThreshold: "sampleThreshold", isLoading: "isLoading" }, viewQueries: [{ propertyName: "chartContainer", first: true, predicate: ["pieChartContainer"], descendants: true }], ngImport: i0, template: "<div #pieChartContainer style=\"width: 100%; height: 100%\"></div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3582
|
+
}
|
|
3583
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: PieChart, decorators: [{
|
|
3584
|
+
type: Component,
|
|
3585
|
+
args: [{ selector: 'lib-pie-chart', imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div #pieChartContainer style=\"width: 100%; height: 100%\"></div>\n" }]
|
|
3586
|
+
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { title: [{
|
|
3587
|
+
type: Input
|
|
3588
|
+
}], height: [{
|
|
3589
|
+
type: Input
|
|
3590
|
+
}], enableSampling: [{
|
|
3591
|
+
type: Input
|
|
3592
|
+
}], sampleThreshold: [{
|
|
3593
|
+
type: Input
|
|
3594
|
+
}], isLoading: [{
|
|
3595
|
+
type: Input
|
|
3596
|
+
}], chartContainer: [{
|
|
3597
|
+
type: ViewChild,
|
|
3598
|
+
args: ['pieChartContainer', { static: false }]
|
|
3599
|
+
}] } });
|
|
3600
|
+
|
|
3341
3601
|
class ChartsLib {
|
|
3342
3602
|
chartService;
|
|
3343
3603
|
differs;
|
|
@@ -3417,6 +3677,8 @@ class ChartsLib {
|
|
|
3417
3677
|
return LineChart;
|
|
3418
3678
|
case 'area':
|
|
3419
3679
|
return AreaChart;
|
|
3680
|
+
case 'pie':
|
|
3681
|
+
return PieChart;
|
|
3420
3682
|
default:
|
|
3421
3683
|
return null;
|
|
3422
3684
|
}
|
|
@@ -3457,5 +3719,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
|
|
|
3457
3719
|
* Generated bundle index. Do not edit.
|
|
3458
3720
|
*/
|
|
3459
3721
|
|
|
3460
|
-
export { ChartsLib, ChartsLibType, ClickEvent, ContextMenuListItem, OptionsConfig };
|
|
3722
|
+
export { ChartsLib, ChartsLibType, ClickEvent, ContextMenuListItem, OptionsConfig, PieChartOptionsConfig };
|
|
3461
3723
|
//# sourceMappingURL=cats-charts.mjs.map
|