@agorapulse/ui-charts 20.1.15 → 20.1.17

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,82 +1,59 @@
1
1
  import * as Highcharts from 'highcharts';
2
2
  import { numberFormat, setOptions, dateFormat, Chart } from 'highcharts';
3
3
  import * as i0 from '@angular/core';
4
- import { Input, ViewChild, Directive, Component, input, EventEmitter, Output, effect, ChangeDetectionStrategy, signal, afterNextRender } from '@angular/core';
4
+ import { inject, DestroyRef, ElementRef, input, signal, afterNextRender, effect, Directive, ChangeDetectionStrategy, Component, output } from '@angular/core';
5
+ import { isPlainObject, cloneDeep, round } from 'es-toolkit';
5
6
  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
7
 
12
- /* eslint-disable @typescript-eslint/ban-ts-comment */
13
- const borderRadiusPlugin = function (H) {
14
- if (H.borderRadiusPlugininitialized) {
8
+ function borderRadiusPlugin(H) {
9
+ const runtime = H;
10
+ if (runtime.borderRadiusPlugininitialized)
15
11
  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
12
+ runtime.borderRadiusPlugininitialized = true;
13
+ H.wrap(runtime.seriesTypes.column.prototype, 'translate', function (proceed) {
14
+ const { topMargin = 0, bottomMargin = 0, borderRadiusTopLeft, borderRadiusTopRight, borderRadiusBottomLeft, borderRadiusBottomRight, } = this.options;
28
15
  proceed.call(this);
29
- // @ts-ignore
30
- if (!this.points) {
16
+ if (!this.points)
31
17
  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
- }
18
+ if (!borderRadiusTopLeft && !borderRadiusTopRight && !borderRadiusBottomLeft && !borderRadiusBottomRight)
19
+ return;
20
+ this.points.forEach(point => roundPoint(point, H, {
21
+ topMargin,
22
+ bottomMargin,
23
+ topLeft: borderRadiusTopLeft,
24
+ topRight: borderRadiusTopRight,
25
+ bottomLeft: borderRadiusBottomLeft,
26
+ bottomRight: borderRadiusBottomRight,
27
+ }));
42
28
  });
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);
29
+ }
30
+ function pickRadius(value, index) {
31
+ if (Array.isArray(value))
32
+ return value[index] ?? 0;
33
+ return value ?? 0;
34
+ }
35
+ function roundPoint(point, H, config) {
36
+ const { width: w, height: h, x, y } = point.shapeArgs;
65
37
  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;
38
+ const clamp = (radius) => (radius > maxR ? maxR : radius);
39
+ const radiusTopLeft = clamp(H.relativeLength(pickRadius(config.topLeft, point.index), w));
40
+ const radiusTopRight = clamp(H.relativeLength(pickRadius(config.topRight, point.index), w));
41
+ const radiusBottomRight = clamp(H.relativeLength(pickRadius(config.bottomRight, point.index), w));
42
+ const radiusBottomLeft = clamp(H.relativeLength(pickRadius(config.bottomLeft, point.index), w));
70
43
  point.dlBox = point.shapeArgs;
71
44
  point.shapeType = 'path';
72
45
  point.shapeArgs = {
46
+ width: w,
47
+ height: h,
48
+ x,
49
+ y,
73
50
  d: [
74
51
  'M',
75
52
  x + radiusTopLeft,
76
- y + topMargin,
53
+ y + config.topMargin,
77
54
  'L',
78
55
  x + w - radiusTopRight,
79
- y + topMargin,
56
+ y + config.topMargin,
80
57
  'C',
81
58
  x + w - radiusTopRight / 2,
82
59
  y,
@@ -93,10 +70,10 @@ function roundPoint(borderRadiusTopLeftSettings, borderRadiusTopRightSettings, b
93
70
  x + w - radiusBottomRight / 2,
94
71
  y + h,
95
72
  x + w - radiusBottomRight,
96
- y + h + bottomMargin,
73
+ y + h + config.bottomMargin,
97
74
  'L',
98
75
  x + radiusBottomLeft,
99
- y + h + bottomMargin,
76
+ y + h + config.bottomMargin,
100
77
  'C',
101
78
  x + radiusBottomLeft / 2,
102
79
  y + h,
@@ -233,61 +210,53 @@ class ChartColors {
233
210
  }
234
211
 
235
212
  class AbstractChartComponent {
236
- chartRef;
237
- chartOptions = {}; // https://api.highcharts.com/highcharts/
238
- color = ChartColor.ElectricBlue;
239
- labelDateFormat = '%m/%d';
240
- locale = 'en';
241
- series = [];
213
+ destroyRef = inject(DestroyRef);
214
+ /** Highcharts renders into the component's host element directly — no inner template ref needed. */
215
+ hostElement = inject(ElementRef).nativeElement;
216
+ chartOptions = input({}, ...(ngDevMode ? [{ debugName: "chartOptions" }] : []));
217
+ color = input(ChartColor.ElectricBlue, ...(ngDevMode ? [{ debugName: "color" }] : []));
218
+ labelDateFormat = input('%m/%d', ...(ngDevMode ? [{ debugName: "labelDateFormat" }] : []));
219
+ locale = input('en', ...(ngDevMode ? [{ debugName: "locale" }] : []));
242
220
  chart;
221
+ viewReady = signal(false, ...(ngDevMode ? [{ debugName: "viewReady" }] : []));
243
222
  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) {
223
+ constructor() {
224
+ afterNextRender(() => {
225
+ this.resizeObserver = new ResizeObserver(() => this.onResize());
226
+ this.resizeObserver.observe(this.hostElement);
227
+ this.viewReady.set(true);
228
+ });
229
+ // Eager init once the view is ready: Highcharts handles 0-width containers via its
230
+ // default width and the ResizeObserver below reflows when the container later grows.
231
+ effect(() => {
232
+ if (!this.viewReady())
257
233
  return;
258
- }
259
- if (this.chart) {
260
- this.chart.reflow();
261
- }
262
- else if (this.series?.length) {
263
- this.initChart();
264
- }
234
+ this.rebuild();
265
235
  });
266
- this.resizeObserver.observe(this.chartRef.nativeElement);
236
+ this.destroyRef.onDestroy(() => {
237
+ this.resizeObserver?.disconnect();
238
+ this.chart?.destroy();
239
+ });
240
+ }
241
+ onResize() {
242
+ if (this.chart) {
243
+ this.chart.reflow();
244
+ }
245
+ else if (this.hostElement.clientWidth > 0 && this.series().length) {
246
+ this.rebuild();
247
+ }
267
248
  }
268
- ngOnDestroy() {
269
- this.resizeObserver?.disconnect();
249
+ rebuild() {
270
250
  this.chart?.destroy();
251
+ this.chart = undefined;
252
+ this.initChart();
271
253
  }
272
254
  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 });
255
+ 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
256
  }
275
257
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: AbstractChartComponent, decorators: [{
276
258
  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
- }] } });
259
+ }], 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
260
 
292
261
  /**
293
262
  * Builds Highcharts locale options (lang + tooltip date formats) from a locale string.
@@ -332,22 +301,11 @@ function buildShortMonths(locale) {
332
301
  });
333
302
  }
334
303
 
304
+ const FONT_FAMILY = "Averta, 'Open Sans', Helvetica, sans-serif";
305
+ const LABEL_FONT_SIZE = '12px';
335
306
  class ChartOptions {
336
307
  static DEFAULT_DATE_FORMAT = '%A, %b %e, %Y';
337
308
  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
309
  chart: {
352
310
  spacingRight: 20,
353
311
  zooming: {
@@ -358,34 +316,22 @@ class ChartOptions {
358
316
  r: 4,
359
317
  style: {
360
318
  color: ChartColors.GREY_COLORS[100],
361
- fontSize: '12px',
319
+ fontSize: LABEL_FONT_SIZE,
362
320
  },
363
321
  states: {
364
- hover: {
365
- fill: ChartColors.GREY_COLORS[5],
366
- },
322
+ hover: { fill: ChartColors.GREY_COLORS[5] },
367
323
  },
368
324
  },
369
325
  },
370
326
  },
371
- panning: {
372
- enabled: true,
373
- },
327
+ panning: { enabled: true },
374
328
  panKey: 'shift',
375
- style: {
376
- fontFamily: "Averta, 'Open Sans', Helvetica, sans-serif",
377
- },
329
+ style: { fontFamily: FONT_FAMILY },
378
330
  },
379
331
  colorAxis: {
380
- labels: {
381
- style: {
382
- color: ChartColors.GREY_COLORS[60],
383
- },
384
- },
385
- },
386
- credits: {
387
- enabled: false,
332
+ labels: { style: { color: ChartColors.GREY_COLORS[60] } },
388
333
  },
334
+ credits: { enabled: false },
389
335
  legend: {
390
336
  borderWidth: 0,
391
337
  itemStyle: {
@@ -401,21 +347,15 @@ class ChartOptions {
401
347
  plotOptions: {
402
348
  series: {
403
349
  states: {
404
- hover: {
405
- brightness: 0,
406
- },
350
+ hover: { brightness: 0 },
407
351
  },
408
352
  connectNulls: true,
409
353
  },
410
354
  },
411
355
  navigation: {
412
- buttonOptions: {
413
- y: 0,
414
- },
415
- },
416
- title: {
417
- text: undefined,
356
+ buttonOptions: { y: 0 },
418
357
  },
358
+ title: { text: undefined },
419
359
  tooltip: {
420
360
  backgroundColor: ChartColors.WHITE_COLOR,
421
361
  borderRadius: 4,
@@ -432,22 +372,20 @@ class ChartOptions {
432
372
  shared: true,
433
373
  useHTML: true,
434
374
  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>`,
375
+ `<div style="white-space: wrap; font-size: ${LABEL_FONT_SIZE}; color: ${ChartColors.GREY_COLORS[60]}">{point.key}</div></div>`,
436
376
  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>',
377
+ '<span style="color:{point.color}">●</span> {series.name}: <b>{point.y}</b> {point.custom.details}</div>',
438
378
  },
439
379
  xAxis: {
440
380
  gridLineColor: ChartColors.GREY_COLORS[10],
441
381
  lineColor: ChartColors.GREY_COLORS[10],
442
382
  tickColor: ChartColors.GREY_COLORS[10],
443
383
  gridLineWidth: 1,
444
- title: {
445
- text: null,
446
- },
384
+ title: { text: null },
447
385
  labels: {
448
386
  style: {
449
387
  color: ChartColors.GREY_COLORS[85],
450
- fontSize: '12px',
388
+ fontSize: LABEL_FONT_SIZE,
451
389
  },
452
390
  },
453
391
  },
@@ -456,19 +394,14 @@ class ChartOptions {
456
394
  gridLineColor: ChartColors.GREY_COLORS[10],
457
395
  lineColor: ChartColors.GREY_COLORS[10],
458
396
  gridLineWidth: 1,
459
- title: {
460
- text: undefined,
461
- },
397
+ title: { text: undefined },
462
398
  labels: {
463
- formatter: function () {
464
- if (typeof this.value === 'string') {
465
- return this.value;
466
- }
467
- return numberFormat(this.value, -1);
399
+ formatter() {
400
+ return typeof this.value === 'string' ? this.value : numberFormat(this.value, -1);
468
401
  },
469
402
  style: {
470
403
  color: ChartColors.GREY_COLORS[85],
471
- fontSize: '12px',
404
+ fontSize: LABEL_FONT_SIZE,
472
405
  },
473
406
  },
474
407
  },
@@ -479,18 +412,15 @@ class ChartOptions {
479
412
  return mergeDeep(mergeDeep(ChartOptions.DEFAULT_OPTIONS, localeOptions), options);
480
413
  }
481
414
  static configure(series, options, color, labelDateFormat) {
482
- // Configure axis
483
415
  options.xAxis = mergeDeep({
484
416
  labels: {
485
- formatter: function () {
417
+ formatter() {
486
418
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
487
- // @ts-ignore
419
+ // @ts-ignore highcharts callback context types `value` as string | number
488
420
  return dateFormat(labelDateFormat ?? '%m/%d', this.value);
489
421
  },
490
422
  },
491
- //minTickInterval: 24 * 60 * 60 * 1000 // One day
492
423
  }, options.xAxis);
493
- // Configure series
494
424
  if (series?.length) {
495
425
  options.series = series;
496
426
  if (options.legend) {
@@ -500,113 +430,98 @@ class ChartOptions {
500
430
  }
501
431
  }
502
432
  static redrawWithHighestEdgesRounded(chart) {
503
- chart.series.forEach((serie, serieIndex, arr) => {
504
- ChartOptions.roundHighestSerie(arr, serie.options, serieIndex);
433
+ chart.series.forEach((serie, index, all) => {
434
+ ChartOptions.roundHighestSerie(all, serie.options, index);
505
435
  });
506
436
  chart.redraw(true);
507
437
  }
508
438
  static roundHighestSerie(series, serie, serieIndex) {
439
+ if (!serie.data)
440
+ return;
509
441
  const roundedTopMap = [];
510
442
  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
- }
580
- 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]);
443
+ serie.data.forEach((point, columnIndex) => {
444
+ const pointValue = getPointValue(point);
445
+ const pointX = getPointX(point);
446
+ const isNegative = pointValue !== null && pointValue < 0;
447
+ if (isNegative) {
448
+ // Negative bars go downward: the visual tip is the physical bottom.
449
+ // Round bottom corners only on the bottommost segment of the negative stack.
450
+ const isBottommost = series.slice(serieIndex + 1).every(other => {
451
+ if (!other.visible)
452
+ return true;
453
+ const otherPoint = findPointAtAbscissa(other.options.data, pointX, columnIndex);
454
+ if (otherPoint === undefined)
455
+ return true;
456
+ const val = getPointValue(otherPoint);
457
+ return val === null || val >= 0;
458
+ });
459
+ roundedTopMap[columnIndex] = 0;
460
+ roundedBottomMap[columnIndex] = isBottommost ? 100 : 0;
589
461
  }
590
462
  else {
591
- Object.assign(output, { [key]: source[key] });
463
+ // Positive bars go upward: the visual tip is the physical top.
464
+ // Round top corners only on the topmost segment of the positive stack.
465
+ const isTopmost = series.slice(0, serieIndex).every(other => {
466
+ if (!other.visible)
467
+ return true;
468
+ const otherPoint = findPointAtAbscissa(other.options.data, pointX, columnIndex);
469
+ return otherPoint === undefined || getPointValue(otherPoint) === 0;
470
+ });
471
+ roundedTopMap[columnIndex] = isTopmost ? 100 : 0;
472
+ roundedBottomMap[columnIndex] = 0;
592
473
  }
593
474
  });
475
+ serie.borderRadiusTopLeft = roundedTopMap;
476
+ serie.borderRadiusTopRight = roundedTopMap;
477
+ serie.borderRadiusBottomLeft = roundedBottomMap;
478
+ serie.borderRadiusBottomRight = roundedBottomMap;
594
479
  }
595
- return output;
596
480
  }
597
- function deepCopy(source) {
598
- if (typeof source !== 'object' || source === null) {
599
- return source; // Return the value if source is not an object
481
+ function getPointX(point) {
482
+ if (Array.isArray(point))
483
+ return point[0];
484
+ if (point && typeof point === 'object')
485
+ return point.x ?? null;
486
+ return null;
487
+ }
488
+ function getPointValue(point) {
489
+ if (typeof point === 'number')
490
+ return point;
491
+ if (Array.isArray(point))
492
+ return point[1];
493
+ if (point && typeof point === 'object')
494
+ return point.y ?? null;
495
+ return null;
496
+ }
497
+ function findPointAtAbscissa(data, x, fallbackIndex) {
498
+ if (!data)
499
+ return undefined;
500
+ if (x !== null) {
501
+ return data.find(p => getPointX(p) === x);
600
502
  }
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]);
503
+ return data[fallbackIndex];
504
+ }
505
+ /**
506
+ * Deep-merges `source` onto a clone of `target` without mutating either, with one deliberate
507
+ * deviation from `es-toolkit`'s `toMerged`: arrays are treated as opaque values (replaced wholesale)
508
+ * rather than element-merged, which matches how Highcharts options are intended to be overridden.
509
+ */
510
+ function mergeDeep(target, source) {
511
+ if (!isPlainObject(target) || !isPlainObject(source)) {
512
+ return target;
513
+ }
514
+ const output = cloneDeep(target);
515
+ for (const key of Object.keys(source)) {
516
+ const sourceValue = source[key];
517
+ if (isPlainObject(sourceValue)) {
518
+ output[key] = key in target ? mergeDeep(target[key], sourceValue) : cloneDeep(sourceValue);
519
+ }
520
+ else {
521
+ output[key] = sourceValue;
607
522
  }
608
523
  }
609
- return newObject;
524
+ return output;
610
525
  }
611
526
 
612
527
  class ChartBarOptions extends ChartOptions {
@@ -710,41 +625,37 @@ class ChartBarOptions extends ChartOptions {
710
625
  }
711
626
 
712
627
  class ChartBarComponent extends AbstractChartComponent {
713
- categories = [];
714
- opposite = false;
715
- stacked = false;
716
- series = [];
628
+ categories = input([], ...(ngDevMode ? [{ debugName: "categories" }] : []));
629
+ opposite = input(false, ...(ngDevMode ? [{ debugName: "opposite" }] : []));
630
+ stacked = input(false, ...(ngDevMode ? [{ debugName: "stacked" }] : []));
631
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
717
632
  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
- }
633
+ const options = ChartBarOptions.buildBars(this.chartOptions(), this.stacked(), this.opposite(), this.locale());
634
+ ChartBarOptions.configureBar(this.series(), this.categories(), options, this.opposite(), this.color(), this.labelDateFormat());
635
+ this.chart = new Chart(this.hostElement, options);
636
+ if (this.stacked() && !this.opposite()) {
637
+ ChartOptions.redrawWithHighestEdgesRounded(this.chart);
725
638
  }
726
639
  }
727
640
  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" });
641
+ 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
642
  }
730
643
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartBarComponent, decorators: [{
731
644
  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
- }] } });
645
+ args: [{
646
+ selector: 'ap-chart-bar',
647
+ template: '',
648
+ host: { style: 'display: block' },
649
+ changeDetection: ChangeDetectionStrategy.OnPush,
650
+ }]
651
+ }], 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
652
 
743
653
  class ChartColumnOptions extends ChartOptions {
744
654
  static buildColumn(options, stacked, locale) {
745
655
  const column = {
746
656
  borderWidth: 0,
747
- maxPointWidth: 20
657
+ crisp: false,
658
+ maxPointWidth: 20,
748
659
  };
749
660
  if (stacked) {
750
661
  column.stacking = 'normal';
@@ -780,31 +691,30 @@ class ChartColumnOptions extends ChartOptions {
780
691
  }
781
692
 
782
693
  class ChartColumnComponent extends AbstractChartComponent {
783
- series = [];
784
694
  stacked = input(false, ...(ngDevMode ? [{ debugName: "stacked" }] : []));
785
- chartInitialized = new EventEmitter();
695
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
696
+ chartInitialized = output();
786
697
  initChart() {
787
- if (this.series) {
788
- const chartOptions = ChartColumnOptions.buildColumn(this.chartOptions, this.stacked(), this.locale);
789
- ChartColumnOptions.configure(this.series, chartOptions, this.color, this.labelDateFormat);
790
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
791
- if (this.chart && this.stacked()) {
792
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
793
- }
794
- this.chartInitialized.emit(this.chart);
698
+ const options = ChartColumnOptions.buildColumn(this.chartOptions(), this.stacked(), this.locale());
699
+ ChartColumnOptions.configure(this.series(), options, this.color(), this.labelDateFormat());
700
+ this.chart = new Chart(this.hostElement, options);
701
+ if (this.stacked()) {
702
+ ChartOptions.redrawWithHighestEdgesRounded(this.chart);
795
703
  }
704
+ this.chartInitialized.emit(this.chart);
796
705
  }
797
706
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartColumnComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
798
- 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" });
707
+ 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 });
799
708
  }
800
709
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartColumnComponent, decorators: [{
801
710
  type: Component,
802
- args: [{ selector: 'ap-chart-column', standalone: true, template: "<div #chart></div>\n" }]
803
- }], propDecorators: { series: [{
804
- type: Input
805
- }], stacked: [{ type: i0.Input, args: [{ isSignal: true, alias: "stacked", required: false }] }], chartInitialized: [{
806
- type: Output
807
- }] } });
711
+ args: [{
712
+ selector: 'ap-chart-column',
713
+ template: '',
714
+ host: { style: 'display: block' },
715
+ changeDetection: ChangeDetectionStrategy.OnPush,
716
+ }]
717
+ }], 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"] }] } });
808
718
 
809
719
  const HEATMAP_CONSTANTS = {
810
720
  CHART_HEIGHT: 680,
@@ -958,66 +868,28 @@ class ChartHeatmapOptions extends ChartOptions {
958
868
  }
959
869
 
960
870
  class ChartHeatmapComponent extends AbstractChartComponent {
961
- categoriesX = [];
962
- categoriesY = [];
963
- series = [];
871
+ categoriesX = input([], ...(ngDevMode ? [{ debugName: "categoriesX" }] : []));
872
+ categoriesY = input([], ...(ngDevMode ? [{ debugName: "categoriesY" }] : []));
873
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
964
874
  legendLabels = input(...(ngDevMode ? [undefined, { debugName: "legendLabels" }] : []));
965
- legendLabelsEffect = effect(() => {
966
- this.legendLabels();
967
- this.initChart();
968
- }, ...(ngDevMode ? [{ debugName: "legendLabelsEffect" }] : []));
969
875
  initChart() {
970
- if (this.series && this.chartRef) {
971
- const chartOptions = ChartHeatmapOptions.build(this.chartOptions, this.locale);
972
- ChartHeatmapOptions.configureHeatmap(this.categoriesX, this.categoriesY, this.series, chartOptions, this.color, this.legendLabels()?.least, this.legendLabels()?.most, this.labelDateFormat);
973
- mapChart(this.chartRef.nativeElement, chartOptions);
974
- }
876
+ const labels = this.legendLabels();
877
+ const options = ChartHeatmapOptions.build(this.chartOptions(), this.locale());
878
+ ChartHeatmapOptions.configureHeatmap(this.categoriesX(), this.categoriesY(), this.series(), options, this.color(), labels?.least, labels?.most, this.labelDateFormat());
879
+ this.chart = mapChart(this.hostElement, options);
975
880
  }
976
881
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartHeatmapComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
977
- 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" });
882
+ 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 });
978
883
  }
979
884
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartHeatmapComponent, decorators: [{
980
885
  type: Component,
981
- args: [{ selector: 'ap-chart-heatmap', standalone: true, template: "<div #chart></div>\n" }]
982
- }], propDecorators: { categoriesX: [{
983
- type: Input
984
- }], categoriesY: [{
985
- type: Input
986
- }], series: [{
987
- type: Input
988
- }], legendLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "legendLabels", required: false }] }] } });
989
-
990
- var ChartMetricType;
991
- (function (ChartMetricType) {
992
- ChartMetricType[ChartMetricType["default"] = 0] = "default";
993
- ChartMetricType[ChartMetricType["total"] = 1] = "total";
994
- })(ChartMetricType || (ChartMetricType = {}));
995
- class ChartMetric {
996
- children;
997
- name = '';
998
- type;
999
- value = 0;
1000
- }
1001
-
1002
- class ChartMetricsListComponent {
1003
- metrics = [];
1004
- locale = 'en';
1005
- ChartMetricType = ChartMetricType;
1006
- digitsInfo = '1.0-1';
1007
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMetricsListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1008
- 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 });
1009
- }
1010
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMetricsListComponent, decorators: [{
1011
- type: Component,
1012
- 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"] }]
1013
- }], propDecorators: { metrics: [{
1014
- type: Input,
1015
- args: [{
1016
- required: true,
1017
- }]
1018
- }], locale: [{
1019
- type: Input
1020
- }] } });
886
+ args: [{
887
+ selector: 'ap-chart-heatmap',
888
+ template: '',
889
+ host: { style: 'display: block' },
890
+ changeDetection: ChangeDetectionStrategy.OnPush,
891
+ }]
892
+ }], 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 }] }] } });
1021
893
 
1022
894
  class ChartMixedOptions extends ChartOptions {
1023
895
  static buildMixed(options, singleDayEnabled, locale) {
@@ -1060,31 +932,33 @@ class ChartMixedOptions extends ChartOptions {
1060
932
  }
1061
933
 
1062
934
  class ChartMixedComponent extends AbstractChartComponent {
1063
- series = [];
935
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
1064
936
  initChart() {
1065
- if (this.series) {
1066
- const singleDayEnabled = this.series.find(serie => serie.type === 'spline')?.data?.length === 1;
1067
- const chartOptions = ChartMixedOptions.buildMixed(this.chartOptions, singleDayEnabled, this.locale);
1068
- ChartMixedOptions.configure(this.series, chartOptions, this.color, this.labelDateFormat);
1069
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
1070
- if (this.chart) {
1071
- ChartOptions.redrawWithHighestEdgesRounded(this.chart);
1072
- }
1073
- }
937
+ const series = this.series();
938
+ const splineSeries = series.find(serie => serie.type === 'spline');
939
+ const singleDayEnabled = splineSeries?.data?.length === 1;
940
+ const options = ChartMixedOptions.buildMixed(this.chartOptions(), singleDayEnabled, this.locale());
941
+ ChartMixedOptions.configure(series, options, this.color(), this.labelDateFormat());
942
+ this.chart = new Chart(this.hostElement, options);
943
+ ChartOptions.redrawWithHighestEdgesRounded(this.chart);
1074
944
  }
1075
945
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMixedComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1076
- 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" });
946
+ 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 });
1077
947
  }
1078
948
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartMixedComponent, decorators: [{
1079
949
  type: Component,
1080
- args: [{ selector: 'ap-chart-mixed', standalone: true, template: "<div #chart></div>\n" }]
1081
- }], propDecorators: { series: [{
1082
- type: Input
1083
- }] } });
950
+ args: [{
951
+ selector: 'ap-chart-mixed',
952
+ template: '',
953
+ host: { style: 'display: block' },
954
+ changeDetection: ChangeDetectionStrategy.OnPush,
955
+ }]
956
+ }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }] } });
1084
957
 
1085
958
  const NAME_MAX_LENGTH = 30;
1086
- 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
1087
- const RIGHT_TO_LEFT_EMBEDDING_CHARACTER = '\u202B'; // Right-to-left embedding character
959
+ // Hebrew, Arabic, and other RTL scripts
960
+ 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;
961
+ const RIGHT_TO_LEFT_EMBEDDING_CHARACTER = '‫';
1088
962
  class ChartPieOptions extends ChartOptions {
1089
963
  static buildPie(options, innerLabels, metricFormat, locale) {
1090
964
  const defaultPieOptions = {
@@ -1104,51 +978,14 @@ class ChartPieOptions extends ChartOptions {
1104
978
  },
1105
979
  series: {
1106
980
  allowPointSelect: !innerLabels,
1107
- dataLabels: innerLabels
1108
- ? {
1109
- format: metricFormat === 'percentage' ? '{point.percentage:.1f}%' : '{point.y}',
1110
- style: {
1111
- fontSize: '16px',
1112
- color: 'white',
1113
- textOutline: '0',
1114
- },
1115
- }
1116
- : {
1117
- formatter: function () {
1118
- const name = this.name.length > NAME_MAX_LENGTH
1119
- ? this.name.substring(0, NAME_MAX_LENGTH) + '...'
1120
- : this.name;
1121
- const displayValue = metricFormat === 'percentage'
1122
- ? numberFormat(Math.round((this.percentage ?? 0) * 10) / 10, -1) + '%'
1123
- : numberFormat(this.y ?? 0, -1);
1124
- // Add right-to-left embedding character only if the first character is a right-to-left character
1125
- const prefix = RIGHT_TO_LEFT_CHARACTERS.test(this.name.charAt(0))
1126
- ? RIGHT_TO_LEFT_EMBEDDING_CHARACTER
1127
- : '';
1128
- return prefix + name + ': ' + displayValue;
1129
- },
1130
- style: {
1131
- fontSize: '12px',
1132
- color: ChartColors.GREY_COLORS[60],
1133
- },
1134
- },
981
+ dataLabels: innerLabels ? buildInnerLabels(metricFormat) : buildOuterLabels(metricFormat),
1135
982
  showInLegend: innerLabels,
1136
- states: {
1137
- inactive: {
1138
- opacity: 1,
1139
- },
1140
- },
1141
983
  },
1142
984
  },
1143
985
  tooltip: {
1144
986
  outside: true,
1145
987
  },
1146
- legend: innerLabels
1147
- ? {
1148
- symbolHeight: 10,
1149
- enabled: true,
1150
- }
1151
- : {},
988
+ legend: innerLabels ? { symbolHeight: 10, enabled: true } : {},
1152
989
  };
1153
990
  return super.build(mergeDeep(defaultPieOptions, options), locale);
1154
991
  }
@@ -1157,159 +994,83 @@ class ChartPieOptions extends ChartOptions {
1157
994
  if (innerLabels && options.legend) {
1158
995
  options.legend.enabled = true;
1159
996
  }
1160
- if (series && series.length > 0 && series[0]) {
1161
- options.colors = colors;
1162
- if (mouseEventEnabled && options.plotOptions?.pie) {
1163
- this.resetColors(series[0].data, innerLabels);
1164
- options.plotOptions.pie.point ??= {};
1165
- options.plotOptions.pie.point.events ??= {};
1166
- options.plotOptions.pie.events ??= {};
1167
- this.configureEnteringASlice(options, innerLabels);
1168
- this.configureLeavingASlice(options, innerLabels);
1169
- this.configureLeavingTheWholePie(options, innerLabels);
1170
- }
1171
- }
1172
- }
1173
- static resetColors(points, innerLabels) {
1174
- points?.forEach(point => {
1175
- delete point?.color;
1176
- if (innerLabels) {
1177
- delete point.dataLabels?.style?.color;
1178
- }
1179
- });
1180
- }
1181
- static configureEnteringASlice(options, innerLabels) {
1182
- if (options.plotOptions?.pie?.point?.events) {
1183
- options.plotOptions.pie.point.events.mouseOver = function () {
1184
- this.series.chart.series[0].points.forEach(point => {
1185
- if (point.index !== this.index) {
1186
- point.update({
1187
- color: ChartColors.GREY_COLORS[5],
1188
- }, false);
1189
- if (innerLabels) {
1190
- point.update({
1191
- dataLabels: {
1192
- style: {
1193
- color: ChartColors.GREY_COLORS[20],
1194
- },
1195
- },
1196
- }, false);
1197
- }
1198
- }
1199
- });
1200
- this.series.chart.redraw(false);
1201
- };
1202
- }
1203
- }
1204
- static configureLeavingASlice(options, innerLabels) {
1205
- if (options.plotOptions?.pie?.point?.events) {
1206
- options.plotOptions.pie.point.events.mouseOut = function () {
1207
- this.series.chart.series[0].points.forEach((point, i) => {
1208
- if (point.index !== this.index) {
1209
- point.update({
1210
- color: options.colors?.[i % options.colors.length],
1211
- }, false);
1212
- if (innerLabels) {
1213
- point.update({
1214
- dataLabels: {
1215
- style: {
1216
- color: 'white',
1217
- },
1218
- },
1219
- }, false);
1220
- }
1221
- }
1222
- });
1223
- };
997
+ if (!series?.[0]) {
998
+ return;
1224
999
  }
1225
- }
1226
- static configureLeavingTheWholePie(options, innerLabels) {
1227
- if (options.plotOptions?.pie?.events) {
1228
- options.plotOptions.pie.events.mouseOut = function () {
1229
- this.chart.series[0].points.forEach((point, i) => {
1230
- point.update({
1231
- color: options.colors?.[i % options.colors.length],
1232
- }, false);
1233
- if (innerLabels) {
1234
- point.update({
1235
- dataLabels: {
1236
- style: {
1237
- color: 'white',
1238
- },
1239
- },
1240
- }, false);
1241
- }
1242
- });
1243
- this.chart.redraw();
1244
- };
1000
+ options.colors = colors;
1001
+ // When mouse interaction is disabled (e.g. half-donut summary), turn off hover/tooltip
1002
+ // wholesale. Otherwise we rely on Highcharts' default `states.inactive.opacity` (0.2)
1003
+ // to fade non-hovered slices — see https://api.highcharts.com/highcharts/plotOptions.pie.states.inactive
1004
+ if (!mouseEventEnabled) {
1005
+ options.plotOptions ??= {};
1006
+ options.plotOptions.pie ??= {};
1007
+ options.plotOptions.pie.enableMouseTracking = false;
1245
1008
  }
1246
1009
  }
1247
1010
  }
1011
+ function buildInnerLabels(metricFormat) {
1012
+ return {
1013
+ format: metricFormat === 'percentage' ? '{point.percentage:.1f}%' : '{point.y}',
1014
+ style: {
1015
+ fontSize: '16px',
1016
+ color: 'white',
1017
+ textOutline: '0',
1018
+ },
1019
+ };
1020
+ }
1021
+ function buildOuterLabels(metricFormat) {
1022
+ return {
1023
+ formatter() {
1024
+ const truncatedName = this.name.length > NAME_MAX_LENGTH ? this.name.substring(0, NAME_MAX_LENGTH) + '...' : this.name;
1025
+ const displayValue = metricFormat === 'percentage' ? numberFormat(round(this.percentage ?? 0, 1), -1) + '%' : numberFormat(this.y ?? 0, -1);
1026
+ const prefix = RIGHT_TO_LEFT_CHARACTERS.test(this.name.charAt(0)) ? RIGHT_TO_LEFT_EMBEDDING_CHARACTER : '';
1027
+ return prefix + truncatedName + ': ' + displayValue;
1028
+ },
1029
+ style: {
1030
+ fontSize: '12px',
1031
+ color: ChartColors.GREY_COLORS[60],
1032
+ },
1033
+ };
1034
+ }
1248
1035
 
1249
1036
  class ChartPieComponent extends AbstractChartComponent {
1250
- innerLabels = false;
1251
- mouseEventEnabled = true;
1252
- series = [];
1037
+ innerLabels = input(false, ...(ngDevMode ? [{ debugName: "innerLabels" }] : []));
1038
+ mouseEventEnabled = input(true, ...(ngDevMode ? [{ debugName: "mouseEventEnabled" }] : []));
1039
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
1253
1040
  colors = input(...(ngDevMode ? [undefined, { debugName: "colors" }] : []));
1254
1041
  metricFormat = input('percentage', ...(ngDevMode ? [{ debugName: "metricFormat" }] : []));
1255
- domReady = signal(false, ...(ngDevMode ? [{ debugName: "domReady" }] : []));
1256
- constructor() {
1257
- super();
1258
- effect(() => {
1259
- if (this.domReady()) {
1260
- this.colors();
1261
- this.initChart();
1262
- }
1263
- });
1264
- afterNextRender(() => {
1265
- this.domReady.set(true);
1266
- });
1267
- }
1268
1042
  initChart() {
1269
- if (this.series) {
1270
- const dataAvailable = this.series[0]?.data && this.series[0].data.length > 0;
1271
- const chartOptions = ChartPieOptions.buildPie(this.chartOptions, this.innerLabels, this.metricFormat(), this.locale);
1272
- // Add placeholder series when there's no data
1273
- const updatedSeries = dataAvailable
1274
- ? this.series
1275
- : [
1276
- {
1277
- type: 'pie',
1278
- data: [
1279
- {
1280
- y: 1,
1281
- dataLabels: {
1282
- enabled: false,
1283
- },
1284
- },
1285
- ],
1286
- enableMouseTracking: false,
1287
- },
1288
- ];
1289
- let colors = this.colors();
1290
- if (!dataAvailable) {
1291
- colors = [ChartColors.GREY_COLORS[10]];
1292
- }
1293
- else if (!colors?.length) {
1294
- colors = ChartColors.getColors(this.series[0]?.data?.length ?? 0, this.color);
1295
- }
1296
- ChartPieOptions.configurePie(updatedSeries, chartOptions, colors, this.labelDateFormat, this.innerLabels, this.mouseEventEnabled);
1297
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
1298
- }
1043
+ const series = this.series();
1044
+ const innerLabels = this.innerLabels();
1045
+ const dataAvailable = !!series[0]?.data?.length;
1046
+ const options = ChartPieOptions.buildPie(this.chartOptions(), innerLabels, this.metricFormat(), this.locale());
1047
+ const effectiveSeries = dataAvailable
1048
+ ? series
1049
+ : [
1050
+ {
1051
+ type: 'pie',
1052
+ data: [{ y: 1, dataLabels: { enabled: false } }],
1053
+ enableMouseTracking: false,
1054
+ },
1055
+ ];
1056
+ const effectiveColors = !dataAvailable
1057
+ ? [ChartColors.GREY_COLORS[10]]
1058
+ : (this.colors() ?? ChartColors.getColors(series[0]?.data?.length ?? 0, this.color()));
1059
+ ChartPieOptions.configurePie(effectiveSeries, options, effectiveColors, this.labelDateFormat(), innerLabels, this.mouseEventEnabled());
1060
+ this.chart = new Chart(this.hostElement, options);
1299
1061
  }
1300
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartPieComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1301
- 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" });
1062
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartPieComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1063
+ 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 });
1302
1064
  }
1303
1065
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartPieComponent, decorators: [{
1304
1066
  type: Component,
1305
- args: [{ selector: 'ap-chart-pie', standalone: true, template: "<div #chart></div>\n" }]
1306
- }], ctorParameters: () => [], propDecorators: { innerLabels: [{
1307
- type: Input
1308
- }], mouseEventEnabled: [{
1309
- type: Input
1310
- }], series: [{
1311
- type: Input
1312
- }], colors: [{ type: i0.Input, args: [{ isSignal: true, alias: "colors", required: false }] }], metricFormat: [{ type: i0.Input, args: [{ isSignal: true, alias: "metricFormat", required: false }] }] } });
1067
+ args: [{
1068
+ selector: 'ap-chart-pie',
1069
+ template: '',
1070
+ host: { style: 'display: block' },
1071
+ changeDetection: ChangeDetectionStrategy.OnPush,
1072
+ }]
1073
+ }], 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 }] }] } });
1313
1074
 
1314
1075
  class ChartSplineOptions extends ChartOptions {
1315
1076
  static buildSpline(options, singleDayEnabled, locale) {
@@ -1336,36 +1097,34 @@ class ChartSplineOptions extends ChartOptions {
1336
1097
  }
1337
1098
 
1338
1099
  class ChartSplineComponent extends AbstractChartComponent {
1339
- series = [];
1340
- chartInitialized = new EventEmitter();
1100
+ series = input([], ...(ngDevMode ? [{ debugName: "series" }] : []));
1101
+ chartInitialized = output();
1341
1102
  initChart() {
1342
- if (this.series) {
1343
- const chartOptions = ChartSplineOptions.buildSpline(this.chartOptions, this.series[0]?.data?.length === 1, this.locale);
1344
- ChartSplineOptions.configure(this.series, chartOptions, this.color, this.labelDateFormat);
1345
- this.chart = new Chart(this.chartRef.nativeElement, chartOptions);
1346
- this.chartInitialized.emit(this.chart);
1347
- }
1103
+ const series = this.series();
1104
+ const singleDayEnabled = series[0]?.data?.length === 1;
1105
+ const options = ChartSplineOptions.buildSpline(this.chartOptions(), singleDayEnabled, this.locale());
1106
+ ChartSplineOptions.configure(series, options, this.color(), this.labelDateFormat());
1107
+ this.chart = new Chart(this.hostElement, options);
1108
+ this.chartInitialized.emit(this.chart);
1348
1109
  }
1349
1110
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartSplineComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1350
- 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" });
1111
+ 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 });
1351
1112
  }
1352
1113
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: ChartSplineComponent, decorators: [{
1353
1114
  type: Component,
1354
- args: [{ selector: 'ap-chart-spline', standalone: true, template: "<div #chart></div>\n" }]
1355
- }], propDecorators: { series: [{
1356
- type: Input
1357
- }], chartInitialized: [{
1358
- type: Output
1359
- }] } });
1115
+ args: [{
1116
+ selector: 'ap-chart-spline',
1117
+ template: '',
1118
+ host: { style: 'display: block' },
1119
+ changeDetection: ChangeDetectionStrategy.OnPush,
1120
+ }]
1121
+ }], propDecorators: { series: [{ type: i0.Input, args: [{ isSignal: true, alias: "series", required: false }] }], chartInitialized: [{ type: i0.Output, args: ["chartInitialized"] }] } });
1360
1122
 
1361
- /*
1362
- * Public API Surface of ui-charts
1363
- */
1364
1123
  borderRadiusPlugin(Highcharts);
1365
1124
 
1366
1125
  /**
1367
1126
  * Generated bundle index. Do not edit.
1368
1127
  */
1369
1128
 
1370
- export { AbstractChartComponent, ChartBarComponent, ChartColor, ChartColors, ChartColumnComponent, ChartHeatmapComponent, ChartMetric, ChartMetricType, ChartMetricsListComponent, ChartMixedComponent, ChartOptions, ChartPieComponent, ChartSplineComponent, borderRadiusPlugin, mergeDeep };
1129
+ export { AbstractChartComponent, ChartBarComponent, ChartColor, ChartColors, ChartColumnComponent, ChartHeatmapComponent, ChartMixedComponent, ChartOptions, ChartPieComponent, ChartSplineComponent, borderRadiusPlugin, mergeDeep };
1371
1130
  //# sourceMappingURL=agorapulse-ui-charts.mjs.map