cats-charts 0.0.21 → 0.0.23

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.
@@ -2,233 +2,124 @@ import * as i0 from '@angular/core';
2
2
  import { Injectable, EventEmitter, Output, Input, ChangeDetectionStrategy, Component, HostListener } from '@angular/core';
3
3
  import * as echarts from 'echarts/core';
4
4
  import { NgxEchartsDirective, provideEchartsCore } from 'ngx-echarts';
5
- import { LineChart, BarChart as BarChart$1, PieChart as PieChart$1 } from 'echarts/charts';
5
+ import { LineChart, BarChart as BarChart$1, PieChart as PieChart$1, CustomChart } from 'echarts/charts';
6
6
  import { GridComponent, TooltipComponent, LegendComponent, TitleComponent, DatasetComponent, GraphicComponent } from 'echarts/components';
7
7
  import { CanvasRenderer } from 'echarts/renderers';
8
8
 
9
9
  class Charts {
10
10
  legendSelected = {};
11
- // buildGraphicLegend(total: number, config: any, chartInstance: any) {
12
- // const pillHeight = 28;
13
- // const spacing = 14;
14
- // const indicatorWidth = 12;
15
- // const horizontalPadding = 8;
16
- // const gapAfterIndicator = 4;
17
- // const font = '14px sans-serif';
18
- // const isVertical = config.legendDirection === 'vertical';
19
- // // 🔹 Initialize selected state once
20
- // // if (Object.keys(this.legendSelected).length === 0) {
21
- // // config.data.forEach((d: any) => {
22
- // // this.legendSelected[d.name] = true;
23
- // // });
24
- // // }
25
- // // 🔹 Build pills
26
- // const pills = config.data.map((item: any, index: number) => {
27
- // const color =
28
- // config.colors?.[index] ?? ['#3b82f6', '#f59e0b', '#16a34a', '#ef4444'][index % 4];
29
- // const percentage = ((item.value / total) * 100).toFixed(1) + '%';
30
- // const nameRect = echarts.format.getTextRect(item.name, font);
31
- // const valueRect = echarts.format.getTextRect(String(item.value), font);
32
- // const pillWidth =
33
- // horizontalPadding +
34
- // indicatorWidth +
35
- // gapAfterIndicator +
36
- // nameRect.width +
37
- // 8 +
38
- // valueRect.width +
39
- // horizontalPadding;
40
- // return { item, color, pillWidth, percentage };
41
- // });
42
- // const totalWidth = isVertical
43
- // ? Math.max(...pills.map((p: any) => p.pillWidth))
44
- // : pills.reduce((sum: any, p: any) => sum + p.pillWidth, 0) + spacing * (pills.length - 1);
45
- // const totalHeight = isVertical
46
- // ? pills.length * pillHeight + spacing * (pills.length - 1)
47
- // : pillHeight;
48
- // let currentOffset = 0;
49
- // // 🔹 Position logic
50
- // const positionConfig: any = {};
51
- // switch (config.legendPosition) {
52
- // case 'top':
53
- // positionConfig.top = 20;
54
- // break;
55
- // case 'bottom':
56
- // positionConfig.bottom = 20;
57
- // break;
58
- // case 'left':
59
- // positionConfig.left = 20;
60
- // break;
61
- // case 'right':
62
- // positionConfig.right = 20;
63
- // break;
64
- // }
65
- // // ALIGNMENT (Cross-Axis)
66
- // if (config.legendPosition === 'top' || config.legendPosition === 'bottom') {
67
- // // Horizontal area → align horizontally
68
- // if (config.legendAlign === 'center') {
69
- // positionConfig.left = 'center';
70
- // } else if (config.legendAlign === 'right') {
71
- // positionConfig.right = 20;
72
- // } else {
73
- // positionConfig.left = 20;
74
- // }
75
- // } else {
76
- // // Vertical area → align vertically
77
- // if (config.legendAlign === 'center') {
78
- // positionConfig.top = 'middle';
79
- // } else if (config.legendAlign === 'right') {
80
- // positionConfig.bottom = 20;
81
- // } else {
82
- // positionConfig.top = 20;
83
- // }
84
- // }
85
- // return [
86
- // {
87
- // id: 'customLegend', // IMPORTANT
88
- // type: 'group',
89
- // ...positionConfig,
90
- // width: totalWidth,
91
- // height: totalHeight,
92
- // children: pills.map((pill: any) => {
93
- // const offset = currentOffset;
94
- // currentOffset += (isVertical ? pillHeight : pill.pillWidth) + spacing;
95
- // let isSelected = this.legendSelected[pill.item.name];
96
- // return {
97
- // type: 'group',
98
- // top: isVertical ? offset : 0,
99
- // left: isVertical ? 0 : offset,
100
- // width: pill.pillWidth,
101
- // height: pillHeight,
102
- // cursor: 'pointer',
103
- // // onclick: () => {
104
- // // // 🔹 Toggle selected state
105
- // // this.legendSelected[pill.item.name] = !this.legendSelected[pill.item.name];
106
- // // chartInstance?.dispatchAction({
107
- // // type: 'legendToggleSelect',
108
- // // name: pill.item.name,
109
- // // });
110
- // // chartInstance?.setOption({
111
- // // graphic: {
112
- // // id: 'customLegend',
113
- // // // $action: 'replace',
114
- // // ...this.buildGraphicLegend(total, config, chartInstance)[0],
115
- // // },
116
- // // });
117
- // // },
118
- // onclick: () => {
119
- // chartInstance.dispatchAction({
120
- // type: 'legendToggleSelect',
121
- // name: pill.item.name,
122
- // });
123
- // // 🔥 Read fresh selected state from chart
124
- // const selectedMap = chartInstance.getOption()?.legend?.[0]?.selected || {};
125
- // this.legendSelected = { ...selectedMap };
126
- // chartInstance.setOption({
127
- // graphic: {
128
- // id: 'customLegend',
129
- // $action: 'replace',
130
- // ...this.buildGraphicLegend(total, config, chartInstance),
131
- // },
132
- // });
133
- // },
134
- // children: [
135
- // // 🔹 Pill Background
136
- // {
137
- // type: 'rect',
138
- // shape: {
139
- // width: pill.pillWidth,
140
- // height: pillHeight,
141
- // r: 4,
142
- // },
143
- // style: {
144
- // fill: !isSelected ? this.hexToRgba(pill.color, 0.08) : '#F2F2F7',
145
- // stroke: !isSelected ? pill.color : '#D1D1D6',
146
- // // fill: this.hexToRgba(pill.color, 0.08),
147
- // // stroke: pill.color,
148
- // lineWidth: 1,
149
- // },
150
- // },
151
- // // 🔹 Color Indicator
152
- // {
153
- // type: 'rect',
154
- // shape: {
155
- // width: indicatorWidth,
156
- // height: indicatorWidth,
157
- // r: 2,
158
- // },
159
- // left: horizontalPadding,
160
- // top: (pillHeight - indicatorWidth) / 2,
161
- // // style: {
162
- // // fill: pill.color,
163
- // // },
164
- // style: {
165
- // fill: !isSelected ? pill.color : '#C7C7CC',
166
- // },
167
- // },
168
- // // 🔹 Label
169
- // {
170
- // type: 'text',
171
- // left: horizontalPadding + indicatorWidth + gapAfterIndicator,
172
- // top: (pillHeight - indicatorWidth) / 2,
173
- // style: {
174
- // text: pill.item.name,
175
- // fontSize: 14,
176
- // // fill: '#1C1C1E',
177
- // fill: !isSelected ? '#1C1C1E' : '#8E8E93',
178
- // textVerticalAlign: 'middle',
179
- // },
180
- // },
181
- // // 🔹 value text
182
- // {
183
- // type: 'text',
184
- // left: pill.pillWidth - horizontalPadding - indicatorWidth - gapAfterIndicator,
185
- // top: (pillHeight - indicatorWidth) / 2,
186
- // style: {
187
- // text: pill.item.value,
188
- // fontSize: 14,
189
- // fontWeight: 500,
190
- // // fill: '#1C1C1E',
191
- // fill: !isSelected ? '#1C1C1E' : '#8E8E93',
192
- // textAlign: 'right',
193
- // textVerticalAlign: 'middle',
194
- // },
195
- // },
196
- // ],
197
- // };
198
- // }),
199
- // },
200
- // ];
201
- // }
202
11
  buildGraphicLegend(total, config, chartInstance) {
203
12
  const pillHeight = 28;
204
13
  const spacing = 14;
205
14
  const indicatorWidth = 12;
206
- const horizontalPadding = 8;
207
- const gapAfterIndicator = 4;
15
+ const padding = 8;
208
16
  const font = '14px sans-serif';
209
- const isVertical = config.legendDirection === 'vertical';
210
- // 🔹 Initialize selected state once
17
+ const containerWidth = chartInstance?.getWidth?.() ?? 800;
18
+ const maxWidth = containerWidth * (config.legendContainerWidth ?? 0.7);
211
19
  const selectedMap = chartInstance?.getOption()?.legend?.[0]?.selected || {};
212
20
  const pills = config.data.map((item, index) => {
213
- const color = config.colors?.[index] ?? ['#3b82f6', '#f59e0b', '#16a34a', '#ef4444'][index % 4];
21
+ const color = total === 0
22
+ ? '#E6E7E8'
23
+ : (item?.itemStyle?.color ??
24
+ config.colors?.[index] ??
25
+ ['#22c55e', '#3b82f6', '#ef4444', '#6b7280'][index % 4]);
214
26
  const nameRect = echarts.format.getTextRect(item.name, font);
215
27
  const valueRect = echarts.format.getTextRect(String(item.value), font);
216
- const pillWidth = horizontalPadding +
217
- indicatorWidth +
218
- gapAfterIndicator +
219
- nameRect.width +
220
- 8 +
221
- valueRect.width +
222
- horizontalPadding;
28
+ const pillWidth = padding + indicatorWidth + 6 + nameRect.width + 8 + valueRect.width + padding;
223
29
  return { item, color, pillWidth };
224
30
  });
225
- const totalWidth = isVertical
226
- ? Math.max(...pills.map((p) => p.pillWidth))
227
- : pills.reduce((sum, p) => sum + p.pillWidth, 0) + spacing * (pills.length - 1);
228
- const totalHeight = isVertical
229
- ? pills.length * pillHeight + spacing * (pills.length - 1)
230
- : pillHeight;
231
- let currentOffset = 0;
31
+ // 🔹 Build rows dynamically
32
+ const rows = [];
33
+ let currentRow = [];
34
+ let rowWidth = 0;
35
+ pills.forEach((pill) => {
36
+ if (rowWidth + pill.pillWidth > maxWidth && currentRow.length) {
37
+ rows.push({ pills: currentRow, width: rowWidth });
38
+ currentRow = [];
39
+ rowWidth = 0;
40
+ }
41
+ currentRow.push(pill);
42
+ rowWidth += pill.pillWidth + spacing;
43
+ });
44
+ if (currentRow.length)
45
+ rows.push({ pills: currentRow, width: rowWidth });
46
+ // 🔹 Build graphic children
47
+ let yOffset = 0;
48
+ const children = [];
49
+ rows.forEach((row) => {
50
+ let xOffset = config.legendAlign === 'center' ? (maxWidth - row.width) / 2 : maxWidth;
51
+ row.pills.forEach((pill) => {
52
+ const isSelected = selectedMap[pill.item.name] !== false;
53
+ children.push({
54
+ type: 'group',
55
+ left: xOffset,
56
+ top: yOffset,
57
+ width: pill.pillWidth,
58
+ height: pillHeight,
59
+ cursor: 'pointer',
60
+ onclick: () => {
61
+ chartInstance.dispatchAction({
62
+ type: 'legendToggleSelect',
63
+ name: pill.item.name,
64
+ });
65
+ chartInstance.setOption({
66
+ graphic: this.buildGraphicLegend(total, config, chartInstance),
67
+ });
68
+ },
69
+ children: [
70
+ {
71
+ type: 'rect',
72
+ shape: {
73
+ width: pill.pillWidth,
74
+ height: pillHeight,
75
+ r: 4,
76
+ },
77
+ style: {
78
+ fill: isSelected ? this.hexToRgba(pill.color, total === 0 ? 0.3 : 0.03) : '#F2F2F7',
79
+ stroke: isSelected ? this.hexToRgba(pill.color, 0.3) : '#D1D1D6',
80
+ lineWidth: 1,
81
+ },
82
+ },
83
+ {
84
+ type: 'rect',
85
+ shape: { width: 12, height: 12, r: 2 },
86
+ left: padding,
87
+ top: (pillHeight - 12) / 2,
88
+ style: {
89
+ fill: isSelected ? pill.color : '#C7C7CC',
90
+ },
91
+ },
92
+ {
93
+ type: 'text',
94
+ left: padding + indicatorWidth + 6,
95
+ top: (pillHeight - indicatorWidth) / 2,
96
+ style: {
97
+ text: `${pill.item.name}:`,
98
+ fontSize: 14,
99
+ fontWeight: 400,
100
+ fill: isSelected && total !== 0 ? '#1C1C1E' : '#81858A',
101
+ textVerticalAlign: 'middle',
102
+ },
103
+ },
104
+ {
105
+ type: 'text',
106
+ right: padding,
107
+ top: (pillHeight - indicatorWidth) / 2,
108
+ style: {
109
+ text: total === 0 ? '-' : pill.item.value,
110
+ fontSize: 14,
111
+ fontWeight: 500,
112
+ fill: isSelected && total !== 0 ? '#1C1C1E' : '#81858A',
113
+ textAlign: 'right',
114
+ textVerticalAlign: 'middle',
115
+ },
116
+ },
117
+ ],
118
+ });
119
+ xOffset += pill.pillWidth + spacing;
120
+ });
121
+ yOffset += pillHeight + spacing;
122
+ });
232
123
  // 🔹 Position logic
233
124
  const positionConfig = {};
234
125
  switch (config.legendPosition) {
@@ -272,93 +163,12 @@ class Charts {
272
163
  }
273
164
  return [
274
165
  {
275
- id: 'customLegend', // IMPORTANT
166
+ id: 'customLegend',
276
167
  type: 'group',
277
168
  ...positionConfig,
278
- width: totalWidth,
279
- height: totalHeight,
280
- children: pills.map((pill) => {
281
- const offset = currentOffset;
282
- currentOffset += (isVertical ? pillHeight : pill.pillWidth) + spacing;
283
- const isSelected = selectedMap[pill.item.name] !== false;
284
- return {
285
- type: 'group',
286
- top: isVertical ? offset : 0,
287
- left: isVertical ? 0 : offset,
288
- width: pill.pillWidth,
289
- height: pillHeight,
290
- cursor: 'pointer',
291
- onclick: () => {
292
- chartInstance.dispatchAction({
293
- type: 'legendToggleSelect',
294
- name: pill.item.name,
295
- });
296
- chartInstance.setOption({
297
- graphic: {
298
- id: 'customLegend',
299
- // $action: 'replace',
300
- ...this.buildGraphicLegend(total, config, chartInstance)[0],
301
- },
302
- });
303
- },
304
- children: [
305
- // 🔹 Pill Background
306
- {
307
- type: 'rect',
308
- shape: {
309
- width: pill.pillWidth,
310
- height: pillHeight,
311
- r: 4,
312
- },
313
- style: {
314
- fill: isSelected ? this.hexToRgba(pill.color, 0.08) : '#F2F2F7',
315
- stroke: isSelected ? pill.color : '#D1D1D6',
316
- lineWidth: 1,
317
- },
318
- },
319
- // 🔹 Color Indicator
320
- {
321
- type: 'rect',
322
- shape: {
323
- width: indicatorWidth,
324
- height: indicatorWidth,
325
- r: 2,
326
- },
327
- left: horizontalPadding,
328
- top: (pillHeight - indicatorWidth) / 2,
329
- style: {
330
- fill: isSelected ? pill.color : '#C7C7CC',
331
- },
332
- },
333
- // 🔹 Label
334
- {
335
- type: 'text',
336
- left: horizontalPadding + indicatorWidth + gapAfterIndicator,
337
- top: (pillHeight - indicatorWidth) / 2,
338
- style: {
339
- text: pill.item.name,
340
- fontSize: 14,
341
- fill: isSelected ? '#1C1C1E' : '#8E8E93',
342
- textVerticalAlign: 'middle',
343
- },
344
- },
345
- // 🔹 value text
346
- {
347
- type: 'text',
348
- right: horizontalPadding,
349
- top: (pillHeight - indicatorWidth) / 2,
350
- style: {
351
- text: pill.item.value,
352
- fontSize: 14,
353
- fontWeight: 500,
354
- fill: isSelected ? '#1C1C1E' : '#8E8E93',
355
- textAlign: 'right',
356
- textVerticalAlign: 'middle',
357
- },
358
- },
359
- ],
360
- };
361
- }),
169
+ width: maxWidth,
170
+ height: yOffset,
171
+ children,
362
172
  },
363
173
  ];
364
174
  }
@@ -420,44 +230,210 @@ class Charts {
420
230
  const name = params.name;
421
231
  const value = params.value;
422
232
  const percent = params.percent;
423
- return `<div style="
424
- position: relative;
425
- background-color: #fff;
426
- padding: 8px 16px;
427
- border-radius: 8px;
428
- box-shadow: 0 4px 16px rgba(0,0,0,0.08);
429
- display: flex;
430
- align-items: center;
431
- gap: 10px;
432
- ">
433
- <div style="
434
- position: absolute;
435
- left: -10px;
436
- top: 10px;
437
- width: 0;
438
- height: 0;
439
- border-top: 10px solid transparent;
440
- border-bottom: 10px solid transparent;
441
- border-right: 10px solid #ffffff;
442
- "></div>
443
-
444
- <span style="
445
- width: 14px;
446
- height: 14px;
447
- background: ${color};
448
- border-radius: 3px;
449
- display: inline-block;
450
- "></span>
451
-
452
- <span style="
453
- font-size: 12px;
454
- color: #434A51;
455
- ">
456
- ${name}: <b style="color:#111; font-weight:600;">${value}</b> ${config.showTooltipPercent ? '(' + percent + '%)' : ''}
457
- </span>
458
- </div>
233
+ return `<div style="
234
+ position: relative;
235
+ background-color: #fff;
236
+ padding: 8px 16px;
237
+ border-radius: 8px;
238
+ box-shadow: 0 4px 16px rgba(0,0,0,0.08);
239
+ display: flex;
240
+ align-items: center;
241
+ gap: 10px;
242
+ ">
243
+ <div style="
244
+ position: absolute;
245
+ left: -10px;
246
+ top: 10px;
247
+ width: 0;
248
+ height: 0;
249
+ border-top: 10px solid transparent;
250
+ border-bottom: 10px solid transparent;
251
+ border-right: 10px solid #ffffff;
252
+ "></div>
253
+
254
+ <span style="
255
+ width: 14px;
256
+ height: 14px;
257
+ background: ${color};
258
+ border-radius: 3px;
259
+ display: inline-block;
260
+ "></span>
261
+
262
+ <span style="
263
+ font-size: 12px;
264
+ color: #434A51;
265
+ ">
266
+ ${name}: <b style="color:#111; font-weight:600;">${value}</b> ${config.showTooltipPercent ? '(' + percent + '%)' : ''}
267
+ </span>
268
+ </div>
459
269
  `;
460
270
  }
271
+ barLineTooltipFormatter(params) {
272
+ if (!params || !params.length)
273
+ return '';
274
+ const date = params[0].axisValueLabel || params[0].name;
275
+ let total = 0;
276
+ let rows = '';
277
+ params.forEach((item) => {
278
+ const color = item.color;
279
+ const name = item.seriesName;
280
+ const value = item.value ?? 0;
281
+ total += Number(value);
282
+ rows += `
283
+ <div style="
284
+ display:flex;
285
+ align-items:center;
286
+ gap:8px;
287
+ font-size:13px;
288
+ color:#434A51;
289
+ margin-top:6px;
290
+ ">
291
+ <span style="
292
+ width:14px;
293
+ height:14px;
294
+ background:${color};
295
+ border-radius:3px;
296
+ display:inline-block;
297
+ "></span>
298
+
299
+ <span>${name}: <b style="color:#111;font-weight:600;">${value}</b></span>
300
+ </div>
301
+ `;
302
+ });
303
+ return `
304
+ <div style="
305
+ background:#ffffff;
306
+ padding:16px;
307
+ border-radius: 8px;
308
+ background-color: #ffffff;
309
+ border: 1px solid #f0f0f0;
310
+ box-shadow: 0px 10.55px 23.39px -3.52px #0a0d1214;
311
+ min-width:190px;
312
+ font-family: Inter, sans-serif;
313
+ ">
314
+ <div style="
315
+ position: absolute;
316
+ left: -10px;
317
+ top: 50%;
318
+ width: 0;
319
+ height: 0;
320
+ border-top: 10px solid transparent;
321
+ border-bottom: 10px solid transparent;
322
+ border-right: 10px solid #ffffff;
323
+ "></div>
324
+ <div style="
325
+ font-size:15px;
326
+ font-weight:600;
327
+ color:#111;
328
+ margin-bottom:2px;
329
+ border-bottom: 1px #F0F0F0 ;
330
+ ">
331
+ ${date}
332
+ </div>
333
+
334
+ ${rows}
335
+
336
+ <div style="
337
+ font-size:13px;
338
+ color:#434A51;
339
+ margin-top:10px;
340
+ ">
341
+ Total: <b style="color:#111;font-weight:600;">${total}</b>
342
+ </div>
343
+
344
+ </div>
345
+ `;
346
+ }
347
+ timelineChartTooltipFormatter(params) {
348
+ const d = params.data;
349
+ return ` <div style="
350
+ position: relative;
351
+ background:#fff;
352
+ border-radius:8px;
353
+ font-size:12px;
354
+ color:#444;
355
+ box-shadow:0 2px 8px rgba(0,0,0,0.15);
356
+ min-width:220px;
357
+ ">
358
+ <div style="
359
+ position: absolute;
360
+ left: -10px;
361
+ bottom: 10px;
362
+ width: 0;
363
+ height: 0;
364
+ border-top: 10px solid transparent;
365
+ border-bottom: 10px solid transparent;
366
+ border-right: 10px solid #ffffff;
367
+ "></div>
368
+ <div style="padding: 8px 16px; border-bottom:1px solid #E6E7E8;">
369
+ <div style="font-weight:400;color:#040D17;font-size: 14px;">
370
+ ${d.start || '00:00'} - ${d.end || '00:00'}
371
+ </div>
372
+
373
+ <div style="color:#81858A;margin-top:2px;">
374
+ ${d.date || 'NA'}
375
+ </div>
376
+ </div>
377
+ <div style="padding: 8px 16px;">
378
+ <div>
379
+ Work Mode: <b>${d.workMode || '-'}</b>
380
+ </div>
381
+
382
+ <div style="margin-top:6px;">
383
+ Productivity:
384
+ <span style="color:#f59e0b;font-weight:600;">
385
+ ${d.productivity || 'NA'}
386
+ </span>
387
+
388
+ <span style="margin-left:12px;">Activity:</span>
389
+ <span style="color:#22c55e;font-weight:600;">
390
+ ${d.activity || 'NA'}
391
+ </span>
392
+ </div>
393
+
394
+ <div style="margin-top:6px;">
395
+ System Presence: <b>${d.systemPresence || '-'}</b>
396
+ </div>
397
+
398
+ <div style="margin-top:6px;">
399
+ POW Source: <b>${d.powSource || '-'}</b>
400
+ </div>
401
+
402
+ <div style="margin-top:6px;">
403
+ Location: <b>${d.location || '-'}</b>
404
+ </div>
405
+
406
+ <div style="
407
+ display:flex;
408
+ gap:10px;
409
+ align-items:center;
410
+ margin-top:6px;
411
+ ">
412
+ Apps Used:
413
+ <span style="color:#2563eb;font-weight:600;">
414
+ ${d.appsUsed || 0}
415
+ </span>
416
+
417
+ <span style="color:#ccc;">|</span>
418
+
419
+ Screenshots:
420
+ <span style="color:#2563eb;font-weight:600;">
421
+ ${d.screenShots || 0}
422
+ </span>
423
+ </div>
424
+
425
+ <div style="margin-top:8px;">
426
+ <span style="
427
+ color:#2563eb;
428
+ cursor:pointer;
429
+ font-weight:500;
430
+ ">
431
+ Manage Time Record
432
+ </span>
433
+ </div>
434
+ </div>
435
+ </div>`;
436
+ }
461
437
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: Charts, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
462
438
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: Charts, providedIn: 'root' });
463
439
  }
@@ -510,8 +486,9 @@ class LinesChart {
510
486
  left: 'center',
511
487
  },
512
488
  tooltip: {
513
- show: config.showTooltip ?? true,
514
489
  trigger: 'axis',
490
+ padding: 0,
491
+ formatter: (params) => this.chartService.barLineTooltipFormatter(params),
515
492
  },
516
493
  legend: {
517
494
  show: false,
@@ -534,7 +511,7 @@ class LinesChart {
534
511
  axisLine: {
535
512
  show: this.config.showXAxisLine ?? true,
536
513
  },
537
- ...config.xAxis
514
+ ...config.xAxis,
538
515
  },
539
516
  yAxis: {
540
517
  show: !this.config.isTrendChart,
@@ -543,7 +520,7 @@ class LinesChart {
543
520
  axisLine: {
544
521
  show: this.config.showYAxisLine ?? true,
545
522
  },
546
- ...config.yAxis
523
+ ...config.yAxis,
547
524
  },
548
525
  series: config.series.map((s) => {
549
526
  const lineColor = s.color || '#3b82f6';
@@ -607,11 +584,11 @@ class LinesChart {
607
584
  this.chartInstance?.dispose();
608
585
  }
609
586
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LinesChart, deps: [{ token: Charts }], target: i0.ɵɵFactoryTarget.Component });
610
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: LinesChart, isStandalone: true, selector: "lib-line-chart", inputs: { config: "config", theme: "theme", events: "events" }, outputs: { chartEvent: "chartEvent" }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "\r\n<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n (chartInit)=\"onChartInit($event)\"\r\n class=\"chart-container\">\r\n</div>\r\n", styles: [".chart-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
587
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: LinesChart, isStandalone: true, selector: "lib-line-chart", inputs: { config: "config", theme: "theme", events: "events" }, outputs: { chartEvent: "chartEvent" }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "\n<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n (chartInit)=\"onChartInit($event)\"\n class=\"chart-container\">\n</div>\n", styles: [".chart-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
611
588
  }
612
589
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: LinesChart, decorators: [{
613
590
  type: Component,
614
- args: [{ selector: 'lib-line-chart', standalone: true, imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "\r\n<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n (chartInit)=\"onChartInit($event)\"\r\n class=\"chart-container\">\r\n</div>\r\n", styles: [".chart-container{width:100%;height:100%}\n"] }]
591
+ args: [{ selector: 'lib-line-chart', standalone: true, imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "\n<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n (chartInit)=\"onChartInit($event)\"\n class=\"chart-container\">\n</div>\n", styles: [".chart-container{width:100%;height:100%}\n"] }]
615
592
  }], ctorParameters: () => [{ type: Charts }], propDecorators: { config: [{
616
593
  type: Input
617
594
  }], theme: [{
@@ -631,11 +608,11 @@ class RightClickCard {
631
608
  // this.closeMenu();
632
609
  }
633
610
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RightClickCard, deps: [], target: i0.ɵɵFactoryTarget.Component });
634
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: RightClickCard, isStandalone: true, selector: "lib-right-click-card", inputs: { cardPosition: "cardPosition", cardOptions: "cardOptions" }, outputs: { contextMenuClick: "contextMenuClick" }, ngImport: i0, template: "<div\r\n class=\"context-card\"\r\n [style.left.px]=\"cardPosition.x\"\r\n [style.top.px]=\"cardPosition.y\"\r\n (click)=\"$event.stopPropagation()\"\r\n>\r\n @for (item of cardOptions; track item.value) {\r\n <div class=\"context-item\" (click)=\"onMenuClick(item)\">\r\n @if (item.icon) {\r\n <img [src]=\"item.icon\" alt=\"icon\" />\r\n }\r\n\r\n <span>{{ item.label }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".context-card{position:absolute;background:#fff;border-radius:10px;padding:6px 0;min-width:160px;box-shadow:0 10px 25px #00000026;z-index:9999}.context-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .2s ease}.context-item:hover{background:#f3f3f3}\n"] });
611
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: RightClickCard, isStandalone: true, selector: "lib-right-click-card", inputs: { cardPosition: "cardPosition", cardOptions: "cardOptions" }, outputs: { contextMenuClick: "contextMenuClick" }, ngImport: i0, template: "<div\n class=\"context-card\"\n [style.left.px]=\"cardPosition.x\"\n [style.top.px]=\"cardPosition.y\"\n (click)=\"$event.stopPropagation()\"\n>\n @for (item of cardOptions; track item.value) {\n <div class=\"context-item\" (click)=\"onMenuClick(item)\">\n @if (item.icon) {\n <img [src]=\"item.icon\" alt=\"icon\" />\n }\n\n <span>{{ item.label }}</span>\n </div>\n }\n</div>\n", styles: [".context-card{position:absolute;background:#fff;border-radius:10px;padding:6px 0;min-width:160px;box-shadow:0 10px 25px #00000026;z-index:9999}.context-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .2s ease}.context-item:hover{background:#f3f3f3}\n"] });
635
612
  }
636
613
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: RightClickCard, decorators: [{
637
614
  type: Component,
638
- args: [{ selector: 'lib-right-click-card', imports: [], template: "<div\r\n class=\"context-card\"\r\n [style.left.px]=\"cardPosition.x\"\r\n [style.top.px]=\"cardPosition.y\"\r\n (click)=\"$event.stopPropagation()\"\r\n>\r\n @for (item of cardOptions; track item.value) {\r\n <div class=\"context-item\" (click)=\"onMenuClick(item)\">\r\n @if (item.icon) {\r\n <img [src]=\"item.icon\" alt=\"icon\" />\r\n }\r\n\r\n <span>{{ item.label }}</span>\r\n </div>\r\n }\r\n</div>\r\n", styles: [".context-card{position:absolute;background:#fff;border-radius:10px;padding:6px 0;min-width:160px;box-shadow:0 10px 25px #00000026;z-index:9999}.context-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .2s ease}.context-item:hover{background:#f3f3f3}\n"] }]
615
+ args: [{ selector: 'lib-right-click-card', imports: [], template: "<div\n class=\"context-card\"\n [style.left.px]=\"cardPosition.x\"\n [style.top.px]=\"cardPosition.y\"\n (click)=\"$event.stopPropagation()\"\n>\n @for (item of cardOptions; track item.value) {\n <div class=\"context-item\" (click)=\"onMenuClick(item)\">\n @if (item.icon) {\n <img [src]=\"item.icon\" alt=\"icon\" />\n }\n\n <span>{{ item.label }}</span>\n </div>\n }\n</div>\n", styles: [".context-card{position:absolute;background:#fff;border-radius:10px;padding:6px 0;min-width:160px;box-shadow:0 10px 25px #00000026;z-index:9999}.context-item{display:flex;align-items:center;gap:8px;padding:8px 14px;cursor:pointer;transition:background .2s ease}.context-item:hover{background:#f3f3f3}\n"] }]
639
616
  }], propDecorators: { cardPosition: [{
640
617
  type: Input
641
618
  }], cardOptions: [{
@@ -654,6 +631,7 @@ echarts.use([
654
631
  CanvasRenderer,
655
632
  ]);
656
633
  class BarChart {
634
+ chartService;
657
635
  cdr;
658
636
  config;
659
637
  theme;
@@ -666,7 +644,8 @@ class BarChart {
666
644
  chartInstance;
667
645
  cardPosition = { x: 0, y: 0 };
668
646
  openCard = false;
669
- constructor(cdr) {
647
+ constructor(chartService, cdr) {
648
+ this.chartService = chartService;
670
649
  this.cdr = cdr;
671
650
  }
672
651
  /* ------------------ CONFIG CHANGE ------------------ */
@@ -688,9 +667,20 @@ class BarChart {
688
667
  text: this.config.title,
689
668
  left: this.config.titlePosition || 'center',
690
669
  },
670
+ // tooltip: {
671
+ // show: this.config.showTooltip ?? true,
672
+ // trigger: 'axis',
673
+ // },
691
674
  tooltip: {
692
- show: this.config.showTooltip ?? true,
693
675
  trigger: 'axis',
676
+ backgroundColor: 'transparent', // remove default box
677
+ borderWidth: 0,
678
+ padding: 0,
679
+ confine: true,
680
+ formatter: (params) => this.chartService.barLineTooltipFormatter(params),
681
+ },
682
+ legends: {
683
+ show: false,
694
684
  },
695
685
  grid: {
696
686
  left: this.config.gridLeft ?? '',
@@ -702,12 +692,12 @@ class BarChart {
702
692
  type: 'category',
703
693
  data: this.config.categories,
704
694
  axisLine: { show: this.config.showXAxisLine ?? true },
705
- ...this.config.xAxis
695
+ ...this.config.xAxis,
706
696
  },
707
697
  yAxis: {
708
698
  type: 'value',
709
699
  axisLine: { show: this.config.showYAxisLine ?? true },
710
- ...this.config.yAxis
700
+ ...this.config.yAxis,
711
701
  },
712
702
  // Handle both single-series and multi-series dynamically
713
703
  series: (() => {
@@ -728,9 +718,9 @@ class BarChart {
728
718
  borderRadius: this.config.borderRadius ?? 0,
729
719
  },
730
720
  emphasis: {
731
- scale: false
721
+ scale: false,
732
722
  },
733
- ...s
723
+ ...s,
734
724
  }));
735
725
  }
736
726
  else if (this.config.data) {
@@ -751,7 +741,7 @@ class BarChart {
751
741
  },
752
742
  emphasis: {
753
743
  focus: 'series',
754
- show: false
744
+ show: false,
755
745
  },
756
746
  // ...this.config,
757
747
  },
@@ -809,13 +799,13 @@ class BarChart {
809
799
  this.chartInstance.dispose();
810
800
  }
811
801
  }
812
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BarChart, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
813
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BarChart, isStandalone: true, selector: "lib-bar-chart", inputs: { config: "config", theme: "theme", events: "events", contextMenuOptions: "contextMenuOptions", showContextMenu: "showContextMenu" }, outputs: { contextMenuClick: "contextMenuClick", chartEvent: "chartEvent" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n class=\"chart-container\"\r\n (chartInit)=\"onChartInit($event)\"\r\n>\r\n</div>\r\n\r\n@if (openCard) {\r\n <lib-right-click-card\r\n [cardOptions]=\"contextMenuOptions\"\r\n (contextMenuClick)=\"onMenuClick($event)\"\r\n [cardPosition]=\"cardPosition\"\r\n ></lib-right-click-card>\r\n}", styles: [".chart-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
802
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BarChart, deps: [{ token: Charts }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
803
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: BarChart, isStandalone: true, selector: "lib-bar-chart", inputs: { config: "config", theme: "theme", events: "events", contextMenuOptions: "contextMenuOptions", showContextMenu: "showContextMenu" }, outputs: { contextMenuClick: "contextMenuClick", chartEvent: "chartEvent" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n>\n</div>\n\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"contextMenuOptions\"\n (contextMenuClick)=\"onMenuClick($event)\"\n [cardPosition]=\"cardPosition\"\n ></lib-right-click-card>\n}", styles: [".chart-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
814
804
  }
815
805
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: BarChart, decorators: [{
816
806
  type: Component,
817
- args: [{ selector: 'lib-bar-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n class=\"chart-container\"\r\n (chartInit)=\"onChartInit($event)\"\r\n>\r\n</div>\r\n\r\n@if (openCard) {\r\n <lib-right-click-card\r\n [cardOptions]=\"contextMenuOptions\"\r\n (contextMenuClick)=\"onMenuClick($event)\"\r\n [cardPosition]=\"cardPosition\"\r\n ></lib-right-click-card>\r\n}", styles: [".chart-container{width:100%;height:100%}\n"] }]
818
- }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { config: [{
807
+ args: [{ selector: 'lib-bar-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n>\n</div>\n\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"contextMenuOptions\"\n (contextMenuClick)=\"onMenuClick($event)\"\n [cardPosition]=\"cardPosition\"\n ></lib-right-click-card>\n}", styles: [".chart-container{width:100%;height:100%}\n"] }]
808
+ }], ctorParameters: () => [{ type: Charts }, { type: i0.ChangeDetectorRef }], propDecorators: { config: [{
819
809
  type: Input
820
810
  }], theme: [{
821
811
  type: Input
@@ -971,11 +961,11 @@ class PieChart {
971
961
  this.openCard = false;
972
962
  }
973
963
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PieChart, deps: [{ token: Charts }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
974
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: PieChart, isStandalone: true, selector: "lib-pie-chart", inputs: { config: "config", theme: "theme", events: "events", cardOptions: "cardOptions" }, outputs: { chartEvent: "chartEvent", cardOptionClick: "cardOptionClick" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n class=\"chart-container\"\r\n (chartInit)=\"onChartInit($event)\"\r\n></div>\r\n\r\n@if (openCard) {\r\n <lib-right-click-card\r\n [cardOptions]=\"cardOptions\"\r\n [cardPosition]=\"cardPosition\"\r\n (contextMenuClick)=\"onMenuClick($event)\"\r\n >\r\n </lib-right-click-card>\r\n}\r\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
964
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: PieChart, isStandalone: true, selector: "lib-pie-chart", inputs: { config: "config", theme: "theme", events: "events", cardOptions: "cardOptions" }, outputs: { chartEvent: "chartEvent", cardOptionClick: "cardOptionClick" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"cardOptions\"\n [cardPosition]=\"cardPosition\"\n (contextMenuClick)=\"onMenuClick($event)\"\n >\n </lib-right-click-card>\n}\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
975
965
  }
976
966
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PieChart, decorators: [{
977
967
  type: Component,
978
- args: [{ selector: 'lib-pie-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n class=\"chart-container\"\r\n (chartInit)=\"onChartInit($event)\"\r\n></div>\r\n\r\n@if (openCard) {\r\n <lib-right-click-card\r\n [cardOptions]=\"cardOptions\"\r\n [cardPosition]=\"cardPosition\"\r\n (contextMenuClick)=\"onMenuClick($event)\"\r\n >\r\n </lib-right-click-card>\r\n}\r\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"] }]
968
+ args: [{ selector: 'lib-pie-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"cardOptions\"\n [cardPosition]=\"cardPosition\"\n (contextMenuClick)=\"onMenuClick($event)\"\n >\n </lib-right-click-card>\n}\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"] }]
979
969
  }], ctorParameters: () => [{ type: Charts }, { type: i0.ChangeDetectorRef }], propDecorators: { config: [{
980
970
  type: Input
981
971
  }], theme: [{
@@ -1056,6 +1046,13 @@ class DoughnutChart {
1056
1046
  */
1057
1047
  buildOption() {
1058
1048
  const total = this.config.data?.reduce((sum, item) => sum + item.value, 0);
1049
+ const seriesData = total === 0
1050
+ ? this.config.data.map((d) => ({
1051
+ value: d.value,
1052
+ name: d.name,
1053
+ itemStyle: { color: '#d3d3d3' }, // grey
1054
+ }))
1055
+ : this.config.data;
1059
1056
  const innerRadius = this.config.innerRadius ?? '70%';
1060
1057
  const outerRadius = this.config.outerRadius ?? '90%';
1061
1058
  this.chartOption = {
@@ -1092,7 +1089,7 @@ class DoughnutChart {
1092
1089
  bottom: this.config.bottom ?? 0,
1093
1090
  radius: [innerRadius, outerRadius],
1094
1091
  center: this.config.center ?? ['50%', '50%'],
1095
- data: this.config.data,
1092
+ data: seriesData,
1096
1093
  color: this.config.colors,
1097
1094
  label: {
1098
1095
  show: this.config.showLabel ?? false,
@@ -1162,11 +1159,11 @@ class DoughnutChart {
1162
1159
  }
1163
1160
  }
1164
1161
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DoughnutChart, deps: [{ token: Charts }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1165
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DoughnutChart, isStandalone: true, selector: "lib-doughnut-chart", inputs: { config: "config", theme: "theme", events: "events", contextMenuOptions: "contextMenuOptions", showContextMenu: "showContextMenu" }, outputs: { contextMenuClick: "contextMenuClick", chartEvent: "chartEvent" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n class=\"chart-container\"\r\n (chartInit)=\"onChartInit($event)\"\r\n></div>\r\n@if (openCard) {\r\n <lib-right-click-card\r\n [cardOptions]=\"contextMenuOptions\"\r\n (contextMenuClick)=\"onMenuClick($event)\"\r\n [cardPosition]=\"cardPosition\"\r\n ></lib-right-click-card>\r\n}\r\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: DoughnutChart, isStandalone: true, selector: "lib-doughnut-chart", inputs: { config: "config", theme: "theme", events: "events", contextMenuOptions: "contextMenuOptions", showContextMenu: "showContextMenu" }, outputs: { contextMenuClick: "contextMenuClick", chartEvent: "chartEvent" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"contextMenuOptions\"\n (contextMenuClick)=\"onMenuClick($event)\"\n [cardPosition]=\"cardPosition\"\n ></lib-right-click-card>\n}\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1166
1163
  }
1167
1164
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DoughnutChart, decorators: [{
1168
1165
  type: Component,
1169
- args: [{ selector: 'lib-doughnut-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n class=\"chart-container\"\r\n (chartInit)=\"onChartInit($event)\"\r\n></div>\r\n@if (openCard) {\r\n <lib-right-click-card\r\n [cardOptions]=\"contextMenuOptions\"\r\n (contextMenuClick)=\"onMenuClick($event)\"\r\n [cardPosition]=\"cardPosition\"\r\n ></lib-right-click-card>\r\n}\r\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"] }]
1166
+ args: [{ selector: 'lib-doughnut-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"contextMenuOptions\"\n (contextMenuClick)=\"onMenuClick($event)\"\n [cardPosition]=\"cardPosition\"\n ></lib-right-click-card>\n}\n", styles: [".chart-container{width:100%;height:100%;position:relative}\n"] }]
1170
1167
  }], ctorParameters: () => [{ type: Charts }, { type: i0.ChangeDetectorRef }], propDecorators: { config: [{
1171
1168
  type: Input
1172
1169
  }], theme: [{
@@ -1231,11 +1228,11 @@ class StackedAreaChart {
1231
1228
  };
1232
1229
  }
1233
1230
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: StackedAreaChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
1234
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: StackedAreaChart, isStandalone: true, selector: "lib-stacked-area-chart", inputs: { data: "data", title: "title" }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\r\n echarts\r\n class=\"chart-container\"\r\n [options]=\"chartOption\"\r\n ></div>", styles: [".chart-container{width:100%;height:400px}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1231
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: StackedAreaChart, isStandalone: true, selector: "lib-stacked-area-chart", inputs: { data: "data", title: "title" }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\n echarts\n class=\"chart-container\"\n [options]=\"chartOption\"\n ></div>", styles: [".chart-container{width:100%;height:400px}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1235
1232
  }
1236
1233
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: StackedAreaChart, decorators: [{
1237
1234
  type: Component,
1238
- args: [{ selector: 'lib-stacked-area-chart', imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], template: "<div\r\n echarts\r\n class=\"chart-container\"\r\n [options]=\"chartOption\"\r\n ></div>", styles: [".chart-container{width:100%;height:400px}\n"] }]
1235
+ args: [{ selector: 'lib-stacked-area-chart', imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], template: "<div\n echarts\n class=\"chart-container\"\n [options]=\"chartOption\"\n ></div>", styles: [".chart-container{width:100%;height:400px}\n"] }]
1239
1236
  }], propDecorators: { data: [{
1240
1237
  type: Input
1241
1238
  }], title: [{
@@ -1321,20 +1318,351 @@ class AreaChart {
1321
1318
  }
1322
1319
  }
1323
1320
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AreaChart, deps: [], target: i0.ɵɵFactoryTarget.Component });
1324
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: AreaChart, isStandalone: true, selector: "lib-area-chart", inputs: { config: "config", theme: "theme" }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n \r\n class=\"chart-container\"\r\n>\r\n</div>\r\n", styles: [".chart-container{width:100%;height:400px}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1321
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: AreaChart, isStandalone: true, selector: "lib-area-chart", inputs: { config: "config", theme: "theme" }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n \n class=\"chart-container\"\n>\n</div>\n", styles: [".chart-container{width:100%;height:400px}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }] });
1325
1322
  }
1326
1323
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: AreaChart, decorators: [{
1327
1324
  type: Component,
1328
- args: [{ selector: 'lib-area-chart', imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], template: "<div\r\n echarts\r\n [options]=\"chartOption\"\r\n [theme]=\"theme\"\r\n \r\n class=\"chart-container\"\r\n>\r\n</div>\r\n", styles: [".chart-container{width:100%;height:400px}\n"] }]
1325
+ args: [{ selector: 'lib-area-chart', imports: [NgxEchartsDirective], providers: [provideEchartsCore({ echarts })], template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n \n class=\"chart-container\"\n>\n</div>\n", styles: [".chart-container{width:100%;height:400px}\n"] }]
1329
1326
  }], propDecorators: { config: [{
1330
1327
  type: Input
1331
1328
  }], theme: [{
1332
1329
  type: Input
1333
1330
  }] } });
1334
1331
 
1332
+ echarts.use([CustomChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer]);
1333
+ class CustomChartComponent {
1334
+ chartService;
1335
+ cdr;
1336
+ config;
1337
+ theme;
1338
+ events = [];
1339
+ contextMenuOptions = [];
1340
+ contextMenuClick = new EventEmitter();
1341
+ chartEvent = new EventEmitter();
1342
+ cardPosition = { x: 0, y: 0 };
1343
+ openCard = false;
1344
+ chartOption;
1345
+ chartInstance;
1346
+ constructor(chartService, cdr) {
1347
+ this.chartService = chartService;
1348
+ this.cdr = cdr;
1349
+ }
1350
+ onChartInit(ec) {
1351
+ this.chartInstance = ec;
1352
+ this.buildOption();
1353
+ this.bindEvents();
1354
+ }
1355
+ ngOnChanges(changes) {
1356
+ if (!this.config)
1357
+ return;
1358
+ if (changes['theme'] && this.chartInstance) {
1359
+ this.chartInstance.dispose();
1360
+ }
1361
+ this.buildOption();
1362
+ }
1363
+ onMenuClick(item) {
1364
+ this.contextMenuClick.emit(item);
1365
+ this.closeCard();
1366
+ }
1367
+ closeCard() {
1368
+ this.openCard = false;
1369
+ }
1370
+ bindEvents() {
1371
+ if (!this.chartInstance)
1372
+ return;
1373
+ this.chartInstance.off();
1374
+ /* ---- existing chart events ---- */
1375
+ this.events.forEach((eventName) => {
1376
+ if (eventName === 'contextmenu')
1377
+ return;
1378
+ this.chartInstance.on(eventName, (params) => {
1379
+ this.chartEvent.emit({
1380
+ type: eventName,
1381
+ data: params,
1382
+ });
1383
+ });
1384
+ });
1385
+ /* ---- RIGHT CLICK ANYWHERE IN GRID ---- */
1386
+ const zr = this.chartInstance.getZr();
1387
+ zr.off('contextmenu');
1388
+ zr.on('contextmenu', (event) => {
1389
+ event.event.preventDefault();
1390
+ const point = [event.offsetX, event.offsetY];
1391
+ // check if click is inside grid
1392
+ if (!this.chartInstance.containPixel({ gridIndex: 0 }, point))
1393
+ return;
1394
+ const container = this.chartInstance.getDom();
1395
+ const rect = container.getBoundingClientRect();
1396
+ this.cardPosition = {
1397
+ x: event.event.clientX - rect.left,
1398
+ y: event.event.clientY - rect.top,
1399
+ };
1400
+ this.openCard = true;
1401
+ this.cdr.markForCheck();
1402
+ this.chartEvent.emit({
1403
+ type: 'contextmenu',
1404
+ data: event,
1405
+ });
1406
+ });
1407
+ }
1408
+ convertTimeToNumber(time) {
1409
+ const [h, m] = time.split(':').map(Number);
1410
+ return h + m / 60;
1411
+ }
1412
+ renderBlock = (isShift = false) => (params, api) => {
1413
+ const categoryIndex = api.value(0);
1414
+ const start = api.coord([api.value(1), categoryIndex]);
1415
+ const end = api.coord([api.value(2), categoryIndex]);
1416
+ const baseHeight = api.size([0, 1])[1];
1417
+ const height = baseHeight * (isShift ? (this.config.shiftHeight ?? 1) : (this.config.barHeight ?? 0.6));
1418
+ return {
1419
+ type: 'rect',
1420
+ shape: {
1421
+ x: start[0],
1422
+ y: start[1] - height / 2,
1423
+ width: end[0] - start[0],
1424
+ height: height,
1425
+ },
1426
+ style: api.style(),
1427
+ };
1428
+ };
1429
+ buildLegend() {
1430
+ const groups = this.config.categories.map((cat) => {
1431
+ return { title: cat, key: cat };
1432
+ });
1433
+ const legends = [];
1434
+ let topOffset = 0;
1435
+ groups.forEach((group) => {
1436
+ const items = this.config.tracks.find((track) => track.category === group.key)?.legend;
1437
+ if (!items || !items.length)
1438
+ return;
1439
+ const names = [
1440
+ { name: group.title, icon: 'none', itemStyle: { opacity: 0 } },
1441
+ ...items.map((i) => ({
1442
+ name: i.name,
1443
+ itemStyle: { color: i.color },
1444
+ })),
1445
+ ];
1446
+ legends.push({
1447
+ top: topOffset,
1448
+ left: 0,
1449
+ orient: 'horizontal',
1450
+ icon: 'roundRect',
1451
+ itemGap: 16,
1452
+ itemWidth: 12,
1453
+ itemHeight: 12,
1454
+ data: names,
1455
+ formatter: (name) => {
1456
+ if (name === group.title) {
1457
+ return `{title|${name}:}`;
1458
+ }
1459
+ return name;
1460
+ },
1461
+ textStyle: {
1462
+ fontSize: 14,
1463
+ rich: {
1464
+ title: {
1465
+ fontWeight: 'bold',
1466
+ padding: [0, 6, 0, -12],
1467
+ },
1468
+ },
1469
+ },
1470
+ });
1471
+ topOffset += 30;
1472
+ });
1473
+ return legends;
1474
+ }
1475
+ buildOption() {
1476
+ if (!this.config?.categories || !this.config?.tracks)
1477
+ return;
1478
+ const series = [];
1479
+ const categories = this.config.categories;
1480
+ /* ---------------- SHIFT DATA ---------------- */
1481
+ if (this.config.shifts?.length) {
1482
+ const shiftData = [];
1483
+ (this.config.shifts || []).forEach((s) => {
1484
+ s.items.forEach((p) => {
1485
+ shiftData.push({
1486
+ value: [
1487
+ categories.indexOf(s.category),
1488
+ this.convertTimeToNumber(p.start),
1489
+ this.convertTimeToNumber(p.end),
1490
+ ],
1491
+ itemStyle: {
1492
+ color: this.config.shiftColor ?? '#F0F0F0',
1493
+ },
1494
+ });
1495
+ });
1496
+ });
1497
+ if (shiftData.length) {
1498
+ series.push({
1499
+ name: 'Shift',
1500
+ type: 'custom',
1501
+ renderItem: this.renderBlock(true),
1502
+ silent: true,
1503
+ z: 0,
1504
+ encode: { x: [1, 2], y: 0 },
1505
+ data: shiftData,
1506
+ });
1507
+ }
1508
+ }
1509
+ /* ---------------- TRACK SERIES ---------------- */
1510
+ this.config.tracks.forEach((track) => {
1511
+ track.items.forEach((item) => {
1512
+ series.push({ name: track.category, type: 'custom', renderItem: () => { }, data: [] });
1513
+ series.push({
1514
+ name: item.type,
1515
+ type: 'custom',
1516
+ renderItem: this.renderBlock(false),
1517
+ encode: { x: [1, 2], y: 0 },
1518
+ z: 2,
1519
+ data: [
1520
+ {
1521
+ ...item,
1522
+ value: [
1523
+ categories.indexOf(track.category),
1524
+ this.convertTimeToNumber(item.start),
1525
+ this.convertTimeToNumber(item.end),
1526
+ ],
1527
+ itemStyle: {
1528
+ color: track.legend.find((l) => l.name === item.type)?.color,
1529
+ },
1530
+ type: item.type,
1531
+ },
1532
+ ],
1533
+ });
1534
+ });
1535
+ });
1536
+ /* -------- ACTIVITY LINE -------- */
1537
+ if (this.config.activity?.length) {
1538
+ (this.config.activity || []).forEach((cat) => {
1539
+ const activityData = [];
1540
+ const categoryIndex = this.config.categories.indexOf(cat.category);
1541
+ if (categoryIndex === -1)
1542
+ return;
1543
+ cat.items.forEach((p, i) => {
1544
+ const y = categoryIndex +
1545
+ p.value * (this.config.barHeight ?? 0.6) +
1546
+ (1 - (this.config.barHeight ?? 0.6)) / 2;
1547
+ activityData.push([this.convertTimeToNumber(p.time), y]);
1548
+ });
1549
+ series.push({
1550
+ name: cat.name,
1551
+ type: 'line',
1552
+ symbol: 'none',
1553
+ yAxisIndex: 1,
1554
+ z: 3,
1555
+ lineStyle: {
1556
+ width: 1,
1557
+ color: '#C8DFF9',
1558
+ },
1559
+ data: activityData,
1560
+ });
1561
+ });
1562
+ }
1563
+ /* ---------------- LEGEND ---------------- */
1564
+ const legendItems = [];
1565
+ this.config.tracks.forEach((track) => {
1566
+ track.legend.forEach((l) => {
1567
+ legendItems.push({
1568
+ name: l.name,
1569
+ icon: 'roundRect',
1570
+ itemStyle: { color: l.color },
1571
+ });
1572
+ });
1573
+ });
1574
+ /* ---------------- CHART OPTION ---------------- */
1575
+ this.chartOption = {
1576
+ tooltip: {
1577
+ trigger: 'item',
1578
+ backgroundColor: 'transparent',
1579
+ borderWidth: 0,
1580
+ padding: 0,
1581
+ extraCssText: 'box-shadow:none;',
1582
+ formatter: (params) => this.chartService.timelineChartTooltipFormatter(params),
1583
+ },
1584
+ legend: this.buildLegend(),
1585
+ grid: {
1586
+ left: 0,
1587
+ right: 0,
1588
+ bottom: 0,
1589
+ },
1590
+ xAxis: {
1591
+ type: 'value',
1592
+ min: this.config.startHour ?? 0,
1593
+ max: this.config.endHour ?? 24,
1594
+ axisLine: {
1595
+ show: false,
1596
+ },
1597
+ axisTick: {
1598
+ show: false,
1599
+ },
1600
+ splitLine: {
1601
+ lineStyle: {
1602
+ width: 0.5,
1603
+ color: '#C0C2C5',
1604
+ },
1605
+ },
1606
+ minorSplitLine: {
1607
+ show: true,
1608
+ lineStyle: {
1609
+ width: 0.2,
1610
+ color: '#DADBDC',
1611
+ },
1612
+ },
1613
+ minorTick: { splitNumber: 4 },
1614
+ interval: 1,
1615
+ axisLabel: {
1616
+ formatter: (val) => `${val}:00`,
1617
+ },
1618
+ },
1619
+ yAxis: [
1620
+ {
1621
+ type: 'category',
1622
+ data: categories,
1623
+ axisLine: {
1624
+ show: false,
1625
+ },
1626
+ },
1627
+ {
1628
+ type: 'value',
1629
+ min: 0,
1630
+ max: categories.length,
1631
+ show: false,
1632
+ },
1633
+ ],
1634
+ series,
1635
+ };
1636
+ }
1637
+ ngOnDestroy() {
1638
+ this.chartInstance?.dispose();
1639
+ }
1640
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CustomChartComponent, deps: [{ token: Charts }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1641
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CustomChartComponent, isStandalone: true, selector: "lib-custom-chart", inputs: { config: "config", theme: "theme", events: "events", contextMenuOptions: "contextMenuOptions" }, outputs: { contextMenuClick: "contextMenuClick", chartEvent: "chartEvent" }, host: { listeners: { "document:click": "closeCard()" } }, providers: [provideEchartsCore({ echarts })], usesOnChanges: true, ngImport: i0, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"contextMenuOptions\"\n (contextMenuClick)=\"onMenuClick($event)\"\n [cardPosition]=\"cardPosition\"\n ></lib-right-click-card>\n}\n", styles: [".chart-container{width:100%;height:100%}\n"], dependencies: [{ kind: "directive", type: NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: RightClickCard, selector: "lib-right-click-card", inputs: ["cardPosition", "cardOptions"], outputs: ["contextMenuClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1642
+ }
1643
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CustomChartComponent, decorators: [{
1644
+ type: Component,
1645
+ args: [{ selector: 'lib-custom-chart', imports: [NgxEchartsDirective, RightClickCard], providers: [provideEchartsCore({ echarts })], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div\n echarts\n [options]=\"chartOption\"\n [theme]=\"theme\"\n class=\"chart-container\"\n (chartInit)=\"onChartInit($event)\"\n></div>\n@if (openCard) {\n <lib-right-click-card\n [cardOptions]=\"contextMenuOptions\"\n (contextMenuClick)=\"onMenuClick($event)\"\n [cardPosition]=\"cardPosition\"\n ></lib-right-click-card>\n}\n", styles: [".chart-container{width:100%;height:100%}\n"] }]
1646
+ }], ctorParameters: () => [{ type: Charts }, { type: i0.ChangeDetectorRef }], propDecorators: { config: [{
1647
+ type: Input
1648
+ }], theme: [{
1649
+ type: Input
1650
+ }], events: [{
1651
+ type: Input
1652
+ }], contextMenuOptions: [{
1653
+ type: Input
1654
+ }], contextMenuClick: [{
1655
+ type: Output
1656
+ }], chartEvent: [{
1657
+ type: Output
1658
+ }], closeCard: [{
1659
+ type: HostListener,
1660
+ args: ['document:click']
1661
+ }] } });
1662
+
1335
1663
  /**
1336
1664
  * Generated bundle index. Do not edit.
1337
1665
  */
1338
1666
 
1339
- export { AreaChart, BarChart, Charts, DoughnutChart, LinesChart, PieChart, RightClickCard, StackedAreaChart };
1667
+ export { AreaChart, BarChart, Charts, CustomChartComponent, DoughnutChart, LinesChart, PieChart, RightClickCard, StackedAreaChart };
1340
1668
  //# sourceMappingURL=cats-charts.mjs.map