@acorex/charts 19.15.0-next.22 → 19.15.0-next.25

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,4 +1,5 @@
1
1
  import { NXComponent } from '@acorex/cdk/common';
2
+ import { AXChartLegendCompatible, AXChartLegendItem } from '@acorex/charts/chart-legend';
2
3
  import { AXChartTooltipData } from '@acorex/charts/chart-tooltip';
3
4
  import { OnDestroy } from '@angular/core';
4
5
  import { AXBarChartClickEvent, AXBarChartData, AXBarChartOption } from './bar-chart.type';
@@ -7,7 +8,7 @@ import * as i0 from "@angular/core";
7
8
  * Bar Chart Component
8
9
  * Renders data as vertical bars with interactive hover effects and animations
9
10
  */
10
- export declare class AXBarChartComponent extends NXComponent implements OnDestroy {
11
+ export declare class AXBarChartComponent extends NXComponent implements OnDestroy, AXChartLegendCompatible {
11
12
  /** Chart data input */
12
13
  data: import("@angular/core").InputSignal<AXBarChartData[]>;
13
14
  /** Chart options input */
@@ -39,6 +40,7 @@ export declare class AXBarChartComponent extends NXComponent implements OnDestro
39
40
  protected tooltipData: import("@angular/core").Signal<AXChartTooltipData>;
40
41
  private configToken;
41
42
  private chartColors;
43
+ private platform;
42
44
  protected effectiveOptions: import("@angular/core").Signal<{
43
45
  width?: number;
44
46
  height?: number;
@@ -54,6 +56,7 @@ export declare class AXBarChartComponent extends NXComponent implements OnDestro
54
56
  animationDuration?: number;
55
57
  animationEasing?: import("@acorex/cdk/common").AXAnimationEasing;
56
58
  }>;
59
+ private hiddenBars;
57
60
  constructor();
58
61
  ngOnDestroy(): void;
59
62
  /**
@@ -112,6 +115,34 @@ export declare class AXBarChartComponent extends NXComponent implements OnDestro
112
115
  * Shows a message when no data is available
113
116
  */
114
117
  private showNoDataMessage;
118
+ /**
119
+ * Shows a message when all bars are hidden
120
+ */
121
+ private showAllBarsHiddenMessage;
122
+ /**
123
+ * Gets the color for a bar based on its index
124
+ */
125
+ protected getColor(index: number): string;
126
+ /**
127
+ * Checks if a bar is hidden
128
+ */
129
+ protected isBarHidden(id: string): boolean;
130
+ /**
131
+ * Implementation of AXChartLegendCompatible interface
132
+ * Returns legend items based on the chart data
133
+ */
134
+ getLegendItems(): AXChartLegendItem[];
135
+ /**
136
+ * Implementation of AXChartLegendCompatible interface
137
+ * Highlights a specific bar by ID
138
+ */
139
+ highlightSegment(id: string | null): void;
140
+ /**
141
+ * Implementation of AXChartLegendCompatible interface
142
+ * Toggles visibility of a bar by ID
143
+ * @returns New visibility state (true = visible, false = hidden)
144
+ */
145
+ toggleSegment(id: string): boolean;
115
146
  static ɵfac: i0.ɵɵFactoryDeclaration<AXBarChartComponent, never>;
116
147
  static ɵcmp: i0.ɵɵComponentDeclaration<AXBarChartComponent, "ax-bar-chart", never, { "data": { "alias": "data"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; }, { "barClick": "barClick"; }, never, never, true, never>;
117
148
  }
@@ -0,0 +1,2 @@
1
+ export * from './lib/chart-legend.component';
2
+ export * from './lib/chart-legend.type';
@@ -0,0 +1,60 @@
1
+ import { ElementRef } from '@angular/core';
2
+ import { AXChartLegendCompatible, AXChartLegendItem, AXChartLegendOptions } from './chart-legend.type';
3
+ import * as i0 from "@angular/core";
4
+ export declare class AXChartLegendComponent {
5
+ /**
6
+ * Chart component instance
7
+ * Must implement AXChartLegendCompatible interface
8
+ */
9
+ chart: import("@angular/core").InputSignal<AXChartLegendCompatible>;
10
+ /**
11
+ * Configuration options for the legend
12
+ */
13
+ options: import("@angular/core").InputSignal<AXChartLegendOptions>;
14
+ /**
15
+ * Event emitted when a legend item is clicked
16
+ * Returns the item that was clicked
17
+ */
18
+ itemClick: import("@angular/core").OutputEmitterRef<AXChartLegendItem>;
19
+ /**
20
+ * Event emitted when the mouse enters a legend item
21
+ */
22
+ itemMouseEnter: import("@angular/core").OutputEmitterRef<AXChartLegendItem>;
23
+ /**
24
+ * Event emitted when the mouse leaves a legend item
25
+ */
26
+ itemMouseLeave: import("@angular/core").OutputEmitterRef<AXChartLegendItem>;
27
+ /**
28
+ * Reference to legend container for measuring dimensions
29
+ */
30
+ legendContainer?: ElementRef<HTMLDivElement>;
31
+ protected showValues: import("@angular/core").Signal<boolean>;
32
+ protected showPercentage: import("@angular/core").Signal<boolean>;
33
+ protected containerClass: import("@angular/core").Signal<{
34
+ [x: string]: boolean;
35
+ 'ax-chart-legend': boolean;
36
+ }>;
37
+ protected isInteractive: import("@angular/core").Signal<boolean>;
38
+ protected displayItems: import("@angular/core").Signal<AXChartLegendItem[]>;
39
+ /**
40
+ * Handle clicks on legend items
41
+ */
42
+ protected onItemClick(item: AXChartLegendItem): void;
43
+ /**
44
+ * Handle mouse enter on legend items
45
+ */
46
+ protected onItemMouseEnter(item: AXChartLegendItem): void;
47
+ /**
48
+ * Handle mouse leave on legend items
49
+ */
50
+ protected onItemMouseLeave(item: AXChartLegendItem): void;
51
+ /**
52
+ * Get legend container dimensions
53
+ */
54
+ getDimensions(): {
55
+ width: number;
56
+ height: number;
57
+ };
58
+ static ɵfac: i0.ɵɵFactoryDeclaration<AXChartLegendComponent, never>;
59
+ static ɵcmp: i0.ɵɵComponentDeclaration<AXChartLegendComponent, "ax-chart-legend", never, { "chart": { "alias": "chart"; "required": true; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; }, { "itemClick": "itemClick"; "itemMouseEnter": "itemMouseEnter"; "itemMouseLeave": "itemMouseLeave"; }, never, never, true, never>;
60
+ }
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Defines a legend item
3
+ */
4
+ export interface AXChartLegendItem {
5
+ id: string;
6
+ name: string;
7
+ value: number | string;
8
+ percentage?: number;
9
+ color?: string;
10
+ hidden?: boolean;
11
+ [key: string]: any;
12
+ }
13
+ /**
14
+ * Interface that chart components should implement to work with the legend
15
+ */
16
+ export interface AXChartLegendCompatible {
17
+ /**
18
+ * Returns the data items for the legend
19
+ */
20
+ getLegendItems(): AXChartLegendItem[];
21
+ /**
22
+ * Highlights a specific segment by ID
23
+ */
24
+ highlightSegment(id: string | null): void;
25
+ /**
26
+ * Toggles visibility of a segment by ID
27
+ * @returns New visibility state (true = visible, false = hidden)
28
+ */
29
+ toggleSegment(id: string): boolean;
30
+ }
31
+ /**
32
+ * Legend configuration options
33
+ */
34
+ export interface AXChartLegendOptions {
35
+ showValues?: boolean;
36
+ showPercentage?: boolean;
37
+ className?: string;
38
+ interactive?: boolean;
39
+ mode?: 'vertical' | 'horizontal';
40
+ }
@@ -1,3 +1,4 @@
1
+ import { AXChartLegendCompatible, AXChartLegendItem } from '@acorex/charts/chart-legend';
1
2
  import { AXChartTooltipData } from '@acorex/charts/chart-tooltip';
2
3
  import { OnDestroy } from '@angular/core';
3
4
  import { AXDonutChartData, AXDonutChartOption, AXDonutChartValue } from './donut-chart.type';
@@ -6,7 +7,8 @@ import * as i0 from "@angular/core";
6
7
  * Donut Chart Component
7
8
  * Displays data in a circular donut chart with interactive segments
8
9
  */
9
- export declare class AXDonutChartComponent implements OnDestroy {
10
+ export declare class AXDonutChartComponent implements OnDestroy, AXChartLegendCompatible {
11
+ #private;
10
12
  private cdr;
11
13
  /** Chart data input */
12
14
  data: import("@angular/core").InputSignal<AXDonutChartValue>;
@@ -25,6 +27,7 @@ export declare class AXDonutChartComponent implements OnDestroy {
25
27
  private hiddenSegments;
26
28
  private _initialized;
27
29
  private _rendered;
30
+ private _isInitialAnimating;
28
31
  private _tooltipVisible;
29
32
  private _tooltipPosition;
30
33
  private _tooltipData;
@@ -121,10 +124,6 @@ export declare class AXDonutChartComponent implements OnDestroy {
121
124
  * Ensures the tooltip is visible by adjusting position when near edges
122
125
  */
123
126
  private updateTooltipPosition;
124
- /**
125
- * Toggles the visibility of a segment
126
- */
127
- private toggleSegmentVisibility;
128
127
  /**
129
128
  * Adds center display with total value
130
129
  */
@@ -141,6 +140,11 @@ export declare class AXDonutChartComponent implements OnDestroy {
141
140
  * Gets an accessibility label describing the donut chart for screen readers
142
141
  */
143
142
  protected getAccessibilityLabel(): string;
143
+ /**
144
+ * Returns the data items for the legend
145
+ * @implements AXChartLegendCompatible
146
+ */
147
+ getLegendItems(): AXChartLegendItem[];
144
148
  static ɵfac: i0.ɵɵFactoryDeclaration<AXDonutChartComponent, never>;
145
149
  static ɵcmp: i0.ɵɵComponentDeclaration<AXDonutChartComponent, "ax-donut-chart", never, { "data": { "alias": "data"; "required": false; "isSignal": true; }; "options": { "alias": "options"; "required": false; "isSignal": true; }; }, { "segmentClick": "segmentClick"; "segmentHover": "segmentHover"; }, never, never, true, never>;
146
150
  }
@@ -1,6 +1,7 @@
1
1
  import { NXComponent } from '@acorex/cdk/common';
2
2
  import { AX_CHART_COLOR_PALETTE, getChartColor } from '@acorex/charts';
3
3
  import { AXChartTooltipComponent } from '@acorex/charts/chart-tooltip';
4
+ import { AXPlatform } from '@acorex/core/platform';
4
5
  import { CommonModule } from '@angular/common';
5
6
  import * as i0 from '@angular/core';
6
7
  import { InjectionToken, inject, input, output, viewChild, signal, computed, afterNextRender, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
@@ -84,6 +85,8 @@ class AXBarChartComponent extends NXComponent {
84
85
  configToken = inject(AX_BAR_CHART_CONFIG);
85
86
  // Inject the chart colors
86
87
  chartColors = inject(AX_CHART_COLOR_PALETTE);
88
+ // Inject AXPlatform
89
+ platform = inject(AXPlatform);
87
90
  // Configuration with defaults
88
91
  effectiveOptions = computed(() => {
89
92
  return {
@@ -91,6 +94,8 @@ class AXBarChartComponent extends NXComponent {
91
94
  ...this.options(),
92
95
  };
93
96
  });
97
+ // Track hidden bars
98
+ hiddenBars = new Set();
94
99
  constructor() {
95
100
  super();
96
101
  // Dynamically load D3 and initialize the chart when the component is ready
@@ -141,6 +146,8 @@ class AXBarChartComponent extends NXComponent {
141
146
  return;
142
147
  const containerElement = this.chartContainerEl().nativeElement;
143
148
  const data = this.data() || [];
149
+ // Filter out hidden bars for visible data
150
+ const visibleData = data.filter((d) => !this.isBarHidden(d.id));
144
151
  // Clear existing chart
145
152
  this.d3.select(containerElement).selectAll('svg').remove();
146
153
  // Early return if no data
@@ -148,11 +155,16 @@ class AXBarChartComponent extends NXComponent {
148
155
  this.showNoDataMessage(containerElement);
149
156
  return;
150
157
  }
158
+ // Early return if all bars are hidden
159
+ if (visibleData.length === 0) {
160
+ this.showAllBarsHiddenMessage(containerElement);
161
+ return;
162
+ }
151
163
  // Get options and setup dimensions
152
164
  const chartOptions = this.effectiveOptions();
153
165
  this.setupDimensions(containerElement, chartOptions);
154
- // Create scales and axes
155
- this.setupScales(data);
166
+ // Create scales and axes using visible data
167
+ this.setupScales(visibleData);
156
168
  this.createAxes(chartOptions);
157
169
  // Render the bars
158
170
  this.renderBars(data);
@@ -266,6 +278,7 @@ class AXBarChartComponent extends NXComponent {
266
278
  const showXAxis = options.showXAxis !== false;
267
279
  const showYAxis = options.showYAxis !== false;
268
280
  const showGrid = options.showGrid !== false;
281
+ const isRtl = this.platform.isRtl();
269
282
  // Create a group for all axes
270
283
  const axesGroup = this.chart.append('g').attr('class', 'ax-bar-chart-axes');
271
284
  if (showXAxis) {
@@ -276,16 +289,17 @@ class AXBarChartComponent extends NXComponent {
276
289
  .attr('transform', `translate(0,${this.height})`)
277
290
  .call(this.d3.axisBottom(this.xScale));
278
291
  // Style the axis text
292
+ const dynamicXAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.width / 45)));
279
293
  this.xAxis
280
294
  .selectAll('text')
281
- .style('font-size', '11px')
295
+ .style('font-size', `${dynamicXAxisTickFontSize}px`)
282
296
  .style('font-weight', '400')
283
297
  .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)');
284
298
  // Style all lines in the x-axis (path, ticks)
285
299
  this.xAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
286
300
  // Add X axis label if provided
287
301
  if (options.xAxisLabel) {
288
- const labelY = this.height + this.margin.bottom * 0.65;
302
+ const labelY = this.height + this.margin.bottom * 0.8;
289
303
  axesGroup
290
304
  .append('text')
291
305
  .attr('class', 'ax-bar-chart-axis-label ax-x-axis-label')
@@ -293,7 +307,7 @@ class AXBarChartComponent extends NXComponent {
293
307
  .attr('dominant-baseline', 'middle')
294
308
  .attr('x', this.width / 2)
295
309
  .attr('y', labelY)
296
- .style('font-size', '13px')
310
+ .style('font-size', '14px')
297
311
  .style('font-weight', '500')
298
312
  .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
299
313
  .text(options.xAxisLabel);
@@ -303,17 +317,21 @@ class AXBarChartComponent extends NXComponent {
303
317
  // Create Y axis
304
318
  this.yAxis = axesGroup.append('g').attr('class', 'ax-bar-chart-axis-y').call(this.d3.axisLeft(this.yScale));
305
319
  // Style the axis text
306
- this.yAxis
320
+ const dynamicYAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.height / 30)));
321
+ const yTickTexts = this.yAxis
307
322
  .selectAll('text')
308
- .style('font-size', '11px')
323
+ .style('font-size', `${dynamicYAxisTickFontSize}px`)
309
324
  .style('font-weight', '400')
310
325
  .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)');
326
+ if (isRtl) {
327
+ yTickTexts.attr('text-anchor', 'start');
328
+ }
311
329
  // Style all lines in the y-axis (path, ticks)
312
330
  this.yAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
313
331
  // Add Y axis label if provided
314
332
  if (options.yAxisLabel) {
315
333
  const labelX = -this.height / 2;
316
- const labelY = -this.margin.left * 0.65;
334
+ const labelY = -this.margin.left * 0.8;
317
335
  axesGroup
318
336
  .append('text')
319
337
  .attr('class', 'ax-bar-chart-axis-label ax-y-axis-label')
@@ -322,7 +340,7 @@ class AXBarChartComponent extends NXComponent {
322
340
  .attr('transform', 'rotate(-90)')
323
341
  .attr('x', labelX)
324
342
  .attr('y', labelY)
325
- .style('font-size', '13px')
343
+ .style('font-size', '14px')
326
344
  .style('font-weight', '500')
327
345
  .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
328
346
  .text(options.yAxisLabel);
@@ -348,6 +366,9 @@ class AXBarChartComponent extends NXComponent {
348
366
  * Renders the bars with animations
349
367
  */
350
368
  renderBars(data) {
369
+ // Filter out hidden bars
370
+ const visibleData = data.filter((d) => !this.isBarHidden(d.id));
371
+ const originalFullData = this.data(); // Get the original full data set
351
372
  // Reset animation state
352
373
  this._initialAnimationComplete.set(false);
353
374
  // Get corner radius from options
@@ -360,7 +381,7 @@ class AXBarChartComponent extends NXComponent {
360
381
  // Create groups for each bar to handle transformations
361
382
  const barGroups = barsContainer
362
383
  .selectAll('.ax-bar-chart-bar-group')
363
- .data(data)
384
+ .data(visibleData)
364
385
  .enter()
365
386
  .append('g')
366
387
  .style('cursor', 'pointer')
@@ -375,7 +396,13 @@ class AXBarChartComponent extends NXComponent {
375
396
  .attr('height', 0) // Start with height 0 for animation
376
397
  .attr('rx', radius) // Rounded corners
377
398
  .attr('ry', radius) // Rounded corners
378
- .attr('fill', (d, i) => d.color || getChartColor(i, this.chartColors));
399
+ .attr('fill', (d) => {
400
+ // Find the index of the current bar (d) in the original data array
401
+ const originalIndex = originalFullData.findIndex((item) => item.id === d.id);
402
+ // Use the original color if provided, otherwise get color from palette using original index
403
+ // Fallback to index 0 if not found, though this shouldn't happen with valid data.
404
+ return d.color || this.getColor(originalIndex !== -1 ? originalIndex : 0);
405
+ });
379
406
  // Add data labels if they're enabled
380
407
  if (this.effectiveOptions().showDataLabels !== false) {
381
408
  barGroups
@@ -478,7 +505,7 @@ class AXBarChartComponent extends NXComponent {
478
505
  handleBarHover(event, datum) {
479
506
  if (this.effectiveOptions().showTooltip !== false) {
480
507
  const index = this.data().findIndex((item) => item.id === datum.id);
481
- const color = datum.color || getChartColor(index, this.chartColors);
508
+ const color = datum.color || this.getColor(index);
482
509
  // Calculate percentage of total
483
510
  const total = this.data().reduce((sum, item) => sum + item.value, 0);
484
511
  const percentage = total > 0 ? ((datum.value / total) * 100).toFixed(1) : '0';
@@ -531,47 +558,211 @@ class AXBarChartComponent extends NXComponent {
531
558
  const messageContainer = this.d3
532
559
  .select(containerElement)
533
560
  .append('div')
534
- .attr('class', 'ax-bar-chart-no-data-message')
535
- .style('position', 'absolute')
536
- .style('left', '50%')
537
- .style('top', '50%')
538
- .style('transform', 'translate(-50%, -50%)')
539
- .style('text-align', 'center')
540
- .style('background-color', 'rgb(var(--ax-comp-bar-chart-bg-color))')
541
- .style('padding', '1.5rem')
542
- .style('border-radius', '0.5rem')
543
- .style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
544
- .style('width', '80%')
545
- .style('max-width', '300px');
561
+ // Apply generic container class, specific bar chart background class, and existing specific class
562
+ .attr('class', 'ax-chart-message-container ax-bar-chart-message-background ax-bar-chart-no-data-message');
546
563
  // Add an icon
547
564
  messageContainer
548
565
  .append('div')
549
- .attr('class', 'ax-bar-chart-no-data-icon')
550
- .style('opacity', '0.6')
551
- .style('margin-bottom', '0.75rem')
566
+ // Apply generic icon class and specific bar chart icon class
567
+ .attr('class', 'ax-chart-message-icon ax-bar-chart-no-data-icon')
552
568
  .html('<i class="fa-light fa-chart-column fa-2x"></i>');
553
569
  // Add text message
554
570
  messageContainer
555
571
  .append('div')
556
- .attr('class', 'ax-bar-chart-no-data-text')
557
- .style('font-size', '1rem')
558
- .style('font-weight', '600')
559
- .style('margin-bottom', '0.5rem')
572
+ // Apply generic text class and specific bar chart text class
573
+ .attr('class', 'ax-chart-message-text ax-bar-chart-no-data-text')
560
574
  .text('No data available');
561
575
  // Add help text
562
576
  messageContainer
563
577
  .append('div')
564
- .attr('class', 'ax-bar-chart-no-data-help')
565
- .style('font-size', '0.8rem')
566
- .style('opacity', '0.6')
578
+ // Apply generic help class and specific bar chart help class
579
+ .attr('class', 'ax-chart-message-help ax-bar-chart-no-data-help')
567
580
  .text('Please provide data to display the chart');
568
581
  }
569
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AXBarChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
570
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.13", type: AXBarChartComponent, isStandalone: true, selector: "ax-bar-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { barClick: "barClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-bar-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-bar-chart-axis-label-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-data-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-bg-color: var(--ax-sys-color-lightest-surface)}ax-bar-chart .ax-bar-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-sys-color-on-lightest-surface));background-color:rgb(var(--ax-comp-bar-chart-bg-color))}ax-bar-chart .ax-bar-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-bar-chart .ax-bar-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);background-color:rgb(var(--ax-comp-bar-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-help{font-size:.8rem;opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
582
+ /**
583
+ * Shows a message when all bars are hidden
584
+ */
585
+ showAllBarsHiddenMessage(containerElement) {
586
+ // Clear existing contents first
587
+ this.d3.select(containerElement).selectAll('*').remove();
588
+ const messageContainer = this.d3
589
+ .select(containerElement)
590
+ .append('div')
591
+ // Apply generic container class, specific bar chart background class, and existing specific class
592
+ .attr('class', 'ax-chart-message-container ax-bar-chart-message-background ax-bar-chart-no-data-message');
593
+ // Add an icon
594
+ messageContainer
595
+ .append('div')
596
+ // Apply generic icon class and specific bar chart icon class
597
+ .attr('class', 'ax-chart-message-icon ax-bar-chart-no-data-icon')
598
+ .html('<i class="fa-light fa-eye-slash fa-2x"></i>');
599
+ // Add text message
600
+ messageContainer
601
+ .append('div')
602
+ // Apply generic text class and specific bar chart text class
603
+ .attr('class', 'ax-chart-message-text ax-bar-chart-no-data-text')
604
+ .text('All bars are hidden');
605
+ // Add help text
606
+ messageContainer
607
+ .append('div')
608
+ // Apply generic help class and specific bar chart help class
609
+ .attr('class', 'ax-chart-message-help ax-bar-chart-no-data-help')
610
+ .text('Click on legend items to show bars');
611
+ }
612
+ /**
613
+ * Gets the color for a bar based on its index
614
+ */
615
+ getColor(index) {
616
+ return getChartColor(index, this.chartColors);
617
+ }
618
+ /**
619
+ * Checks if a bar is hidden
620
+ */
621
+ isBarHidden(id) {
622
+ return this.hiddenBars.has(id);
623
+ }
624
+ /**
625
+ * Implementation of AXChartLegendCompatible interface
626
+ * Returns legend items based on the chart data
627
+ */
628
+ getLegendItems() {
629
+ const data = this.data() || [];
630
+ const total = data.reduce((sum, item) => sum + (typeof item.value === 'number' ? item.value : 0), 0);
631
+ return data.map((item, index) => {
632
+ const value = typeof item.value === 'number' ? item.value : 0;
633
+ const percentage = total > 0 ? (value / total) * 100 : 0;
634
+ return {
635
+ id: item.id,
636
+ name: item.label || `Item ${index + 1}`,
637
+ value: item.value,
638
+ percentage,
639
+ color: item.color || this.getColor(index),
640
+ hidden: this.isBarHidden(item.id),
641
+ };
642
+ });
643
+ }
644
+ /**
645
+ * Implementation of AXChartLegendCompatible interface
646
+ * Highlights a specific bar by ID
647
+ */
648
+ highlightSegment(id) {
649
+ if (!this.svg)
650
+ return;
651
+ // If the bar is hidden, we shouldn't try to highlight it
652
+ if (id !== null && this.isBarHidden(id)) {
653
+ // Just unhighlight everything when trying to highlight a hidden bar
654
+ this.svg
655
+ .selectAll('.ax-bar-chart-bar')
656
+ .classed('ax-bar-chart-highlighted', false)
657
+ .classed('ax-bar-chart-dimmed', false)
658
+ .attr('opacity', 1)
659
+ .attr('filter', null)
660
+ .attr('stroke', null)
661
+ .attr('stroke-width', null)
662
+ .attr('stroke-opacity', null);
663
+ return;
664
+ }
665
+ if (id === null) {
666
+ // If id is null, unhighlight everything
667
+ this.svg
668
+ .selectAll('.ax-bar-chart-bar')
669
+ .classed('ax-bar-chart-highlighted', false)
670
+ .classed('ax-bar-chart-dimmed', false)
671
+ .attr('opacity', 1)
672
+ .attr('filter', null)
673
+ .attr('stroke', null)
674
+ .attr('stroke-width', null)
675
+ .attr('stroke-opacity', null);
676
+ return;
677
+ }
678
+ // Find the target bar
679
+ const targetBar = this.svg.selectAll('.ax-bar-chart-bar').filter((d) => d?.id === id);
680
+ // Safety check - if no matching bar is found, do nothing
681
+ if (targetBar.empty())
682
+ return;
683
+ // Check if the target bar is currently highlighted
684
+ const isCurrentlyHighlighted = targetBar.classed('ax-bar-chart-highlighted');
685
+ if (isCurrentlyHighlighted) {
686
+ // If already highlighted, unhighlight all bars
687
+ this.svg
688
+ .selectAll('.ax-bar-chart-bar')
689
+ .classed('ax-bar-chart-highlighted', false)
690
+ .classed('ax-bar-chart-dimmed', false)
691
+ .attr('opacity', 1)
692
+ .attr('filter', null)
693
+ .attr('stroke', null)
694
+ .attr('stroke-width', null)
695
+ .attr('stroke-opacity', null);
696
+ }
697
+ else {
698
+ // Reset all bars first
699
+ this.svg
700
+ .selectAll('.ax-bar-chart-bar')
701
+ .classed('ax-bar-chart-highlighted', false)
702
+ .classed('ax-bar-chart-dimmed', false)
703
+ .attr('opacity', 1)
704
+ .attr('filter', null)
705
+ .attr('stroke', null)
706
+ .attr('stroke-width', null)
707
+ .attr('stroke-opacity', null);
708
+ // Highlight the target bar
709
+ targetBar
710
+ .classed('ax-bar-chart-highlighted', true)
711
+ .attr('filter', 'drop-shadow(0 0 4px rgba(0, 0, 0, 0.3))')
712
+ .attr('stroke', '#000')
713
+ .attr('stroke-width', '1px')
714
+ .attr('stroke-opacity', '0.3')
715
+ .style('transition', 'all 0.2s ease-in-out');
716
+ // Dim other bars
717
+ this.svg
718
+ .selectAll('.ax-bar-chart-bar')
719
+ .filter((d) => d?.id !== id)
720
+ .classed('ax-bar-chart-dimmed', true)
721
+ .attr('opacity', 0.5)
722
+ .style('transition', 'opacity 0.2s ease-in-out');
723
+ }
724
+ }
725
+ /**
726
+ * Implementation of AXChartLegendCompatible interface
727
+ * Toggles visibility of a bar by ID
728
+ * @returns New visibility state (true = visible, false = hidden)
729
+ */
730
+ toggleSegment(id) {
731
+ const wasAllHidden = this.data().length > 0 && this.data().every((d) => this.isBarHidden(d.id));
732
+ if (this.hiddenBars.has(id)) {
733
+ // Making a bar visible
734
+ this.hiddenBars.delete(id);
735
+ // If all bars were previously hidden, we need to ensure the message is cleared
736
+ if (wasAllHidden) {
737
+ // Force complete DOM cleanup and redraw
738
+ if (this.chartContainerEl()?.nativeElement) {
739
+ // Clear everything in the container
740
+ this.d3?.select(this.chartContainerEl().nativeElement).selectAll('*').remove();
741
+ // Force full redraw
742
+ setTimeout(() => {
743
+ this.createChart();
744
+ }, 0);
745
+ }
746
+ }
747
+ else {
748
+ // Normal update for other cases
749
+ this.updateChart();
750
+ }
751
+ }
752
+ else {
753
+ // Hiding a bar
754
+ this.hiddenBars.add(id);
755
+ this.updateChart();
756
+ }
757
+ // Return the new visibility state
758
+ return !this.hiddenBars.has(id);
759
+ }
760
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AXBarChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
761
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "19.2.14", type: AXBarChartComponent, isStandalone: true, selector: "ax-bar-chart", inputs: { data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { barClick: "barClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-bar-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-bar-chart-axis-label-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-data-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-bg-color: var(--ax-sys-color-lightest-surface)}ax-bar-chart .ax-bar-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-sys-color-on-lightest-surface));background-color:rgb(var(--ax-comp-bar-chart-bg-color))}ax-bar-chart .ax-bar-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-bar-chart .ax-bar-chart-no-data-message{text-align:center;background-color:rgb(var(--ax-comp-bar-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-help{font-size:.8rem;opacity:.6}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
571
762
  }
572
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.13", ngImport: i0, type: AXBarChartComponent, decorators: [{
763
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AXBarChartComponent, decorators: [{
573
764
  type: Component,
574
- args: [{ selector: 'ax-bar-chart', encapsulation: ViewEncapsulation.None, imports: [CommonModule, AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-bar-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-bar-chart-axis-label-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-data-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-bg-color: var(--ax-sys-color-lightest-surface)}ax-bar-chart .ax-bar-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-sys-color-on-lightest-surface));background-color:rgb(var(--ax-comp-bar-chart-bg-color))}ax-bar-chart .ax-bar-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-bar-chart .ax-bar-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);background-color:rgb(var(--ax-comp-bar-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-help{font-size:.8rem;opacity:.6}\n"] }]
765
+ args: [{ selector: 'ax-bar-chart', encapsulation: ViewEncapsulation.None, imports: [CommonModule, AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-bar-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"true\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-bar-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-bar-chart-axis-label-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-data-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-bar-chart-bg-color: var(--ax-sys-color-lightest-surface)}ax-bar-chart .ax-bar-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-sys-color-on-lightest-surface));background-color:rgb(var(--ax-comp-bar-chart-bg-color))}ax-bar-chart .ax-bar-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-bar-chart .ax-bar-chart-no-data-message{text-align:center;background-color:rgb(var(--ax-comp-bar-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-bar-chart .ax-bar-chart-no-data-message .ax-bar-chart-no-data-help{font-size:.8rem;opacity:.6}\n"] }]
575
766
  }], ctorParameters: () => [] });
576
767
 
577
768
  /**