@agorapulse/ui-charts 20.1.16 → 20.1.18

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.
@@ -1,123 +1,8 @@
1
- import * as Highcharts from 'highcharts';
2
- import { numberFormat, setOptions, dateFormat, Chart } from 'highcharts';
3
1
  import * as i0 from '@angular/core';
4
- import { Input, ViewChild, Directive, Component, input, EventEmitter, Output, effect, ChangeDetectionStrategy, signal, afterNextRender } from '@angular/core';
2
+ import { inject, DestroyRef, ElementRef, input, signal, afterNextRender, effect, Directive, ChangeDetectionStrategy, Component, output } from '@angular/core';
3
+ import { setOptions, Chart, numberFormat } from 'highcharts';
4
+ import { isPlainObject, cloneDeep, round } from 'es-toolkit';
5
5
  import { mapChart } from 'highcharts/highmaps';
6
- import * as i1 from '@angular/common';
7
- import { CommonModule } from '@angular/common';
8
- import { MatDividerModule } from '@angular/material/divider';
9
- import * as i2 from '@angular/material/list';
10
- import { MatListModule } from '@angular/material/list';
11
-
12
- /* eslint-disable @typescript-eslint/ban-ts-comment */
13
- const borderRadiusPlugin = function (H) {
14
- if (H.borderRadiusPlugininitialized) {
15
- return;
16
- }
17
- H.borderRadiusPlugininitialized = true;
18
- H.wrap(H.seriesTypes.column.prototype, 'translate', function (proceed) {
19
- // @ts-ignore
20
- const options = this.options;
21
- const topMargin = options.topMargin || 0;
22
- const bottomMargin = options.bottomMargin || 0;
23
- const borderRadiusTopLeftSettings = options.borderRadiusTopLeft;
24
- const borderRadiusTopRightSettings = options.borderRadiusTopRight;
25
- const borderRadiusBottomLeftSettings = options.borderRadiusBottomLeft;
26
- const borderRadiusBottomRightSettings = options.borderRadiusBottomRight;
27
- // @ts-ignore
28
- proceed.call(this);
29
- // @ts-ignore
30
- if (!this.points) {
31
- return;
32
- }
33
- if (borderRadiusTopLeftSettings ||
34
- borderRadiusTopRightSettings ||
35
- borderRadiusBottomLeftSettings ||
36
- borderRadiusBottomRightSettings) {
37
- // @ts-ignore
38
- this.points.forEach(function (point) {
39
- roundPoint(borderRadiusTopLeftSettings, borderRadiusTopRightSettings, borderRadiusBottomLeftSettings, borderRadiusBottomRightSettings, point, H, topMargin, bottomMargin);
40
- });
41
- }
42
- });
43
- };
44
- function roundPoint(borderRadiusTopLeftSettings, borderRadiusTopRightSettings, borderRadiusBottomLeftSettings, borderRadiusBottomRightSettings, point, H, topMargin, bottomMargin) {
45
- const w = point.shapeArgs.width;
46
- const h = point.shapeArgs.height;
47
- const x = point.shapeArgs.x;
48
- const y = point.shapeArgs.y;
49
- const borderRadiusTopLeft = borderRadiusTopLeftSettings?.length
50
- ? borderRadiusTopLeftSettings[point.index]
51
- : borderRadiusTopLeftSettings || 0;
52
- const borderRadiusTopRight = borderRadiusTopRightSettings?.length
53
- ? borderRadiusTopRightSettings[point.index]
54
- : borderRadiusTopRightSettings || 0;
55
- const borderRadiusBottomLeft = borderRadiusBottomLeftSettings?.length
56
- ? borderRadiusBottomLeftSettings[point.index]
57
- : borderRadiusBottomLeftSettings || 0;
58
- const borderRadiusBottomRight = borderRadiusBottomRightSettings?.length
59
- ? borderRadiusBottomRightSettings[point.index]
60
- : borderRadiusBottomRightSettings || 0;
61
- let radiusTopLeft = H.relativeLength(borderRadiusTopLeft, w);
62
- let radiusTopRight = H.relativeLength(borderRadiusTopRight, w);
63
- let radiusBottomRight = H.relativeLength(borderRadiusBottomRight, w);
64
- let radiusBottomLeft = H.relativeLength(borderRadiusBottomLeft, w);
65
- const maxR = Math.min(w, h) / 2;
66
- radiusTopLeft = radiusTopLeft > maxR ? maxR : radiusTopLeft;
67
- radiusTopRight = radiusTopRight > maxR ? maxR : radiusTopRight;
68
- radiusBottomRight = radiusBottomRight > maxR ? maxR : radiusBottomRight;
69
- radiusBottomLeft = radiusBottomLeft > maxR ? maxR : radiusBottomLeft;
70
- point.dlBox = point.shapeArgs;
71
- point.shapeType = 'path';
72
- point.shapeArgs = {
73
- d: [
74
- 'M',
75
- x + radiusTopLeft,
76
- y + topMargin,
77
- 'L',
78
- x + w - radiusTopRight,
79
- y + topMargin,
80
- 'C',
81
- x + w - radiusTopRight / 2,
82
- y,
83
- x + w,
84
- y + radiusTopRight / 2,
85
- x + w,
86
- y + radiusTopRight,
87
- 'L',
88
- x + w,
89
- y + h - radiusBottomRight,
90
- 'C',
91
- x + w,
92
- y + h - radiusBottomRight / 2,
93
- x + w - radiusBottomRight / 2,
94
- y + h,
95
- x + w - radiusBottomRight,
96
- y + h + bottomMargin,
97
- 'L',
98
- x + radiusBottomLeft,
99
- y + h + bottomMargin,
100
- 'C',
101
- x + radiusBottomLeft / 2,
102
- y + h,
103
- x,
104
- y + h - radiusBottomLeft / 2,
105
- x,
106
- y + h - radiusBottomLeft,
107
- 'L',
108
- x,
109
- y + radiusTopLeft,
110
- 'C',
111
- x,
112
- y + radiusTopLeft / 2,
113
- x + radiusTopLeft / 2,
114
- y,
115
- x + radiusTopLeft,
116
- y,
117
- 'Z',
118
- ],
119
- };
120
- }
121
6
 
122
7
  var ChartColor;
123
8
  (function (ChartColor) {
@@ -233,121 +118,72 @@ class ChartColors {
233
118
  }
234
119
 
235
120
  class AbstractChartComponent {
236
- chartRef;
237
- chartOptions = {}; // https://api.highcharts.com/highcharts/
238
- color = ChartColor.ElectricBlue;
239
- labelDateFormat = '%m/%d';
240
- locale = 'en';
241
- series = [];
121
+ destroyRef = inject(DestroyRef);
122
+ /** Highcharts renders into the host element directly. */
123
+ hostElement = inject(ElementRef).nativeElement;
124
+ chartOptions = input({}, ...(ngDevMode ? [{ debugName: "chartOptions" }] : []));
125
+ color = input(ChartColor.ElectricBlue, ...(ngDevMode ? [{ debugName: "color" }] : []));
126
+ labelDateFormat = input('%m/%d', ...(ngDevMode ? [{ debugName: "labelDateFormat" }] : []));
127
+ locale = input('en', ...(ngDevMode ? [{ debugName: "locale" }] : []));
242
128
  chart;
129
+ viewReady = signal(false, ...(ngDevMode ? [{ debugName: "viewReady" }] : []));
243
130
  resizeObserver;
244
- ngOnChanges(changes) {
245
- if ((changes.series && !changes.series.firstChange) ||
246
- (changes.color && !changes.color.firstChange) ||
247
- (changes.chartOptions && !changes.chartOptions.firstChange) ||
248
- (changes.locale && !changes.locale.firstChange) ||
249
- (changes.metricFormat && !changes.metricFormat.firstChange)) {
250
- this.initChart();
251
- }
252
- }
253
- ngAfterViewInit() {
254
- this.resizeObserver = new ResizeObserver(() => {
255
- const el = this.chartRef?.nativeElement;
256
- if (!el || el.clientWidth === 0) {
131
+ constructor() {
132
+ afterNextRender(() => {
133
+ this.resizeObserver = new ResizeObserver(() => this.onResize());
134
+ this.resizeObserver.observe(this.hostElement);
135
+ this.viewReady.set(true);
136
+ });
137
+ // Eager init on view-ready; ResizeObserver reflows as the container grows.
138
+ effect(() => {
139
+ if (!this.viewReady())
257
140
  return;
258
- }
259
- if (this.chart) {
260
- this.chart.reflow();
261
- }
262
- else if (this.series?.length) {
263
- this.initChart();
264
- }
141
+ this.rebuild();
265
142
  });
266
- this.resizeObserver.observe(this.chartRef.nativeElement);
143
+ this.destroyRef.onDestroy(() => {
144
+ this.resizeObserver?.disconnect();
145
+ this.chart?.destroy();
146
+ });
147
+ }
148
+ onResize() {
149
+ if (this.chart) {
150
+ this.chart.reflow();
151
+ }
152
+ else if (this.hostElement.clientWidth > 0 && this.series().length) {
153
+ this.rebuild();
154
+ }
267
155
  }
268
- ngOnDestroy() {
269
- this.resizeObserver?.disconnect();
156
+ rebuild() {
270
157
  this.chart?.destroy();
158
+ this.chart = undefined;
159
+ this.initChart();
271
160
  }
272
161
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AbstractChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
273
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.18", type: AbstractChartComponent, isStandalone: true, inputs: { chartOptions: "chartOptions", color: "color", labelDateFormat: "labelDateFormat", locale: "locale", series: "series" }, viewQueries: [{ propertyName: "chartRef", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0 });
162
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.18", type: AbstractChartComponent, isStandalone: true, inputs: { chartOptions: { classPropertyName: "chartOptions", publicName: "chartOptions", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, labelDateFormat: { classPropertyName: "labelDateFormat", publicName: "labelDateFormat", isSignal: true, isRequired: false, transformFunction: null }, locale: { classPropertyName: "locale", publicName: "locale", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
274
163
  }
275
164
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AbstractChartComponent, decorators: [{
276
165
  type: Directive
277
- }], propDecorators: { chartRef: [{
278
- type: ViewChild,
279
- args: ['chart']
280
- }], chartOptions: [{
281
- type: Input
282
- }], color: [{
283
- type: Input
284
- }], labelDateFormat: [{
285
- type: Input
286
- }], locale: [{
287
- type: Input
288
- }], series: [{
289
- type: Input
290
- }] } });
166
+ }], ctorParameters: () => [], propDecorators: { chartOptions: [{ type: i0.Input, args: [{ isSignal: true, alias: "chartOptions", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], labelDateFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelDateFormat", required: false }] }], locale: [{ type: i0.Input, args: [{ isSignal: true, alias: "locale", required: false }] }] } });
291
167
 
292
- /**
293
- * Builds Highcharts locale options (lang + tooltip date formats) from a locale string.
294
- * Uses the browser's Intl API to generate translated month/weekday names and number formatting rules.
295
- */
168
+ /** `lang.locale` drives Intl-based weekday/month/number formatting; we only override the tooltip date order. */
296
169
  function buildHighchartsLocaleOptions(locale) {
297
- const { decimalPoint, thousandsSep } = buildNumberSeparators(locale);
170
+ const dayFormat = locale === 'en' ? '%A, %b %e, %Y' : '%A %e %b %Y';
298
171
  return {
299
- lang: {
300
- decimalPoint,
301
- thousandsSep,
302
- weekdays: buildWeekdays(locale),
303
- shortMonths: buildShortMonths(locale),
304
- },
172
+ lang: { locale },
305
173
  tooltip: {
306
174
  dateTimeLabelFormats: {
307
- day: locale === 'en' ? '%A, %b %e, %Y' : '%A %e %b %Y',
308
- week: locale === 'en' ? '%A, %b %e, %Y' : '%A %e %b %Y',
175
+ day: dayFormat,
176
+ week: dayFormat,
309
177
  },
310
178
  },
311
179
  };
312
180
  }
313
- function buildNumberSeparators(locale) {
314
- const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);
315
- const decimalPoint = parts.find(p => p.type === 'decimal')?.value ?? '.';
316
- const thousandsSep = parts.find(p => p.type === 'group')?.value ?? ',';
317
- return { decimalPoint, thousandsSep };
318
- }
319
- function buildWeekdays(locale) {
320
- const formatter = new Intl.DateTimeFormat(locale, { weekday: 'long' });
321
- // Jan 4, 1970 is a Sunday
322
- return Array.from({ length: 7 }, (_, i) => {
323
- const name = formatter.format(new Date(1970, 0, 4 + i));
324
- return name.charAt(0).toUpperCase() + name.slice(1);
325
- });
326
- }
327
- function buildShortMonths(locale) {
328
- const formatter = new Intl.DateTimeFormat(locale, { month: 'short' });
329
- return Array.from({ length: 12 }, (_, i) => {
330
- const name = formatter.format(new Date(2000, i, 1));
331
- return name.charAt(0).toUpperCase() + name.slice(1);
332
- });
333
- }
334
181
 
182
+ const FONT_FAMILY = "Averta, 'Open Sans', Helvetica, sans-serif";
183
+ const LABEL_FONT_SIZE = '12px';
335
184
  class ChartOptions {
336
185
  static DEFAULT_DATE_FORMAT = '%A, %b %e, %Y';
337
186
  static DEFAULT_OPTIONS = {
338
- /*lang: {
339
- decimalPoint: (manager && manager.locale !== 'en') ? ',' : '.',
340
- resetZoom: resetZoomLabel,
341
- resetZoomTitle: resetZoomHtmlTitle,
342
- shortMonths: [
343
- shortJanuary, shortFebruary, shortMarch, shortApril, shortMay, shortJune,
344
- shortJuly, shortAugust, shortSeptember, shortOctober, shortNovember, shortDecember
345
- ],
346
- thousandsSep: (manager && manager.locale !== 'en') ? ' ' : ',',
347
- weekdays: this.weekDays,
348
- zoomIn: zoomInHtmlTitle,
349
- zoomOut: zoomOutHtmlTitle
350
- },*/
351
187
  chart: {
352
188
  spacingRight: 20,
353
189
  zooming: {
@@ -358,34 +194,22 @@ class ChartOptions {
358
194
  r: 4,
359
195
  style: {
360
196
  color: ChartColors.GREY_COLORS[100],
361
- fontSize: '12px',
197
+ fontSize: LABEL_FONT_SIZE,
362
198
  },
363
199
  states: {
364
- hover: {
365
- fill: ChartColors.GREY_COLORS[5],
366
- },
200
+ hover: { fill: ChartColors.GREY_COLORS[5] },
367
201
  },
368
202
  },
369
203
  },
370
204
  },
371
- panning: {
372
- enabled: true,
373
- },
205
+ panning: { enabled: true },
374
206
  panKey: 'shift',
375
- style: {
376
- fontFamily: "Averta, 'Open Sans', Helvetica, sans-serif",
377
- },
207
+ style: { fontFamily: FONT_FAMILY },
378
208
  },
379
209
  colorAxis: {
380
- labels: {
381
- style: {
382
- color: ChartColors.GREY_COLORS[60],
383
- },
384
- },
385
- },
386
- credits: {
387
- enabled: false,
210
+ labels: { style: { color: ChartColors.GREY_COLORS[60] } },
388
211
  },
212
+ credits: { enabled: false },
389
213
  legend: {
390
214
  borderWidth: 0,
391
215
  itemStyle: {
@@ -401,21 +225,15 @@ class ChartOptions {
401
225
  plotOptions: {
402
226
  series: {
403
227
  states: {
404
- hover: {
405
- brightness: 0,
406
- },
228
+ hover: { brightness: 0 },
407
229
  },
408
230
  connectNulls: true,
409
231
  },
410
232
  },
411
233
  navigation: {
412
- buttonOptions: {
413
- y: 0,
414
- },
415
- },
416
- title: {
417
- text: undefined,
234
+ buttonOptions: { y: 0 },
418
235
  },
236
+ title: { text: undefined },
419
237
  tooltip: {
420
238
  backgroundColor: ChartColors.WHITE_COLOR,
421
239
  borderRadius: 4,
@@ -432,22 +250,20 @@ class ChartOptions {
432
250
  shared: true,
433
251
  useHTML: true,
434
252
  headerFormat: `<div style="border-bottom: 1px solid ${ChartColors.GREY_COLORS[10]}; padding: 0 8px 7px">` +
435
- `<div style="white-space: wrap; font-size: 12px; color: ${ChartColors.GREY_COLORS[60]}">{point.key}</div></div>`,
253
+ `<div style="white-space: wrap; font-size: ${LABEL_FONT_SIZE}; color: ${ChartColors.GREY_COLORS[60]}">{point.key}</div></div>`,
436
254
  pointFormat: `<div style="font-size: 14px; color: ${ChartColors.GREY_COLORS[100]}; margin: 6px 8px 0 8px;">` +
437
- '<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.y}</b> {point.custom.details}</div>',
255
+ '<span style="color:{point.color}">●</span> {series.name}: <b>{point.y}</b> {point.custom.details}</div>',
438
256
  },
439
257
  xAxis: {
440
258
  gridLineColor: ChartColors.GREY_COLORS[10],
441
259
  lineColor: ChartColors.GREY_COLORS[10],
442
260
  tickColor: ChartColors.GREY_COLORS[10],
443
261
  gridLineWidth: 1,
444
- title: {
445
- text: null,
446
- },
262
+ title: { text: null },
447
263
  labels: {
448
264
  style: {
449
265
  color: ChartColors.GREY_COLORS[85],
450
- fontSize: '12px',
266
+ fontSize: LABEL_FONT_SIZE,
451
267
  },
452
268
  },
453
269
  },
@@ -456,19 +272,12 @@ class ChartOptions {
456
272
  gridLineColor: ChartColors.GREY_COLORS[10],
457
273
  lineColor: ChartColors.GREY_COLORS[10],
458
274
  gridLineWidth: 1,
459
- title: {
460
- text: undefined,
461
- },
275
+ title: { text: undefined },
462
276
  labels: {
463
- formatter: function () {
464
- if (typeof this.value === 'string') {
465
- return this.value;
466
- }
467
- return numberFormat(this.value, -1);
468
- },
277
+ // Highcharts auto-formats per `lang.locale`.
469
278
  style: {
470
279
  color: ChartColors.GREY_COLORS[85],
471
- fontSize: '12px',
280
+ fontSize: LABEL_FONT_SIZE,
472
281
  },
473
282
  },
474
283
  },
@@ -479,18 +288,7 @@ class ChartOptions {
479
288
  return mergeDeep(mergeDeep(ChartOptions.DEFAULT_OPTIONS, localeOptions), options);
480
289
  }
481
290
  static configure(series, options, color, labelDateFormat) {
482
- // Configure axis
483
- options.xAxis = mergeDeep({
484
- labels: {
485
- formatter: function () {
486
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
487
- // @ts-ignore
488
- return dateFormat(labelDateFormat ?? '%m/%d', this.value);
489
- },
490
- },
491
- //minTickInterval: 24 * 60 * 60 * 1000 // One day
492
- }, options.xAxis);
493
- // Configure series
291
+ options.xAxis = mergeDeep({ labels: { format: `{value:${labelDateFormat ?? '%m/%d'}}` } }, options.xAxis);
494
292
  if (series?.length) {
495
293
  options.series = series;
496
294
  if (options.legend) {
@@ -499,114 +297,23 @@ class ChartOptions {
499
297
  options.colors = ChartColors.getColors(series.length, color);
500
298
  }
501
299
  }
502
- static redrawWithHighestEdgesRounded(chart) {
503
- chart.series.forEach((serie, serieIndex, arr) => {
504
- ChartOptions.roundHighestSerie(arr, serie.options, serieIndex);
505
- });
506
- chart.redraw(true);
507
- }
508
- static roundHighestSerie(series, serie, serieIndex) {
509
- const roundedTopMap = [];
510
- const roundedBottomMap = [];
511
- if (serie.data) {
512
- serie.data.forEach((point, columnIndex) => {
513
- const pointValue = ChartOptions.getPointValue(point);
514
- const pointX = ChartOptions.getPointX(point);
515
- const isNegative = pointValue !== null && pointValue < 0;
516
- if (isNegative) {
517
- // Negative bars go downward: the visual tip is the physical bottom.
518
- // Round bottom corners if no higher-index visible series has a negative value here
519
- // (meaning this series is the bottommost segment of the negative stack).
520
- const isBottommost = series.slice(serieIndex + 1).every(otherSerie => {
521
- if (!otherSerie.visible)
522
- return true;
523
- const otherPoint = ChartOptions.findPointAtAbscissa(otherSerie.options.data, pointX, columnIndex);
524
- if (otherPoint === undefined)
525
- return true;
526
- const val = ChartOptions.getPointValue(otherPoint);
527
- return val === null || val >= 0;
528
- });
529
- roundedTopMap[columnIndex] = 0;
530
- roundedBottomMap[columnIndex] = isBottommost ? 100 : 0;
531
- }
532
- else {
533
- // Positive bars go upward: the visual tip is the physical top.
534
- // Round top corners if all lower-index visible series are 0/missing here
535
- // (meaning this series is the topmost segment of the positive stack).
536
- const isTopmost = series.slice(0, serieIndex).every(otherSerie => {
537
- if (!otherSerie.visible)
538
- return true;
539
- const otherPoint = ChartOptions.findPointAtAbscissa(otherSerie.options.data, pointX, columnIndex);
540
- return otherPoint === undefined || ChartOptions.getPointValue(otherPoint) === 0;
541
- });
542
- roundedTopMap[columnIndex] = isTopmost ? 100 : 0;
543
- roundedBottomMap[columnIndex] = 0;
544
- }
545
- });
546
- serie.borderRadiusTopLeft = roundedTopMap;
547
- serie.borderRadiusTopRight = roundedTopMap;
548
- serie.borderRadiusBottomLeft = roundedBottomMap;
549
- serie.borderRadiusBottomRight = roundedBottomMap;
550
- }
551
- }
552
- static getPointX(point) {
553
- if (Array.isArray(point))
554
- return point[0];
555
- if (point && typeof point === 'object')
556
- return point.x ?? null;
557
- return null;
558
- }
559
- static findPointAtAbscissa(data, x, fallbackIndex) {
560
- if (!data)
561
- return undefined;
562
- if (x !== null) {
563
- return data.find(p => ChartOptions.getPointX(p) === x);
564
- }
565
- return data[fallbackIndex];
566
- }
567
- static getPointValue(point) {
568
- if (typeof point === 'number')
569
- return point;
570
- if (Array.isArray(point))
571
- return point[1];
572
- if (point && typeof point === 'object')
573
- return point.y ?? null;
574
- return null;
575
- }
576
- }
577
- function isObject(item) {
578
- return item && typeof item === 'object' && !Array.isArray(item);
579
300
  }
301
+ /** Deep-merge clone (immutable). Arrays are replaced wholesale, not element-merged like `es-toolkit`'s `toMerged`. */
580
302
  function mergeDeep(target, source) {
581
- const output = deepCopy(target);
582
- if (isObject(target) && isObject(source)) {
583
- Object.keys(source).forEach(key => {
584
- if (isObject(source[key])) {
585
- if (!(key in target))
586
- Object.assign(output, { [key]: source[key] });
587
- else
588
- output[key] = mergeDeep(target[key], source[key]);
589
- }
590
- else {
591
- Object.assign(output, { [key]: source[key] });
592
- }
593
- });
594
- }
595
- return output;
596
- }
597
- function deepCopy(source) {
598
- if (typeof source !== 'object' || source === null) {
599
- return source; // Return the value if source is not an object
600
- }
601
- // Create an array or object to hold the values
602
- const newObject = Array.isArray(source) ? [] : {};
603
- for (const key in source) {
604
- if (source.hasOwnProperty(key)) {
605
- // Recursively (deep) copy for nested objects, including arrays
606
- newObject[key] = deepCopy(source[key]);
303
+ if (!isPlainObject(target) || !isPlainObject(source)) {
304
+ return target;
305
+ }
306
+ const output = cloneDeep(target);
307
+ for (const key of Object.keys(source)) {
308
+ const sourceValue = source[key];
309
+ if (isPlainObject(sourceValue)) {
310
+ output[key] = key in target ? mergeDeep(target[key], sourceValue) : cloneDeep(sourceValue);
311
+ }
312
+ else {
313
+ output[key] = sourceValue;
607
314
  }
608
315
  }
609
- return newObject;
316
+ return output;
610
317
  }
611
318
 
612
319
  class ChartBarOptions extends ChartOptions {
@@ -614,19 +321,13 @@ class ChartBarOptions extends ChartOptions {
614
321
  const bar = {
615
322
  maxPointWidth: 20,
616
323
  };
617
- if (stacked && !opposite) {
324
+ if (stacked || opposite) {
325
+ // `opposite` = diverging left/right bars (one series flipped to negative).
618
326
  bar.stacking = 'normal';
619
- bar.events = {
620
- hide() {
621
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
622
- },
623
- show() {
624
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
625
- },
626
- };
327
+ bar.borderRadius = { radius: '50%', scope: 'stack', where: 'end' };
627
328
  }
628
329
  else {
629
- bar.borderRadius = 100;
330
+ bar.borderRadius = '50%';
630
331
  }
631
332
  const defaultBarOptions = {
632
333
  chart: {
@@ -663,37 +364,28 @@ class ChartBarOptions extends ChartOptions {
663
364
  bar,
664
365
  series: {
665
366
  borderWidth: 0,
666
- }
367
+ },
667
368
  },
668
369
  };
669
370
  return super.build(mergeDeep(defaultBarOptions, options), locale);
670
371
  }
671
372
  static configureBar(series, categories, options, opposite, color, labelDateFormat) {
672
373
  ChartOptions.configure(series, options, color, labelDateFormat);
673
- if (categories && categories.length) {
374
+ if (categories?.length) {
674
375
  options.xAxis.categories = categories;
675
376
  }
676
377
  if (opposite && series.length === 2) {
677
378
  const negativeSerie = series[0];
678
- negativeSerie.borderRadiusBottomLeft = 100;
679
- negativeSerie.borderRadiusBottomRight = 100;
680
- negativeSerie.borderRadiusTopLeft = 0;
681
- negativeSerie.borderRadiusTopRight = 0;
379
+ // Flip the first series negative so it stacks left of zero.
682
380
  negativeSerie.data = negativeSerie.data?.map((point) => {
683
381
  if (point && isNaN(point)) {
684
- return {
685
- ...point,
686
- y: -Math.abs(point.y),
687
- };
382
+ return { ...point, y: -Math.abs(point.y) };
688
383
  }
689
- else if (!isNaN(point)) {
384
+ if (!isNaN(point)) {
690
385
  return -Math.abs(point);
691
386
  }
692
387
  return point;
693
388
  });
694
- if (options.plotOptions?.series) {
695
- options.plotOptions.series.stacking = 'normal';
696
- }
697
389
  const yAxisLabels = options.yAxis.labels;
698
390
  if (yAxisLabels) {
699
391
  yAxisLabels.formatter = function () {
@@ -702,7 +394,7 @@ class ChartBarOptions extends ChartOptions {
702
394
  }
703
395
  if (options.tooltip) {
704
396
  options.tooltip.pointFormatter = function () {
705
- return `<div style="font-size: 14px; color: #344563; margin: 6px 8px 0 8px;"><span style="color:${this.color};">\u25CF</span> ${this.series.name}: <b>${Math.abs(this.y ?? 0) + '%'}</b></div>`;
397
+ return `<div style="font-size: 14px; color: #344563; margin: 6px 8px 0 8px;"><span style="color:${this.color};">●</span> ${this.series.name}: <b>${Math.abs(this.y ?? 0) + '%'}</b></div>`;
706
398
  };
707
399
  }
708
400
  }
@@ -710,35 +402,27 @@ class ChartBarOptions extends ChartOptions {
710
402
  }
711
403
 
712
404
  class ChartBarComponent extends AbstractChartComponent {
713
- categories = [];
714
- opposite = false;
715
- stacked = false;
716
- series = [];
405
+ categories = input([], ...(ngDevMode ? [{ debugName: "categories" }] : []));
406
+ opposite = input(false, ...(ngDevMode ? [{ debugName: "opposite" }] : []));
407
+ stacked = input(false, ...(ngDevMode ? [{ debugName: "stacked" }] : []));
408
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
717
409
  initChart() {
718
- if (this.series) {
719
- const chartOptions = ChartBarOptions.buildBars(this.chartOptions, this.stacked, this.opposite, this.locale);
720
- ChartBarOptions.configureBar(this.series, this.categories, chartOptions, this.opposite, this.color, this.labelDateFormat);
721
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
722
- if (this.chart && this.stacked && !this.opposite) {
723
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
724
- }
725
- }
410
+ const options = ChartBarOptions.buildBars(this.chartOptions(), this.stacked(), this.opposite(), this.locale());
411
+ ChartBarOptions.configureBar(this.series(), this.categories(), options, this.opposite(), this.color(), this.labelDateFormat());
412
+ this.chart = new Chart(this.hostElement, options);
726
413
  }
727
414
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartBarComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
728
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: ChartBarComponent, isStandalone: true, selector: "ap-chart-bar", inputs: { categories: "categories", opposite: "opposite", stacked: "stacked", series: "series" }, usesInheritance: true, ngImport: i0, template: "<div #chart></div>\n" });
415
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartBarComponent, isStandalone: true, selector: "ap-chart-bar", inputs: { categories: { classPropertyName: "categories", publicName: "categories", isSignal: true, isRequired: false, transformFunction: null }, opposite: { classPropertyName: "opposite", publicName: "opposite", isSignal: true, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: block" }, usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
729
416
  }
730
417
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartBarComponent, decorators: [{
731
418
  type: Component,
732
- args: [{ selector: 'ap-chart-bar', standalone: true, template: "<div #chart></div>\n" }]
733
- }], propDecorators: { categories: [{
734
- type: Input
735
- }], opposite: [{
736
- type: Input
737
- }], stacked: [{
738
- type: Input
739
- }], series: [{
740
- type: Input
741
- }] } });
419
+ args: [{
420
+ selector: 'ap-chart-bar',
421
+ template: '',
422
+ host: { style: 'display: block' },
423
+ changeDetection: ChangeDetectionStrategy.OnPush,
424
+ }]
425
+ }], propDecorators: { categories: [{ type: i0.Input, args: [{ isSignal: true, alias: "categories", required: false }] }], opposite: [{ type: i0.Input, args: [{ isSignal: true, alias: "opposite", required: false }] }], stacked: [{ type: i0.Input, args: [{ isSignal: true, alias: "stacked", required: false }] }], series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }] } });
742
426
 
743
427
  class ChartColumnOptions extends ChartOptions {
744
428
  static buildColumn(options, stacked, locale) {
@@ -746,20 +430,11 @@ class ChartColumnOptions extends ChartOptions {
746
430
  borderWidth: 0,
747
431
  crisp: false,
748
432
  maxPointWidth: 20,
433
+ // Round only the value-side end; `scope: 'stack'` keeps middle segments square.
434
+ borderRadius: stacked ? { radius: '50%', scope: 'stack', where: 'end' } : '50%',
749
435
  };
750
436
  if (stacked) {
751
437
  column.stacking = 'normal';
752
- column.events = {
753
- hide() {
754
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
755
- },
756
- show() {
757
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
758
- },
759
- };
760
- }
761
- else {
762
- column.borderRadius = 100;
763
438
  }
764
439
  const defaultColumnOptions = {
765
440
  chart: {
@@ -781,31 +456,27 @@ class ChartColumnOptions extends ChartOptions {
781
456
  }
782
457
 
783
458
  class ChartColumnComponent extends AbstractChartComponent {
784
- series = [];
785
459
  stacked = input(false, ...(ngDevMode ? [{ debugName: "stacked" }] : []));
786
- chartInitialized = new EventEmitter();
460
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
461
+ chartInitialized = output();
787
462
  initChart() {
788
- if (this.series) {
789
- const chartOptions = ChartColumnOptions.buildColumn(this.chartOptions, this.stacked(), this.locale);
790
- ChartColumnOptions.configure(this.series, chartOptions, this.color, this.labelDateFormat);
791
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
792
- if (this.chart && this.stacked()) {
793
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
794
- }
795
- this.chartInitialized.emit(this.chart);
796
- }
463
+ const options = ChartColumnOptions.buildColumn(this.chartOptions(), this.stacked(), this.locale());
464
+ ChartColumnOptions.configure(this.series(), options, this.color(), this.labelDateFormat());
465
+ this.chart = new Chart(this.hostElement, options);
466
+ this.chartInitialized.emit(this.chart);
797
467
  }
798
468
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
799
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartColumnComponent, isStandalone: true, selector: "ap-chart-column", inputs: { series: { classPropertyName: "series", publicName: "series", isSignal: false, isRequired: false, transformFunction: null }, stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartInitialized: "chartInitialized" }, usesInheritance: true, ngImport: i0, template: "<div #chart></div>\n" });
469
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartColumnComponent, isStandalone: true, selector: "ap-chart-column", inputs: { stacked: { classPropertyName: "stacked", publicName: "stacked", isSignal: true, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartInitialized: "chartInitialized" }, host: { styleAttribute: "display: block" }, usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
800
470
  }
801
471
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartColumnComponent, decorators: [{
802
472
  type: Component,
803
- args: [{ selector: 'ap-chart-column', standalone: true, template: "<div #chart></div>\n" }]
804
- }], propDecorators: { series: [{
805
- type: Input
806
- }], stacked: [{ type: i0.Input, args: [{ isSignal: true, alias: "stacked", required: false }] }], chartInitialized: [{
807
- type: Output
808
- }] } });
473
+ args: [{
474
+ selector: 'ap-chart-column',
475
+ template: '',
476
+ host: { style: 'display: block' },
477
+ changeDetection: ChangeDetectionStrategy.OnPush,
478
+ }]
479
+ }], propDecorators: { stacked: [{ type: i0.Input, args: [{ isSignal: true, alias: "stacked", required: false }] }], series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], chartInitialized: [{ type: i0.Output, args: ["chartInitialized"] }] } });
809
480
 
810
481
  const HEATMAP_CONSTANTS = {
811
482
  CHART_HEIGHT: 680,
@@ -816,7 +487,6 @@ const HEATMAP_CONSTANTS = {
816
487
  TOOLTIP_FONT_SIZE: '14px',
817
488
  LEGEND_SYMBOL_WIDTH: 300,
818
489
  LEGEND_SYMBOL_HEIGHT: 10,
819
- TICK_INTERVAL: 3,
820
490
  DEFAULT_TICK_AMOUNT: 6,
821
491
  DEFAULT_MAX_VALUE: 3,
822
492
  MIN_VALUE: 0,
@@ -870,155 +540,83 @@ class ChartHeatmapOptions extends ChartOptions {
870
540
  pointFormat: `<div style="border-bottom: 1px solid ${ChartColors.GREY_COLORS[10]}; padding: 0 8px 7px">` +
871
541
  `<span style="font-size: ${HEATMAP_CONSTANTS.HEADER_FONT_SIZE}; color: ${ChartColors.GREY_COLORS[60]}">{point.tooltipHeaderLabel}</span></div>` +
872
542
  `<div style="font-size: ${HEATMAP_CONSTANTS.TOOLTIP_FONT_SIZE}; color: ${ChartColors.GREY_COLORS[100]}; margin: 6px 8px 0 8px;">` +
873
- `<span style="color:{point.color}">\u25CF</span> {series.name}: <b>{point.value}{point.unit}</b></div>`,
543
+ `<span style="color:{point.color}">●</span> {series.name}: <b>{point.value}{point.unit}</b></div>`,
874
544
  },
875
545
  xAxis: {
876
- labels: {
877
- formatter: this.createXAxisFormatter(),
878
- },
879
546
  lineWidth: 1,
880
547
  tickWidth: 0,
881
548
  visible: true,
882
549
  },
883
550
  yAxis: {
884
551
  lineWidth: 0,
885
- labels: {
886
- step: 3,
887
- },
552
+ labels: { step: 3 },
888
553
  reversed: true,
889
554
  visible: true,
890
555
  },
891
556
  };
892
557
  return super.build(mergeDeep(defaultHeatmapOptions, options), locale);
893
558
  }
894
- static createColorAxisFormatter(leastLabel, mostLabel) {
895
- return function () {
896
- if (this.value === this.axis.min) {
897
- return leastLabel;
898
- }
899
- if (this.value === this.axis.max) {
900
- return mostLabel;
901
- }
902
- return '';
903
- };
904
- }
905
- static createXAxisFormatter() {
906
- return function () {
907
- return this.value.toString();
908
- };
909
- }
910
559
  static configureHeatmap(categoriesX, categoriesY, series, options, color, leastLabel, mostLabel, labelDateFormat) {
911
560
  super.configure(series, options, color, labelDateFormat);
912
- this.setAxisCategories(options, categoriesX, categoriesY);
913
- const points = series[0].data;
914
- const maxValue = points.reduce((max, point) => Math.max(max, point.value), 0) || HEATMAP_CONSTANTS.DEFAULT_MAX_VALUE;
915
- this.configureColorAxis(options, color, maxValue, leastLabel, mostLabel);
916
- this.configureLegend(options);
917
- }
918
- static setAxisCategories(options, categoriesX, categoriesY) {
919
561
  if (categoriesX?.length) {
920
562
  options.xAxis.categories = categoriesX;
921
563
  }
922
564
  if (categoriesY?.length) {
923
565
  options.yAxis.categories = categoriesY;
924
566
  }
925
- }
926
- static configureColorAxis(options, color, maxValue, leastLabel, mostLabel) {
927
- const tickPositions = this.buildTickPositions(maxValue);
567
+ const data = (series[0].data ?? []);
568
+ const maxValue = data.reduce((max, point) => Math.max(max, point.value ?? 0), 0) || HEATMAP_CONSTANTS.DEFAULT_MAX_VALUE;
928
569
  const labelsEnabled = !!(leastLabel && mostLabel);
570
+ // `tickAmount` spreads ticks evenly between min and max.
929
571
  options.colorAxis = {
930
- ...(options.colorAxis || {}),
572
+ ...(options.colorAxis ?? {}),
931
573
  visible: labelsEnabled,
932
574
  min: HEATMAP_CONSTANTS.MIN_VALUE,
933
- max: HEATMAP_CONSTANTS.DEFAULT_MAX_VALUE,
934
- tickPositions,
575
+ max: maxValue,
576
+ tickAmount: HEATMAP_CONSTANTS.DEFAULT_TICK_AMOUNT,
935
577
  maxColor: ChartColors.getChartColors(color)[100],
936
578
  };
937
579
  if (labelsEnabled) {
938
580
  options.colorAxis.labels = {
939
- ...(options.colorAxis?.labels || {}),
940
- formatter: this.createColorAxisFormatter(leastLabel, mostLabel),
581
+ ...(options.colorAxis?.labels ?? {}),
582
+ formatter: createColorAxisFormatter(leastLabel, mostLabel),
941
583
  };
942
584
  }
943
585
  }
944
- static configureLegend(options) {
945
- options.legend = {
946
- ...options.legend,
947
- enabled: true,
948
- };
949
- }
950
- static buildTickPositions(maxValue) {
951
- const tickAmount = HEATMAP_CONSTANTS.DEFAULT_TICK_AMOUNT;
952
- // Calculate the step between each tick
953
- // We subtract 1 from tickAmount so that the last tick is exactly at maxValue
954
- const step = maxValue / (tickAmount - 1);
955
- // Generate an array of positions for the ticks
956
- // Each position is calculated as i * step and rounded to 2 decimal places
957
- return Array.from({ length: tickAmount }, (_, i) => parseFloat((i * step).toFixed(2)));
958
- }
586
+ }
587
+ function createColorAxisFormatter(leastLabel, mostLabel) {
588
+ return function () {
589
+ if (this.value === this.axis.min)
590
+ return leastLabel;
591
+ if (this.value === this.axis.max)
592
+ return mostLabel;
593
+ return '';
594
+ };
959
595
  }
960
596
 
961
597
  class ChartHeatmapComponent extends AbstractChartComponent {
962
- categoriesX = [];
963
- categoriesY = [];
964
- series = [];
598
+ categoriesX = input([], ...(ngDevMode ? [{ debugName: "categoriesX" }] : []));
599
+ categoriesY = input([], ...(ngDevMode ? [{ debugName: "categoriesY" }] : []));
600
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
965
601
  legendLabels = input(...(ngDevMode ? [undefined, { debugName: "legendLabels" }] : []));
966
- legendLabelsEffect = effect(() => {
967
- this.legendLabels();
968
- this.initChart();
969
- }, ...(ngDevMode ? [{ debugName: "legendLabelsEffect" }] : []));
970
602
  initChart() {
971
- if (this.series && this.chartRef) {
972
- const chartOptions = ChartHeatmapOptions.build(this.chartOptions, this.locale);
973
- ChartHeatmapOptions.configureHeatmap(this.categoriesX, this.categoriesY, this.series, chartOptions, this.color, this.legendLabels()?.least, this.legendLabels()?.most, this.labelDateFormat);
974
- mapChart(this.chartRef.nativeElement, chartOptions);
975
- }
603
+ const labels = this.legendLabels();
604
+ const options = ChartHeatmapOptions.build(this.chartOptions(), this.locale());
605
+ ChartHeatmapOptions.configureHeatmap(this.categoriesX(), this.categoriesY(), this.series(), options, this.color(), labels?.least, labels?.most, this.labelDateFormat());
606
+ this.chart = mapChart(this.hostElement, options);
976
607
  }
977
608
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartHeatmapComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
978
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartHeatmapComponent, isStandalone: true, selector: "ap-chart-heatmap", inputs: { categoriesX: { classPropertyName: "categoriesX", publicName: "categoriesX", isSignal: false, isRequired: false, transformFunction: null }, categoriesY: { classPropertyName: "categoriesY", publicName: "categoriesY", isSignal: false, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: false, isRequired: false, transformFunction: null }, legendLabels: { classPropertyName: "legendLabels", publicName: "legendLabels", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<div #chart></div>\n" });
609
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartHeatmapComponent, isStandalone: true, selector: "ap-chart-heatmap", inputs: { categoriesX: { classPropertyName: "categoriesX", publicName: "categoriesX", isSignal: true, isRequired: false, transformFunction: null }, categoriesY: { classPropertyName: "categoriesY", publicName: "categoriesY", isSignal: true, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null }, legendLabels: { classPropertyName: "legendLabels", publicName: "legendLabels", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: block" }, usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
979
610
  }
980
611
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartHeatmapComponent, decorators: [{
981
612
  type: Component,
982
- args: [{ selector: 'ap-chart-heatmap', standalone: true, template: "<div #chart></div>\n" }]
983
- }], propDecorators: { categoriesX: [{
984
- type: Input
985
- }], categoriesY: [{
986
- type: Input
987
- }], series: [{
988
- type: Input
989
- }], legendLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendLabels", required: false }] }] } });
990
-
991
- var ChartMetricType;
992
- (function (ChartMetricType) {
993
- ChartMetricType[ChartMetricType["default"] = 0] = "default";
994
- ChartMetricType[ChartMetricType["total"] = 1] = "total";
995
- })(ChartMetricType || (ChartMetricType = {}));
996
- class ChartMetric {
997
- children;
998
- name = '';
999
- type;
1000
- value = 0;
1001
- }
1002
-
1003
- class ChartMetricsListComponent {
1004
- metrics = [];
1005
- locale = 'en';
1006
- ChartMetricType = ChartMetricType;
1007
- digitsInfo = '1.0-1';
1008
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMetricsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1009
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.18", type: ChartMetricsListComponent, isStandalone: true, selector: "ap-chart-metrics-list", inputs: { metrics: "metrics", locale: "locale" }, ngImport: i0, template: "<mat-list>\n @if (metrics) {\n @for (metric of metrics; track metric; let i = $index) {\n <mat-list-item [ngClass]=\"{ 'chart-metric-total': metric.type === ChartMetricType.total }\">\n @if (!metric.children) {\n <div class=\"chart-metric-name metric-label\">\n {{ metric.name }}\n </div>\n }\n @if (metric.children) {\n <div class=\"chart-metric-name\">\n <span class=\"metric-label\">\n {{ metric.name }}\n </span>\n <span class=\"chart-metric-children\">\n @for (item of metric.children; track item) {\n <span>\n <span class=\"child-label\">{{ item.name }}</span>\n :\n <span class=\"child-value\">{{ item.value }}</span>\n </span>\n }\n </span>\n </div>\n }\n <div class=\"chart-metric-value metric-label\">\n {{ metric.value | number: digitsInfo : locale }}\n </div>\n </mat-list-item>\n }\n }\n</mat-list>\n", styles: ["[color=facebook]{color:#0866ff}[bgcolor=facebook],[hcolor=facebook]:hover{background-color:#0866ff}[border=facebook]{border:1px solid #0866ff}[color=google]{color:#4e85e8}[bgcolor=google],[hcolor=google]:hover{background-color:#4e85e8}[border=google]{border:1px solid #4e85e8}[color=instagram]{color:#e1306c}[bgcolor=instagram],[hcolor=instagram]:hover{background-color:#e1306c}[border=instagram]{border:1px solid #e1306c}[color=instagrammagenta]{color:#c13584}[bgcolor=instagrammagenta],[hcolor=instagrammagenta]:hover{background-color:#c13584}[border=instagrammagenta]{border:1px solid #c13584}[color=instagramblue]{color:#5851db}[bgcolor=instagramblue],[hcolor=instagramblue]:hover{background-color:#5851db}[border=instagramblue]{border:1px solid #5851db}[color=instagrampurple]{color:#833ab4}[bgcolor=instagrampurple],[hcolor=instagrampurple]:hover{background-color:#833ab4}[border=instagrampurple]{border:1px solid #833ab4}[color=instagramorange]{color:#f56040}[bgcolor=instagramorange],[hcolor=instagramorange]:hover{background-color:#f56040}[border=instagramorange]{border:1px solid #f56040}[color=instagramyellow]{color:#ffdc80}[bgcolor=instagramyellow],[hcolor=instagramyellow]:hover{background-color:#ffdc80}[border=instagramyellow]{border:1px solid #ffdc80}[color=linkedin]{color:#2c67bc}[bgcolor=linkedin],[hcolor=linkedin]:hover{background-color:#2c67bc}[border=linkedin]{border:1px solid #2c67bc}[color=twitter]{color:#55acee}[bgcolor=twitter],[hcolor=twitter]:hover{background-color:#55acee}[border=twitter]{border:1px solid #55acee}[color=youtube]{color:red}[bgcolor=youtube],[hcolor=youtube]:hover{background-color:red}[border=youtube]{border:1px solid #ff0000}[color=reddit]{color:#ff4500}[bgcolor=reddit],[hcolor=reddit]:hover{background-color:#ff4500}[border=reddit]{border:1px solid #ff4500}[color=blood-orange]{color:#ff4d00}[bgcolor=blood-orange],[hcolor=blood-orange]:hover{background-color:#ff4d00}[border=blood-orange]{border:1px solid #ff4d00}[color=pinkish-orange]{color:#ff7b49}[bgcolor=pinkish-orange],[hcolor=pinkish-orange]:hover{background-color:#ff7b49}[border=pinkish-orange]{border:1px solid #ff7b49}[color=charcoal-grey]{color:#2a2f34}[bgcolor=charcoal-grey],[hcolor=charcoal-grey]:hover{background-color:#2a2f34}[border=charcoal-grey]{border:1px solid #2a2f34}[color=azure]{color:#00aeef}[bgcolor=azure],[hcolor=azure]:hover{background-color:#00aeef}[border=azure]{border:1px solid #00aeef}[color=light-azure]{color:#eaf5fd}[bgcolor=light-azure],[hcolor=light-azure]:hover{background-color:#eaf5fd}[border=light-azure]{border:1px solid #eaf5fd}[color=blue-grey]{color:#8d98a9}[bgcolor=blue-grey],[hcolor=blue-grey]:hover{background-color:#8d98a9}[border=blue-grey]{border:1px solid #8d98a9}[color=silver]{color:#ced0da}[bgcolor=silver],[hcolor=silver]:hover{background-color:#ced0da}[border=silver]{border:1px solid #ced0da}[color=pale-grey]{color:#dfe3e9}[bgcolor=pale-grey],[hcolor=pale-grey]:hover{background-color:#dfe3e9}[border=pale-grey]{border:1px solid #dfe3e9}[color=grey-white]{color:#f5f7f8}[bgcolor=grey-white],[hcolor=grey-white]:hover{background-color:#f5f7f8}[border=grey-white]{border:1px solid #f5f7f8}[color=cool-grey]{color:#b4bbc6}[bgcolor=cool-grey],[hcolor=cool-grey]:hover{background-color:#b4bbc6}[border=cool-grey]{border:1px solid #b4bbc6}[color=black]{color:#344563}[bgcolor=black],[hcolor=black]:hover{background-color:#344563}[border=black]{border:1px solid #344563}[color=grey-blue]{color:#68768c}[bgcolor=grey-blue],[hcolor=grey-blue]:hover{background-color:#68768c}[border=grey-blue]{border:1px solid #68768c}[color=strawberry]{color:#f4282d}[bgcolor=strawberry],[hcolor=strawberry]:hover{background-color:#f4282d}[border=strawberry]{border:1px solid #f4282d}[color=light-strawberry]{color:#f8eded}[bgcolor=light-strawberry],[hcolor=light-strawberry]:hover{background-color:#f8eded}[border=light-strawberry]{border:1px solid #f8eded}[color=white]{color:#fff}[bgcolor=white],[hcolor=white]:hover{background-color:#fff}[border=white]{border:1px solid #ffffff}[color=cool-green]{color:#33c15d}[bgcolor=cool-green],[hcolor=cool-green]:hover{background-color:#33c15d}[border=cool-green]{border:1px solid #33c15d}[color=light-green]{color:#ebfaef}[bgcolor=light-green],[hcolor=light-green]:hover{background-color:#ebfaef}[border=light-green]{border:1px solid #ebfaef}[color=transparent]{color:transparent}[bgcolor=transparent],[hcolor=transparent]:hover{background-color:transparent}[border=transparent]{border:1px solid transparent}[color=c0]{color:#a566a5}[bgcolor=c0],[hcolor=c0]:hover{background-color:#a566a5}[border=c0]{border:1px solid #a566a5}[color=c1]{color:#c7ab82}[bgcolor=c1],[hcolor=c1]:hover{background-color:#c7ab82}[border=c1]{border:1px solid #c7ab82}[color=c2]{color:#f2713c}[bgcolor=c2],[hcolor=c2]:hover{background-color:#f2713c}[border=c2]{border:1px solid #f2713c}[color=c3]{color:#ffd006}[bgcolor=c3],[hcolor=c3]:hover{background-color:#ffd006}[border=c3]{border:1px solid #ffd006}[color=c4]{color:#94c5aa}[bgcolor=c4],[hcolor=c4]:hover{background-color:#94c5aa}[border=c4]{border:1px solid #94c5aa}[color=c5]{color:#2a9d8f}[bgcolor=c5],[hcolor=c5]:hover{background-color:#2a9d8f}[border=c5]{border:1px solid #2a9d8f}[color=c6]{color:#78acd8}[bgcolor=c6],[hcolor=c6]:hover{background-color:#78acd8}[border=c6]{border:1px solid #78acd8}[color=c7]{color:#525a9e}[bgcolor=c7],[hcolor=c7]:hover{background-color:#525a9e}[border=c7]{border:1px solid #525a9e}[color=c8]{color:#6a2459}[bgcolor=c8],[hcolor=c8]:hover{background-color:#6a2459}[border=c8]{border:1px solid #6a2459}[color=c9]{color:#74729e}[bgcolor=c9],[hcolor=c9]:hover{background-color:#74729e}[border=c9]{border:1px solid #74729e}.metric-label{font-size:14px;color:#5d6a82}.chart-metric-total .metric-label{font-size:16px;color:#344563!important;font-weight:700}.chart-metric-name .chart-metric-children{color:#aeb5c1;font-size:14px}.chart-metric-name .chart-metric-children .child-label{margin-left:16px}.chart-metric-value{justify-content:left;flex:1 0 0;flex-direction:row;text-align:end;color:#344563}.mat-mdc-list-item{height:35px}.mat-mdc-list-item ::ng-deep .mdc-list-item__content{padding:0}.mat-mdc-list-item ::ng-deep .mdc-list-item__content .mdc-list-item__primary-text{display:flex;align-items:center}.mat-mdc-list-item:not(:last-child){border-bottom:1px solid var(--sys-border-color-default)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: MatListModule }, { kind: "component", type: i2.MatList, selector: "mat-list", exportAs: ["matList"] }, { kind: "component", type: i2.MatListItem, selector: "mat-list-item, a[mat-list-item], button[mat-list-item]", inputs: ["activated"], exportAs: ["matListItem"] }, { kind: "ngmodule", type: MatDividerModule }, { kind: "pipe", type: i1.DecimalPipe, name: "number" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1010
- }
1011
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMetricsListComponent, decorators: [{
1012
- type: Component,
1013
- args: [{ changeDetection: ChangeDetectionStrategy.OnPush, selector: 'ap-chart-metrics-list', imports: [CommonModule, MatListModule, MatDividerModule], template: "<mat-list>\n @if (metrics) {\n @for (metric of metrics; track metric; let i = $index) {\n <mat-list-item [ngClass]=\"{ 'chart-metric-total': metric.type === ChartMetricType.total }\">\n @if (!metric.children) {\n <div class=\"chart-metric-name metric-label\">\n {{ metric.name }}\n </div>\n }\n @if (metric.children) {\n <div class=\"chart-metric-name\">\n <span class=\"metric-label\">\n {{ metric.name }}\n </span>\n <span class=\"chart-metric-children\">\n @for (item of metric.children; track item) {\n <span>\n <span class=\"child-label\">{{ item.name }}</span>\n :\n <span class=\"child-value\">{{ item.value }}</span>\n </span>\n }\n </span>\n </div>\n }\n <div class=\"chart-metric-value metric-label\">\n {{ metric.value | number: digitsInfo : locale }}\n </div>\n </mat-list-item>\n }\n }\n</mat-list>\n", styles: ["[color=facebook]{color:#0866ff}[bgcolor=facebook],[hcolor=facebook]:hover{background-color:#0866ff}[border=facebook]{border:1px solid #0866ff}[color=google]{color:#4e85e8}[bgcolor=google],[hcolor=google]:hover{background-color:#4e85e8}[border=google]{border:1px solid #4e85e8}[color=instagram]{color:#e1306c}[bgcolor=instagram],[hcolor=instagram]:hover{background-color:#e1306c}[border=instagram]{border:1px solid #e1306c}[color=instagrammagenta]{color:#c13584}[bgcolor=instagrammagenta],[hcolor=instagrammagenta]:hover{background-color:#c13584}[border=instagrammagenta]{border:1px solid #c13584}[color=instagramblue]{color:#5851db}[bgcolor=instagramblue],[hcolor=instagramblue]:hover{background-color:#5851db}[border=instagramblue]{border:1px solid #5851db}[color=instagrampurple]{color:#833ab4}[bgcolor=instagrampurple],[hcolor=instagrampurple]:hover{background-color:#833ab4}[border=instagrampurple]{border:1px solid #833ab4}[color=instagramorange]{color:#f56040}[bgcolor=instagramorange],[hcolor=instagramorange]:hover{background-color:#f56040}[border=instagramorange]{border:1px solid #f56040}[color=instagramyellow]{color:#ffdc80}[bgcolor=instagramyellow],[hcolor=instagramyellow]:hover{background-color:#ffdc80}[border=instagramyellow]{border:1px solid #ffdc80}[color=linkedin]{color:#2c67bc}[bgcolor=linkedin],[hcolor=linkedin]:hover{background-color:#2c67bc}[border=linkedin]{border:1px solid #2c67bc}[color=twitter]{color:#55acee}[bgcolor=twitter],[hcolor=twitter]:hover{background-color:#55acee}[border=twitter]{border:1px solid #55acee}[color=youtube]{color:red}[bgcolor=youtube],[hcolor=youtube]:hover{background-color:red}[border=youtube]{border:1px solid #ff0000}[color=reddit]{color:#ff4500}[bgcolor=reddit],[hcolor=reddit]:hover{background-color:#ff4500}[border=reddit]{border:1px solid #ff4500}[color=blood-orange]{color:#ff4d00}[bgcolor=blood-orange],[hcolor=blood-orange]:hover{background-color:#ff4d00}[border=blood-orange]{border:1px solid #ff4d00}[color=pinkish-orange]{color:#ff7b49}[bgcolor=pinkish-orange],[hcolor=pinkish-orange]:hover{background-color:#ff7b49}[border=pinkish-orange]{border:1px solid #ff7b49}[color=charcoal-grey]{color:#2a2f34}[bgcolor=charcoal-grey],[hcolor=charcoal-grey]:hover{background-color:#2a2f34}[border=charcoal-grey]{border:1px solid #2a2f34}[color=azure]{color:#00aeef}[bgcolor=azure],[hcolor=azure]:hover{background-color:#00aeef}[border=azure]{border:1px solid #00aeef}[color=light-azure]{color:#eaf5fd}[bgcolor=light-azure],[hcolor=light-azure]:hover{background-color:#eaf5fd}[border=light-azure]{border:1px solid #eaf5fd}[color=blue-grey]{color:#8d98a9}[bgcolor=blue-grey],[hcolor=blue-grey]:hover{background-color:#8d98a9}[border=blue-grey]{border:1px solid #8d98a9}[color=silver]{color:#ced0da}[bgcolor=silver],[hcolor=silver]:hover{background-color:#ced0da}[border=silver]{border:1px solid #ced0da}[color=pale-grey]{color:#dfe3e9}[bgcolor=pale-grey],[hcolor=pale-grey]:hover{background-color:#dfe3e9}[border=pale-grey]{border:1px solid #dfe3e9}[color=grey-white]{color:#f5f7f8}[bgcolor=grey-white],[hcolor=grey-white]:hover{background-color:#f5f7f8}[border=grey-white]{border:1px solid #f5f7f8}[color=cool-grey]{color:#b4bbc6}[bgcolor=cool-grey],[hcolor=cool-grey]:hover{background-color:#b4bbc6}[border=cool-grey]{border:1px solid #b4bbc6}[color=black]{color:#344563}[bgcolor=black],[hcolor=black]:hover{background-color:#344563}[border=black]{border:1px solid #344563}[color=grey-blue]{color:#68768c}[bgcolor=grey-blue],[hcolor=grey-blue]:hover{background-color:#68768c}[border=grey-blue]{border:1px solid #68768c}[color=strawberry]{color:#f4282d}[bgcolor=strawberry],[hcolor=strawberry]:hover{background-color:#f4282d}[border=strawberry]{border:1px solid #f4282d}[color=light-strawberry]{color:#f8eded}[bgcolor=light-strawberry],[hcolor=light-strawberry]:hover{background-color:#f8eded}[border=light-strawberry]{border:1px solid #f8eded}[color=white]{color:#fff}[bgcolor=white],[hcolor=white]:hover{background-color:#fff}[border=white]{border:1px solid #ffffff}[color=cool-green]{color:#33c15d}[bgcolor=cool-green],[hcolor=cool-green]:hover{background-color:#33c15d}[border=cool-green]{border:1px solid #33c15d}[color=light-green]{color:#ebfaef}[bgcolor=light-green],[hcolor=light-green]:hover{background-color:#ebfaef}[border=light-green]{border:1px solid #ebfaef}[color=transparent]{color:transparent}[bgcolor=transparent],[hcolor=transparent]:hover{background-color:transparent}[border=transparent]{border:1px solid transparent}[color=c0]{color:#a566a5}[bgcolor=c0],[hcolor=c0]:hover{background-color:#a566a5}[border=c0]{border:1px solid #a566a5}[color=c1]{color:#c7ab82}[bgcolor=c1],[hcolor=c1]:hover{background-color:#c7ab82}[border=c1]{border:1px solid #c7ab82}[color=c2]{color:#f2713c}[bgcolor=c2],[hcolor=c2]:hover{background-color:#f2713c}[border=c2]{border:1px solid #f2713c}[color=c3]{color:#ffd006}[bgcolor=c3],[hcolor=c3]:hover{background-color:#ffd006}[border=c3]{border:1px solid #ffd006}[color=c4]{color:#94c5aa}[bgcolor=c4],[hcolor=c4]:hover{background-color:#94c5aa}[border=c4]{border:1px solid #94c5aa}[color=c5]{color:#2a9d8f}[bgcolor=c5],[hcolor=c5]:hover{background-color:#2a9d8f}[border=c5]{border:1px solid #2a9d8f}[color=c6]{color:#78acd8}[bgcolor=c6],[hcolor=c6]:hover{background-color:#78acd8}[border=c6]{border:1px solid #78acd8}[color=c7]{color:#525a9e}[bgcolor=c7],[hcolor=c7]:hover{background-color:#525a9e}[border=c7]{border:1px solid #525a9e}[color=c8]{color:#6a2459}[bgcolor=c8],[hcolor=c8]:hover{background-color:#6a2459}[border=c8]{border:1px solid #6a2459}[color=c9]{color:#74729e}[bgcolor=c9],[hcolor=c9]:hover{background-color:#74729e}[border=c9]{border:1px solid #74729e}.metric-label{font-size:14px;color:#5d6a82}.chart-metric-total .metric-label{font-size:16px;color:#344563!important;font-weight:700}.chart-metric-name .chart-metric-children{color:#aeb5c1;font-size:14px}.chart-metric-name .chart-metric-children .child-label{margin-left:16px}.chart-metric-value{justify-content:left;flex:1 0 0;flex-direction:row;text-align:end;color:#344563}.mat-mdc-list-item{height:35px}.mat-mdc-list-item ::ng-deep .mdc-list-item__content{padding:0}.mat-mdc-list-item ::ng-deep .mdc-list-item__content .mdc-list-item__primary-text{display:flex;align-items:center}.mat-mdc-list-item:not(:last-child){border-bottom:1px solid var(--sys-border-color-default)}\n"] }]
1014
- }], propDecorators: { metrics: [{
1015
- type: Input,
1016
- args: [{
1017
- required: true,
1018
- }]
1019
- }], locale: [{
1020
- type: Input
1021
- }] } });
613
+ args: [{
614
+ selector: 'ap-chart-heatmap',
615
+ template: '',
616
+ host: { style: 'display: block' },
617
+ changeDetection: ChangeDetectionStrategy.OnPush,
618
+ }]
619
+ }], propDecorators: { categoriesX: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoriesX", required: false }] }], categoriesY: [{ type: i0.Input, args: [{ isSignal: true, alias: "categoriesY", required: false }] }], series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], legendLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendLabels", required: false }] }] } });
1022
620
 
1023
621
  class ChartMixedOptions extends ChartOptions {
1024
622
  static buildMixed(options, singleDayEnabled, locale) {
@@ -1036,20 +634,13 @@ class ChartMixedOptions extends ChartOptions {
1036
634
  radius: singleDayEnabled ? 5 : 2,
1037
635
  symbol: 'circle',
1038
636
  },
1039
- lineWidth: 4
637
+ lineWidth: 4,
1040
638
  },
1041
639
  column: {
1042
640
  stacking: 'normal',
1043
641
  borderWidth: 0,
1044
642
  maxPointWidth: 20,
1045
- events: {
1046
- hide() {
1047
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
1048
- },
1049
- show() {
1050
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
1051
- },
1052
- },
643
+ borderRadius: { radius: '50%', scope: 'stack', where: 'end' },
1053
644
  },
1054
645
  },
1055
646
  xAxis: {
@@ -1061,31 +652,32 @@ class ChartMixedOptions extends ChartOptions {
1061
652
  }
1062
653
 
1063
654
  class ChartMixedComponent extends AbstractChartComponent {
1064
- series = [];
655
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
1065
656
  initChart() {
1066
- if (this.series) {
1067
- const singleDayEnabled = this.series.find(serie => serie.type === 'spline')?.data?.length === 1;
1068
- const chartOptions = ChartMixedOptions.buildMixed(this.chartOptions, singleDayEnabled, this.locale);
1069
- ChartMixedOptions.configure(this.series, chartOptions, this.color, this.labelDateFormat);
1070
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
1071
- if (this.chart) {
1072
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
1073
- }
1074
- }
657
+ const series = this.series();
658
+ const splineSeries = series.find(serie => serie.type === 'spline');
659
+ const singleDayEnabled = splineSeries?.data?.length === 1;
660
+ const options = ChartMixedOptions.buildMixed(this.chartOptions(), singleDayEnabled, this.locale());
661
+ ChartMixedOptions.configure(series, options, this.color(), this.labelDateFormat());
662
+ this.chart = new Chart(this.hostElement, options);
1075
663
  }
1076
664
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMixedComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1077
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: ChartMixedComponent, isStandalone: true, selector: "ap-chart-mixed", inputs: { series: "series" }, usesInheritance: true, ngImport: i0, template: "<div #chart></div>\n" });
665
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartMixedComponent, isStandalone: true, selector: "ap-chart-mixed", inputs: { series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: block" }, usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1078
666
  }
1079
667
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMixedComponent, decorators: [{
1080
668
  type: Component,
1081
- args: [{ selector: 'ap-chart-mixed', standalone: true, template: "<div #chart></div>\n" }]
1082
- }], propDecorators: { series: [{
1083
- type: Input
1084
- }] } });
669
+ args: [{
670
+ selector: 'ap-chart-mixed',
671
+ template: '',
672
+ host: { style: 'display: block' },
673
+ changeDetection: ChangeDetectionStrategy.OnPush,
674
+ }]
675
+ }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }] } });
1085
676
 
1086
677
  const NAME_MAX_LENGTH = 30;
1087
- const RIGHT_TO_LEFT_CHARACTERS = /[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Samaritan}\p{Script=Mandaic}]/u; // Hebrew, Arabic, and other RTL characters
1088
- const RIGHT_TO_LEFT_EMBEDDING_CHARACTER = '\u202B'; // Right-to-left embedding character
678
+ // RTL scripts (Hebrew, Arabic, …).
679
+ const RIGHT_TO_LEFT_CHARACTERS = /[\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Syriac}\p{Script=Thaana}\p{Script=Nko}\p{Script=Samaritan}\p{Script=Mandaic}]/u;
680
+ const RIGHT_TO_LEFT_EMBEDDING_CHARACTER = '‫';
1089
681
  class ChartPieOptions extends ChartOptions {
1090
682
  static buildPie(options, innerLabels, metricFormat, locale) {
1091
683
  const defaultPieOptions = {
@@ -1105,51 +697,14 @@ class ChartPieOptions extends ChartOptions {
1105
697
  },
1106
698
  series: {
1107
699
  allowPointSelect: !innerLabels,
1108
- dataLabels: innerLabels
1109
- ? {
1110
- format: metricFormat === 'percentage' ? '{point.percentage:.1f}%' : '{point.y}',
1111
- style: {
1112
- fontSize: '16px',
1113
- color: 'white',
1114
- textOutline: '0',
1115
- },
1116
- }
1117
- : {
1118
- formatter: function () {
1119
- const name = this.name.length > NAME_MAX_LENGTH
1120
- ? this.name.substring(0, NAME_MAX_LENGTH) + '...'
1121
- : this.name;
1122
- const displayValue = metricFormat === 'percentage'
1123
- ? numberFormat(Math.round((this.percentage ?? 0) * 10) / 10, -1) + '%'
1124
- : numberFormat(this.y ?? 0, -1);
1125
- // Add right-to-left embedding character only if the first character is a right-to-left character
1126
- const prefix = RIGHT_TO_LEFT_CHARACTERS.test(this.name.charAt(0))
1127
- ? RIGHT_TO_LEFT_EMBEDDING_CHARACTER
1128
- : '';
1129
- return prefix + name + ': ' + displayValue;
1130
- },
1131
- style: {
1132
- fontSize: '12px',
1133
- color: ChartColors.GREY_COLORS[60],
1134
- },
1135
- },
700
+ dataLabels: innerLabels ? buildInnerLabels(metricFormat) : buildOuterLabels(metricFormat),
1136
701
  showInLegend: innerLabels,
1137
- states: {
1138
- inactive: {
1139
- opacity: 1,
1140
- },
1141
- },
1142
702
  },
1143
703
  },
1144
704
  tooltip: {
1145
705
  outside: true,
1146
706
  },
1147
- legend: innerLabels
1148
- ? {
1149
- symbolHeight: 10,
1150
- enabled: true,
1151
- }
1152
- : {},
707
+ legend: innerLabels ? { symbolHeight: 10, enabled: true } : {},
1153
708
  };
1154
709
  return super.build(mergeDeep(defaultPieOptions, options), locale);
1155
710
  }
@@ -1158,159 +713,81 @@ class ChartPieOptions extends ChartOptions {
1158
713
  if (innerLabels && options.legend) {
1159
714
  options.legend.enabled = true;
1160
715
  }
1161
- if (series && series.length > 0 && series[0]) {
1162
- options.colors = colors;
1163
- if (mouseEventEnabled && options.plotOptions?.pie) {
1164
- this.resetColors(series[0].data, innerLabels);
1165
- options.plotOptions.pie.point ??= {};
1166
- options.plotOptions.pie.point.events ??= {};
1167
- options.plotOptions.pie.events ??= {};
1168
- this.configureEnteringASlice(options, innerLabels);
1169
- this.configureLeavingASlice(options, innerLabels);
1170
- this.configureLeavingTheWholePie(options, innerLabels);
1171
- }
1172
- }
1173
- }
1174
- static resetColors(points, innerLabels) {
1175
- points?.forEach(point => {
1176
- delete point?.color;
1177
- if (innerLabels) {
1178
- delete point.dataLabels?.style?.color;
1179
- }
1180
- });
1181
- }
1182
- static configureEnteringASlice(options, innerLabels) {
1183
- if (options.plotOptions?.pie?.point?.events) {
1184
- options.plotOptions.pie.point.events.mouseOver = function () {
1185
- this.series.chart.series[0].points.forEach(point => {
1186
- if (point.index !== this.index) {
1187
- point.update({
1188
- color: ChartColors.GREY_COLORS[5],
1189
- }, false);
1190
- if (innerLabels) {
1191
- point.update({
1192
- dataLabels: {
1193
- style: {
1194
- color: ChartColors.GREY_COLORS[20],
1195
- },
1196
- },
1197
- }, false);
1198
- }
1199
- }
1200
- });
1201
- this.series.chart.redraw(false);
1202
- };
1203
- }
1204
- }
1205
- static configureLeavingASlice(options, innerLabels) {
1206
- if (options.plotOptions?.pie?.point?.events) {
1207
- options.plotOptions.pie.point.events.mouseOut = function () {
1208
- this.series.chart.series[0].points.forEach((point, i) => {
1209
- if (point.index !== this.index) {
1210
- point.update({
1211
- color: options.colors?.[i % options.colors.length],
1212
- }, false);
1213
- if (innerLabels) {
1214
- point.update({
1215
- dataLabels: {
1216
- style: {
1217
- color: 'white',
1218
- },
1219
- },
1220
- }, false);
1221
- }
1222
- }
1223
- });
1224
- };
716
+ if (!series?.[0]) {
717
+ return;
1225
718
  }
1226
- }
1227
- static configureLeavingTheWholePie(options, innerLabels) {
1228
- if (options.plotOptions?.pie?.events) {
1229
- options.plotOptions.pie.events.mouseOut = function () {
1230
- this.chart.series[0].points.forEach((point, i) => {
1231
- point.update({
1232
- color: options.colors?.[i % options.colors.length],
1233
- }, false);
1234
- if (innerLabels) {
1235
- point.update({
1236
- dataLabels: {
1237
- style: {
1238
- color: 'white',
1239
- },
1240
- },
1241
- }, false);
1242
- }
1243
- });
1244
- this.chart.redraw();
1245
- };
719
+ options.colors = colors;
720
+ // Otherwise we rely on Highcharts' default `states.inactive.opacity` to fade non-hovered slices.
721
+ if (!mouseEventEnabled) {
722
+ options.plotOptions ??= {};
723
+ options.plotOptions.pie ??= {};
724
+ options.plotOptions.pie.enableMouseTracking = false;
1246
725
  }
1247
726
  }
1248
727
  }
728
+ function buildInnerLabels(metricFormat) {
729
+ return {
730
+ format: metricFormat === 'percentage' ? '{point.percentage:.1f}%' : '{point.y}',
731
+ style: {
732
+ fontSize: '16px',
733
+ color: 'white',
734
+ textOutline: '0',
735
+ },
736
+ };
737
+ }
738
+ function buildOuterLabels(metricFormat) {
739
+ return {
740
+ formatter() {
741
+ const truncatedName = this.name.length > NAME_MAX_LENGTH ? this.name.substring(0, NAME_MAX_LENGTH) + '...' : this.name;
742
+ const displayValue = metricFormat === 'percentage' ? numberFormat(round(this.percentage ?? 0, 1), -1) + '%' : numberFormat(this.y ?? 0, -1);
743
+ const prefix = RIGHT_TO_LEFT_CHARACTERS.test(this.name.charAt(0)) ? RIGHT_TO_LEFT_EMBEDDING_CHARACTER : '';
744
+ return prefix + truncatedName + ': ' + displayValue;
745
+ },
746
+ style: {
747
+ fontSize: '12px',
748
+ color: ChartColors.GREY_COLORS[60],
749
+ },
750
+ };
751
+ }
1249
752
 
1250
753
  class ChartPieComponent extends AbstractChartComponent {
1251
- innerLabels = false;
1252
- mouseEventEnabled = true;
1253
- series = [];
754
+ innerLabels = input(false, ...(ngDevMode ? [{ debugName: "innerLabels" }] : []));
755
+ mouseEventEnabled = input(true, ...(ngDevMode ? [{ debugName: "mouseEventEnabled" }] : []));
756
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
1254
757
  colors = input(...(ngDevMode ? [undefined, { debugName: "colors" }] : []));
1255
758
  metricFormat = input('percentage', ...(ngDevMode ? [{ debugName: "metricFormat" }] : []));
1256
- domReady = signal(false, ...(ngDevMode ? [{ debugName: "domReady" }] : []));
1257
- constructor() {
1258
- super();
1259
- effect(() => {
1260
- if (this.domReady()) {
1261
- this.colors();
1262
- this.initChart();
1263
- }
1264
- });
1265
- afterNextRender(() => {
1266
- this.domReady.set(true);
1267
- });
1268
- }
1269
759
  initChart() {
1270
- if (this.series) {
1271
- const dataAvailable = this.series[0]?.data && this.series[0].data.length > 0;
1272
- const chartOptions = ChartPieOptions.buildPie(this.chartOptions, this.innerLabels, this.metricFormat(), this.locale);
1273
- // Add placeholder series when there's no data
1274
- const updatedSeries = dataAvailable
1275
- ? this.series
1276
- : [
1277
- {
1278
- type: 'pie',
1279
- data: [
1280
- {
1281
- y: 1,
1282
- dataLabels: {
1283
- enabled: false,
1284
- },
1285
- },
1286
- ],
1287
- enableMouseTracking: false,
1288
- },
1289
- ];
1290
- let colors = this.colors();
1291
- if (!dataAvailable) {
1292
- colors = [ChartColors.GREY_COLORS[10]];
1293
- }
1294
- else if (!colors?.length) {
1295
- colors = ChartColors.getColors(this.series[0]?.data?.length ?? 0, this.color);
1296
- }
1297
- ChartPieOptions.configurePie(updatedSeries, chartOptions, colors, this.labelDateFormat, this.innerLabels, this.mouseEventEnabled);
1298
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
1299
- }
1300
- }
1301
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartPieComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1302
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartPieComponent, isStandalone: true, selector: "ap-chart-pie", inputs: { innerLabels: { classPropertyName: "innerLabels", publicName: "innerLabels", isSignal: false, isRequired: false, transformFunction: null }, mouseEventEnabled: { classPropertyName: "mouseEventEnabled", publicName: "mouseEventEnabled", isSignal: false, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: false, isRequired: false, transformFunction: null }, colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, metricFormat: { classPropertyName: "metricFormat", publicName: "metricFormat", isSignal: true, isRequired: false, transformFunction: null } }, usesInheritance: true, ngImport: i0, template: "<div #chart></div>\n" });
760
+ const series = this.series();
761
+ const innerLabels = this.innerLabels();
762
+ const dataAvailable = !!series[0]?.data?.length;
763
+ const options = ChartPieOptions.buildPie(this.chartOptions(), innerLabels, this.metricFormat(), this.locale());
764
+ const effectiveSeries = dataAvailable
765
+ ? series
766
+ : [
767
+ {
768
+ type: 'pie',
769
+ data: [{ y: 1, dataLabels: { enabled: false } }],
770
+ enableMouseTracking: false,
771
+ },
772
+ ];
773
+ const effectiveColors = !dataAvailable
774
+ ? [ChartColors.GREY_COLORS[10]]
775
+ : (this.colors() ?? ChartColors.getColors(series[0]?.data?.length ?? 0, this.color()));
776
+ ChartPieOptions.configurePie(effectiveSeries, options, effectiveColors, this.labelDateFormat(), innerLabels, this.mouseEventEnabled());
777
+ this.chart = new Chart(this.hostElement, options);
778
+ }
779
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartPieComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
780
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartPieComponent, isStandalone: true, selector: "ap-chart-pie", inputs: { innerLabels: { classPropertyName: "innerLabels", publicName: "innerLabels", isSignal: true, isRequired: false, transformFunction: null }, mouseEventEnabled: { classPropertyName: "mouseEventEnabled", publicName: "mouseEventEnabled", isSignal: true, isRequired: false, transformFunction: null }, series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null }, colors: { classPropertyName: "colors", publicName: "colors", isSignal: true, isRequired: false, transformFunction: null }, metricFormat: { classPropertyName: "metricFormat", publicName: "metricFormat", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: block" }, usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1303
781
  }
1304
782
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartPieComponent, decorators: [{
1305
783
  type: Component,
1306
- args: [{ selector: 'ap-chart-pie', standalone: true, template: "<div #chart></div>\n" }]
1307
- }], ctorParameters: () => [], propDecorators: { innerLabels: [{
1308
- type: Input
1309
- }], mouseEventEnabled: [{
1310
- type: Input
1311
- }], series: [{
1312
- type: Input
1313
- }], colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], metricFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricFormat", required: false }] }] } });
784
+ args: [{
785
+ selector: 'ap-chart-pie',
786
+ template: '',
787
+ host: { style: 'display: block' },
788
+ changeDetection: ChangeDetectionStrategy.OnPush,
789
+ }]
790
+ }], propDecorators: { innerLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "innerLabels", required: false }] }], mouseEventEnabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "mouseEventEnabled", required: false }] }], series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], metricFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricFormat", required: false }] }] } });
1314
791
 
1315
792
  class ChartSplineOptions extends ChartOptions {
1316
793
  static buildSpline(options, singleDayEnabled, locale) {
@@ -1337,36 +814,32 @@ class ChartSplineOptions extends ChartOptions {
1337
814
  }
1338
815
 
1339
816
  class ChartSplineComponent extends AbstractChartComponent {
1340
- series = [];
1341
- chartInitialized = new EventEmitter();
817
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
818
+ chartInitialized = output();
1342
819
  initChart() {
1343
- if (this.series) {
1344
- const chartOptions = ChartSplineOptions.buildSpline(this.chartOptions, this.series[0]?.data?.length === 1, this.locale);
1345
- ChartSplineOptions.configure(this.series, chartOptions, this.color, this.labelDateFormat);
1346
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
1347
- this.chartInitialized.emit(this.chart);
1348
- }
820
+ const series = this.series();
821
+ const singleDayEnabled = series[0]?.data?.length === 1;
822
+ const options = ChartSplineOptions.buildSpline(this.chartOptions(), singleDayEnabled, this.locale());
823
+ ChartSplineOptions.configure(series, options, this.color(), this.labelDateFormat());
824
+ this.chart = new Chart(this.hostElement, options);
825
+ this.chartInitialized.emit(this.chart);
1349
826
  }
1350
827
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartSplineComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1351
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: ChartSplineComponent, isStandalone: true, selector: "ap-chart-spline", inputs: { series: "series" }, outputs: { chartInitialized: "chartInitialized" }, usesInheritance: true, ngImport: i0, template: "<div #chart></div>\n" });
828
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "20.3.18", type: ChartSplineComponent, isStandalone: true, selector: "ap-chart-spline", inputs: { series: { classPropertyName: "series", publicName: "series", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { chartInitialized: "chartInitialized" }, host: { styleAttribute: "display: block" }, usesInheritance: true, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1352
829
  }
1353
830
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartSplineComponent, decorators: [{
1354
831
  type: Component,
1355
- args: [{ selector: 'ap-chart-spline', standalone: true, template: "<div #chart></div>\n" }]
1356
- }], propDecorators: { series: [{
1357
- type: Input
1358
- }], chartInitialized: [{
1359
- type: Output
1360
- }] } });
1361
-
1362
- /*
1363
- * Public API Surface of ui-charts
1364
- */
1365
- borderRadiusPlugin(Highcharts);
832
+ args: [{
833
+ selector: 'ap-chart-spline',
834
+ template: '',
835
+ host: { style: 'display: block' },
836
+ changeDetection: ChangeDetectionStrategy.OnPush,
837
+ }]
838
+ }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], chartInitialized: [{ type: i0.Output, args: ["chartInitialized"] }] } });
1366
839
 
1367
840
  /**
1368
841
  * Generated bundle index. Do not edit.
1369
842
  */
1370
843
 
1371
- export { AbstractChartComponent, ChartBarComponent, ChartColor, ChartColors, ChartColumnComponent, ChartHeatmapComponent, ChartMetric, ChartMetricType, ChartMetricsListComponent, ChartMixedComponent, ChartOptions, ChartPieComponent, ChartSplineComponent, borderRadiusPlugin, mergeDeep };
844
+ export { AbstractChartComponent, ChartBarComponent, ChartColor, ChartColors, ChartColumnComponent, ChartHeatmapComponent, ChartMixedComponent, ChartOptions, ChartPieComponent, ChartSplineComponent, mergeDeep };
1372
845
  //# sourceMappingURL=agorapulse-ui-charts.mjs.map