@acorex/charts 20.1.25 → 20.1.26

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.
@@ -17,6 +17,14 @@ const AXBarChartDefaultConfig = {
17
17
  cornerRadius: 4,
18
18
  animationDuration: 800,
19
19
  animationEasing: 'cubic-out',
20
+ messages: {
21
+ noData: 'No data available',
22
+ noDataHelp: 'Please provide data to display the chart',
23
+ allHidden: 'All bars are hidden',
24
+ allHiddenHelp: 'Click on legend items to show bars',
25
+ noDataIcon: 'fa-light fa-chart-column',
26
+ allHiddenIcon: 'fa-light fa-eye-slash',
27
+ },
20
28
  };
21
29
  const AX_BAR_CHART_CONFIG = new InjectionToken('AX_BAR_CHART_CONFIG', {
22
30
  providedIn: 'root',
@@ -94,6 +102,21 @@ class AXBarChartComponent extends NXComponent {
94
102
  ...this.options(),
95
103
  };
96
104
  }, ...(ngDevMode ? [{ debugName: "effectiveOptions" }] : []));
105
+ // Messages with defaults
106
+ effectiveMessages = computed(() => {
107
+ const defaultMessages = {
108
+ noData: 'No data available',
109
+ noDataHelp: 'Please provide data to display the chart',
110
+ allHidden: 'All bars are hidden',
111
+ allHiddenHelp: 'Click on legend items to show bars',
112
+ noDataIcon: 'fa-light fa-chart-column',
113
+ allHiddenIcon: 'fa-light fa-eye-slash',
114
+ };
115
+ return {
116
+ ...defaultMessages,
117
+ ...this.effectiveOptions().messages,
118
+ };
119
+ }, ...(ngDevMode ? [{ debugName: "effectiveMessages" }] : []));
97
120
  // Track hidden bars
98
121
  hiddenBars = new Set();
99
122
  // Track hidden series for clustered charts (by series label)
@@ -173,10 +196,7 @@ class AXBarChartComponent extends NXComponent {
173
196
  hasAnyVisible = visibleSingleData.length > 0;
174
197
  }
175
198
  // Clear existing chart SVG and messages (do not remove tooltip component)
176
- this.d3
177
- .select(containerElement)
178
- .selectAll('svg, .ax-chart-message-container')
179
- .remove();
199
+ this.d3.select(containerElement).selectAll('svg, .ax-chart-message-container').remove();
180
200
  // Early return if no data
181
201
  if (!inputValue.length) {
182
202
  this.showNoDataMessage(containerElement);
@@ -242,34 +262,39 @@ class AXBarChartComponent extends NXComponent {
242
262
  this.width = Math.max(containerWidth, minDim) - this.margin.left - this.margin.right;
243
263
  this.height = Math.max(containerHeight, minDim) - this.margin.top - this.margin.bottom;
244
264
  }
245
- // Create responsive SVG that scales with its container
265
+ // Create responsive SVG with proper coordinate system
266
+ const totalWidth = this.width + this.margin.left + this.margin.right;
267
+ const totalHeight = this.height + this.margin.top + this.margin.bottom;
246
268
  const svg = this.d3
247
269
  .select(containerElement)
248
270
  .append('svg')
249
271
  .attr('width', '100%')
250
272
  .attr('height', '100%')
251
- .attr('viewBox', `0 0 ${this.width + this.margin.left + this.margin.right} ${this.height + this.margin.top + this.margin.bottom}`)
273
+ .attr('viewBox', `0 0 ${totalWidth} ${totalHeight}`)
252
274
  .attr('preserveAspectRatio', 'xMidYMid meet');
253
275
  this.svg = svg;
254
- // Create chart group with margins
255
- this.chart = this.svg.append('g').attr('transform', `translate(${this.margin.left},${this.margin.top})`);
276
+ // Create chart group positioned at margin offsets
277
+ this.chart = this.svg
278
+ .append('g')
279
+ .attr('class', 'chart-content')
280
+ .attr('transform', `translate(${this.margin.left},${this.margin.top})`);
256
281
  }
257
282
  /**
258
283
  * Calculates chart margins based on options
259
284
  */
260
285
  calculateMargins(options, containerWidth) {
261
- // Start with default margins
286
+ // Start with scientifically calculated base margins
262
287
  this.margin = {
263
288
  top: 20,
264
- right: 20,
265
- bottom: 30,
266
- left: 40,
289
+ right: 25,
290
+ bottom: 40,
291
+ left: 60,
267
292
  };
268
293
  const raw = (this.data() || []);
269
294
  const isClustered = this.isClusteredData(raw);
270
295
  const barCount = isClustered
271
296
  ? raw.length
272
- : (raw.filter((d) => !this.isBarHidden(d.id)).length);
297
+ : raw.filter((d) => !this.isBarHidden(d.id)).length;
273
298
  // Pre-emptively increase bottom margin if x-axis labels are likely to be rotated.
274
299
  // This is an estimation before scales and full dimensions are calculated.
275
300
  if (barCount > 0 && containerWidth > 0) {
@@ -285,29 +310,24 @@ class AXBarChartComponent extends NXComponent {
285
310
  return visibleData.reduce((a, b) => (a.length > b.label.length ? a : b.label), '');
286
311
  })();
287
312
  // Estimate font size using the same logic as in createAxes, but with workingWidth.
288
- const estimatedFontSize = Math.max(11, Math.min(15, Math.round(workingWidth / 45)));
289
- // Estimate label width (using 0.6 as an average character width-to-height ratio).
290
- const estimatedLongestLabelWidth = longestLabel.length * estimatedFontSize * 0.6;
313
+ const estimatedFontSize = Math.max(10, Math.min(14, Math.round(workingWidth / 50)));
314
+ // Estimate label width (using 0.65 as character width-to-height ratio for better Persian text support).
315
+ const estimatedLongestLabelWidth = longestLabel.length * estimatedFontSize * 0.65;
291
316
  // If estimated label width is greater than the space available, rotation will occur.
292
317
  if (estimatedLongestLabelWidth > availableWidthPerBar) {
293
318
  // Add space for rotated labels. The height of the rotated label's bounding box
294
- // is roughly its length * sin(45 degrees). Add some padding.
295
- const requiredExtraMargin = estimatedLongestLabelWidth * Math.sin(Math.PI / 4) + 10;
296
- this.margin.bottom += Math.min(60, requiredExtraMargin); // Cap max extra margin.
319
+ // is roughly its length * sin(45 degrees). Add extra padding for Persian text.
320
+ const requiredExtraMargin = estimatedLongestLabelWidth * Math.sin(Math.PI / 4) + 20;
321
+ this.margin.bottom += Math.min(100, requiredExtraMargin); // Increased cap for Persian text.
322
+ // Also ensure minimum space for axis title if present
323
+ if (options.xAxisLabel) {
324
+ // Add substantial extra space for axis title when labels are rotated
325
+ // Account for the increased spacing needed for rotated text bounding box
326
+ this.margin.bottom += 30; // Further increased to match the positioning calculation
327
+ }
297
328
  }
298
329
  }
299
330
  }
300
- // Adjust margins if axis labels are present
301
- if (options.xAxisLabel) {
302
- const xLabelLength = options.xAxisLabel.length;
303
- const extraBottomMargin = Math.min(20, Math.max(10, xLabelLength * 0.8));
304
- this.margin.bottom = Math.max(this.margin.bottom, 30 + extraBottomMargin);
305
- }
306
- if (options.yAxisLabel) {
307
- const yLabelLength = options.yAxisLabel.length;
308
- const extraLeftMargin = Math.min(20, Math.max(10, yLabelLength * 0.8));
309
- this.margin.left = Math.max(this.margin.left, 40 + extraLeftMargin);
310
- }
311
331
  // Ensure enough left margin for Y-axis tick labels (avoid clipping large numbers)
312
332
  if (options.showYAxis !== false && barCount > 0) {
313
333
  const maxValue = (() => {
@@ -330,20 +350,24 @@ class AXBarChartComponent extends NXComponent {
330
350
  })();
331
351
  // Use a localized string to approximate default axis formatter (e.g., includes thousands separators)
332
352
  const exampleTickLabel = Number.isFinite(maxValue) ? maxValue.toLocaleString() : '00000';
333
- // Approximate font size used in axis creation (fallback to 13px here since height isn't finalized yet)
334
- const estimatedYAxisTickFontSize = 13;
335
- // Estimate label width: characters * font size * average char width ratio + padding
336
- const estimatedTickLabelWidth = exampleTickLabel.length * estimatedYAxisTickFontSize * 0.6 + 12;
337
353
  // Reserve additional space for tick mark and padding
338
- this.margin.left = Math.max(this.margin.left, 45, Math.ceil(estimatedTickLabelWidth));
354
+ const maxYAxisLabelWidth = this.calculateMaxYAxisTickLabelWidth();
355
+ const baseYAxisSpace = 25; // Space for axis line and padding
356
+ const yAxisTitleSpace = options.yAxisLabel ? 35 : 0; // Space for Y-axis title if present
357
+ this.margin.left = Math.max(this.margin.left, maxYAxisLabelWidth + baseYAxisSpace + yAxisTitleSpace);
339
358
  }
340
- // Ensure minimum margins for axes
359
+ // Ensure minimum margins meet scientific requirements
341
360
  if (options.showXAxis !== false) {
342
- this.margin.bottom = Math.max(this.margin.bottom, 35);
361
+ this.margin.bottom = Math.max(this.margin.bottom, 40); // Minimum for X-axis
343
362
  }
344
363
  if (options.showYAxis !== false) {
345
- this.margin.left = Math.max(this.margin.left, 45);
364
+ this.margin.left = Math.max(this.margin.left, 60); // Minimum for Y-axis
346
365
  }
366
+ // Ensure final margin integrity
367
+ this.margin.top = Math.max(this.margin.top, 20);
368
+ this.margin.right = Math.max(this.margin.right, 25);
369
+ this.margin.bottom = Math.max(this.margin.bottom, 40);
370
+ this.margin.left = Math.max(this.margin.left, 60);
347
371
  }
348
372
  /**
349
373
  * Creates x and y scales for the chart
@@ -380,11 +404,7 @@ class AXBarChartComponent extends NXComponent {
380
404
  .range([0, this.width])
381
405
  .padding(outerPadding);
382
406
  // Inner band for series
383
- this.xSubScale = this.d3
384
- .scaleBand()
385
- .domain(visibleSeries)
386
- .range([0, this.xScale.bandwidth()])
387
- .padding(0.1);
407
+ this.xSubScale = this.d3.scaleBand().domain(visibleSeries).range([0, this.xScale.bandwidth()]).padding(0.1);
388
408
  // Y scale across all visible values
389
409
  const allVisibleValues = [];
390
410
  for (const g of groups) {
@@ -401,112 +421,178 @@ class AXBarChartComponent extends NXComponent {
401
421
  * Creates x and y axes with grid lines
402
422
  */
403
423
  createAxes(options) {
404
- // Only create axes if they are enabled in options
405
424
  const showXAxis = options.showXAxis !== false;
406
425
  const showYAxis = options.showYAxis !== false;
407
426
  const showGrid = options.showGrid !== false;
408
- // Create a group for all axes
409
427
  const axesGroup = this.chart.append('g').attr('class', 'ax-bar-chart-axes');
410
428
  if (showXAxis) {
411
- // Build a map from id to label for tick formatting
412
- const visibleDataForTicks = (this.data() || []).filter((d) => !this.isBarHidden(d.id));
413
- const idToLabel = new Map(visibleDataForTicks.map((d) => [d.id, d.label]));
414
- // Create X axis
415
- this.xAxis = axesGroup
416
- .append('g')
417
- .attr('class', 'ax-bar-chart-axis-x')
418
- .attr('transform', `translate(0,${this.height})`)
419
- .call(this.d3.axisBottom(this.xScale).tickFormat((id) => idToLabel.get(id) ?? String(id)));
420
- // Style the axis text
421
- const dynamicXAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.width / 45)));
422
- const xAxisTicks = this.xAxis
423
- .selectAll('text')
424
- .style('font-size', `${dynamicXAxisTickFontSize}px`)
425
- .style('font-weight', '400')
426
- .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
427
- .attr('direction', 'ltr');
428
- // Automatically rotate labels if they are likely to overlap
429
- if (this.xScale.domain().length > 0) {
430
- const step = this.xScale.step();
431
- const labelsForRotation = Array.from(idToLabel.values());
432
- const longestLabel = labelsForRotation.reduce((a, b) => (a.length > b.length ? a : b), '');
433
- // Using 0.55 as a safer estimate for char width-to-height ratio
434
- const estimatedLongestLabelWidth = longestLabel.length * dynamicXAxisTickFontSize * 0.55;
435
- if (estimatedLongestLabelWidth > step) {
436
- xAxisTicks
437
- .attr('transform', 'rotate(-45)')
438
- .style('text-anchor', 'end')
439
- .attr('dx', '-0.8em')
440
- .attr('dy', '0.15em');
441
- }
442
- }
443
- // Style all lines in the x-axis (path, ticks)
444
- this.xAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
445
- // Add X axis label if provided
446
- if (options.xAxisLabel) {
447
- const labelY = this.height + this.margin.bottom * 0.8;
448
- axesGroup
449
- .append('text')
450
- .attr('class', 'ax-bar-chart-axis-label ax-x-axis-label')
451
- .attr('text-anchor', 'middle')
452
- .attr('dominant-baseline', 'middle')
453
- .attr('x', this.width / 2)
454
- .attr('y', labelY)
455
- .attr('direction', 'ltr')
456
- .style('font-size', '14px')
457
- .style('font-weight', '500')
458
- .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
459
- .text(options.xAxisLabel);
460
- }
429
+ this.createXAxis(axesGroup, options);
461
430
  }
462
431
  if (showYAxis) {
463
- // Create Y axis
464
- this.yAxis = axesGroup.append('g').attr('class', 'ax-bar-chart-axis-y').call(this.d3.axisLeft(this.yScale));
465
- // Style the axis text
466
- const dynamicYAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.height / 30)));
467
- this.yAxis
468
- .selectAll('text')
469
- .style('font-size', `${dynamicYAxisTickFontSize}px`)
470
- .style('font-weight', '400')
471
- .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
472
- .attr('text-anchor', 'end')
473
- .attr('direction', 'ltr');
474
- // Style all lines in the y-axis (path, ticks)
475
- this.yAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
476
- // Add Y axis label if provided
477
- if (options.yAxisLabel) {
478
- const labelX = -this.height / 2;
479
- const labelY = -this.margin.left * 0.8;
480
- axesGroup
481
- .append('text')
482
- .attr('class', 'ax-bar-chart-axis-label ax-y-axis-label')
483
- .attr('text-anchor', 'middle')
484
- .attr('dominant-baseline', 'middle')
485
- .attr('transform', 'rotate(-90)')
486
- .attr('x', labelX)
487
- .attr('y', labelY)
488
- .attr('direction', 'ltr')
489
- .style('font-size', '14px')
490
- .style('font-weight', '500')
491
- .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
492
- .text(options.yAxisLabel);
493
- }
432
+ this.createYAxis(axesGroup, options);
494
433
  }
495
434
  if (showGrid) {
496
- // Add horizontal grid lines
497
- this.chart
498
- .append('g')
499
- .attr('class', 'ax-bar-chart-grid')
500
- .call(this.d3
501
- .axisLeft(this.yScale)
502
- .tickSize(-this.width)
503
- .tickFormat(() => ''))
504
- .selectAll('line')
505
- .style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))')
506
- .style('stroke-opacity', 0.2);
507
- // Remove unneeded elements from grid
508
- this.chart.select('.ax-bar-chart-grid').selectAll('path, text').remove();
435
+ this.createGridLines();
436
+ }
437
+ }
438
+ createXAxis(axesGroup, options) {
439
+ // Build a map from id to label for tick formatting
440
+ const visibleDataForTicks = (this.data() || []).filter((d) => !this.isBarHidden(d.id));
441
+ const idToLabel = new Map(visibleDataForTicks.map((d) => [d.id, d.label]));
442
+ // Create X axis
443
+ this.xAxis = axesGroup
444
+ .append('g')
445
+ .attr('class', 'ax-bar-chart-axis-x')
446
+ .attr('transform', `translate(0,${this.height})`)
447
+ .call(this.d3.axisBottom(this.xScale).tickFormat((id) => idToLabel.get(id) ?? String(id)));
448
+ // Style the axis text - optimized font size for Persian text
449
+ const dynamicFontSize = Math.max(10, Math.min(14, Math.round(this.width / 50)));
450
+ const xAxisTicks = this.xAxis
451
+ .selectAll('text')
452
+ .style('font-size', `${dynamicFontSize}px`)
453
+ .style('font-weight', '400')
454
+ .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
455
+ .attr('direction', 'ltr');
456
+ // Handle label rotation for long Persian text
457
+ const isRotated = this.shouldRotateXAxisLabels(idToLabel, dynamicFontSize);
458
+ if (isRotated) {
459
+ xAxisTicks.attr('transform', 'rotate(-45)').style('text-anchor', 'end').attr('dx', '-0.8em').attr('dy', '0.15em');
460
+ }
461
+ // Style axis lines
462
+ this.xAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
463
+ // Add X axis title with proper spacing
464
+ if (options.xAxisLabel) {
465
+ this.createXAxisTitle(axesGroup, options.xAxisLabel, isRotated);
466
+ }
467
+ }
468
+ createYAxis(axesGroup, options) {
469
+ // Create Y axis
470
+ this.yAxis = axesGroup.append('g').attr('class', 'ax-bar-chart-axis-y').call(this.d3.axisLeft(this.yScale));
471
+ // Style the axis text
472
+ const dynamicFontSize = Math.max(11, Math.min(15, Math.round(this.height / 30)));
473
+ this.yAxis
474
+ .selectAll('text')
475
+ .style('font-size', `${dynamicFontSize}px`)
476
+ .style('font-weight', '400')
477
+ .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
478
+ .attr('text-anchor', 'end')
479
+ .attr('direction', 'ltr');
480
+ // Style axis lines
481
+ this.yAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
482
+ // Add Y axis title
483
+ if (options.yAxisLabel) {
484
+ this.createYAxisTitle(axesGroup, options.yAxisLabel);
485
+ }
486
+ }
487
+ shouldRotateXAxisLabels(idToLabel, fontSize) {
488
+ if (this.xScale.domain().length === 0)
489
+ return false;
490
+ const step = this.xScale.step();
491
+ const labels = Array.from(idToLabel.values());
492
+ const longestLabel = labels.reduce((a, b) => (a.length > b.length ? a : b), '');
493
+ const estimatedWidth = longestLabel.length * fontSize * 0.65; // Persian text ratio
494
+ return estimatedWidth > step;
495
+ }
496
+ createXAxisTitle(axesGroup, title, isRotated) {
497
+ // Calculate the exact position relative to the SVG coordinate system
498
+ // X-axis is positioned at Y = this.height within the chart group
499
+ // Chart group is translated by (margin.left, margin.top)
500
+ // So X-axis is at Y = margin.top + this.height in SVG coordinates
501
+ let titleOffset;
502
+ if (isRotated) {
503
+ // For 45° rotated text, we need to account for the diagonal bounding box
504
+ // The rotated text extends both horizontally and vertically from the baseline
505
+ const fontSize = 13; // Approximate font size for tick labels
506
+ const textLength = title.length;
507
+ // For 45° rotation, vertical extent = textLength * fontSize * sin(45°) + fontSize * cos(45°)
508
+ const verticalExtent = textLength * fontSize * 0.707 + fontSize * 0.707;
509
+ titleOffset = verticalExtent + 20; // Add padding
510
+ }
511
+ else {
512
+ // For horizontal text, account for font height + padding
513
+ const fontSize = 13; // Approximate font size for tick labels
514
+ titleOffset = fontSize + 12; // Font height + padding
509
515
  }
516
+ // Position the title below the X-axis line
517
+ const labelY = this.height + titleOffset;
518
+ axesGroup
519
+ .append('text')
520
+ .attr('class', 'ax-bar-chart-axis-label ax-x-axis-label')
521
+ .attr('text-anchor', 'middle')
522
+ .attr('dominant-baseline', 'hanging') // Align to top of text for better positioning
523
+ .attr('x', this.width / 2)
524
+ .attr('y', labelY)
525
+ .attr('direction', 'ltr')
526
+ .style('font-size', '14px')
527
+ .style('font-weight', '500')
528
+ .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
529
+ .text(title);
530
+ }
531
+ createYAxisTitle(axesGroup, title) {
532
+ // Calculate the exact position for Y-axis title
533
+ // Y-axis tick labels use text-anchor: end, so they extend LEFT of the Y-axis line
534
+ // Y-axis is at X = 0 within the chart group
535
+ // Chart group is translated by (margin.left, margin.top)
536
+ // So Y-axis is at X = margin.left in SVG coordinates
537
+ const maxTickLabelWidth = this.calculateMaxYAxisTickLabelWidth();
538
+ const padding = 15; // Padding between tick labels and axis title
539
+ // Position title to the left of the tick labels
540
+ // Since text-anchor: end aligns the text to the Y-axis, we need to go further left
541
+ const labelY = -maxTickLabelWidth - padding;
542
+ // Center the title vertically
543
+ const labelX = -this.height / 2;
544
+ axesGroup
545
+ .append('text')
546
+ .attr('class', 'ax-bar-chart-axis-label ax-y-axis-label')
547
+ .attr('text-anchor', 'middle')
548
+ .attr('dominant-baseline', 'middle')
549
+ .attr('transform', 'rotate(-90)')
550
+ .attr('x', labelX)
551
+ .attr('y', labelY)
552
+ .attr('direction', 'ltr')
553
+ .style('font-size', '14px')
554
+ .style('font-weight', '500')
555
+ .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
556
+ .text(title);
557
+ }
558
+ calculateMaxYAxisTickLabelWidth() {
559
+ // Calculate the maximum width needed for Y-axis tick labels
560
+ const raw = (this.data() || []);
561
+ const isClustered = this.isClusteredData(raw);
562
+ let maxValue = 0;
563
+ if (isClustered) {
564
+ const groups = raw;
565
+ const seriesLabels = groups.length > 0 ? this.getClusterSeriesLabels(groups) : [];
566
+ const visibleSeries = seriesLabels.filter((s) => !this.hiddenSeries.has(s));
567
+ for (const g of groups) {
568
+ visibleSeries.forEach((_, idx) => {
569
+ const item = g.chartData[idx];
570
+ if (item && typeof item.value === 'number')
571
+ maxValue = Math.max(maxValue, item.value);
572
+ });
573
+ }
574
+ }
575
+ else {
576
+ const visibleData = raw.filter((d) => !this.isBarHidden(d.id));
577
+ maxValue = visibleData.reduce((acc, d) => (d.value > acc ? d.value : acc), 0);
578
+ }
579
+ const tickLabelText = Number.isFinite(maxValue) ? maxValue.toLocaleString() : '00000';
580
+ const fontSize = 13; // Approximate font size for Y-axis tick labels
581
+ return tickLabelText.length * fontSize * 0.6 + 8; // Character width + padding
582
+ }
583
+ createGridLines() {
584
+ this.chart
585
+ .append('g')
586
+ .attr('class', 'ax-bar-chart-grid')
587
+ .call(this.d3
588
+ .axisLeft(this.yScale)
589
+ .tickSize(-this.width)
590
+ .tickFormat(() => ''))
591
+ .selectAll('line')
592
+ .style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))')
593
+ .style('stroke-opacity', 0.2);
594
+ // Remove unneeded elements from grid
595
+ this.chart.select('.ax-bar-chart-grid').selectAll('path, text').remove();
510
596
  }
511
597
  /**
512
598
  * Creates axes for clustered charts
@@ -517,83 +603,41 @@ class AXBarChartComponent extends NXComponent {
517
603
  const showGrid = options.showGrid !== false;
518
604
  const axesGroup = this.chart.append('g').attr('class', 'ax-bar-chart-axes');
519
605
  if (showXAxis) {
520
- const idToLabel = new Map(groups.map((g) => [g.id, g.label]));
521
- this.xAxis = axesGroup
522
- .append('g')
523
- .attr('class', 'ax-bar-chart-axis-x')
524
- .attr('transform', `translate(0,${this.height})`)
525
- .call(this.d3.axisBottom(this.xScale).tickFormat((id) => idToLabel.get(id) ?? String(id)));
526
- const dynamicXAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.width / 45)));
527
- const xAxisTicks = this.xAxis
528
- .selectAll('text')
529
- .style('font-size', `${dynamicXAxisTickFontSize}px`)
530
- .style('font-weight', '400')
531
- .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
532
- .attr('direction', 'ltr');
533
- if (this.xScale.domain().length > 0) {
534
- const step = this.xScale.step();
535
- const labelsForRotation = Array.from(idToLabel.values());
536
- const longestLabel = labelsForRotation.reduce((a, b) => (a.length > b.length ? a : b), '');
537
- const estimatedLongestLabelWidth = longestLabel.length * dynamicXAxisTickFontSize * 0.55;
538
- if (estimatedLongestLabelWidth > step) {
539
- xAxisTicks.attr('transform', 'rotate(-45)').style('text-anchor', 'end').attr('dx', '-0.8em').attr('dy', '0.15em');
540
- }
541
- }
542
- this.xAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
543
- if (options.xAxisLabel) {
544
- const labelY = this.height + this.margin.bottom * 0.8;
545
- axesGroup
546
- .append('text')
547
- .attr('class', 'ax-bar-chart-axis-label ax-x-axis-label')
548
- .attr('text-anchor', 'middle')
549
- .attr('dominant-baseline', 'middle')
550
- .attr('x', this.width / 2)
551
- .attr('y', labelY)
552
- .attr('direction', 'ltr')
553
- .style('font-size', '14px')
554
- .style('font-weight', '500')
555
- .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
556
- .text(options.xAxisLabel);
557
- }
606
+ this.createXAxisClustered(axesGroup, options, groups);
558
607
  }
559
608
  if (showYAxis) {
560
- this.yAxis = axesGroup.append('g').attr('class', 'ax-bar-chart-axis-y').call(this.d3.axisLeft(this.yScale));
561
- const dynamicYAxisTickFontSize = Math.max(11, Math.min(15, Math.round(this.height / 30)));
562
- this.yAxis
563
- .selectAll('text')
564
- .style('font-size', `${dynamicYAxisTickFontSize}px`)
565
- .style('font-weight', '400')
566
- .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
567
- .attr('text-anchor', 'end')
568
- .attr('direction', 'ltr');
569
- this.yAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
570
- if (options.yAxisLabel) {
571
- const labelX = -this.height / 2;
572
- const labelY = -this.margin.left * 0.8;
573
- axesGroup
574
- .append('text')
575
- .attr('class', 'ax-bar-chart-axis-label ax-y-axis-label')
576
- .attr('text-anchor', 'middle')
577
- .attr('dominant-baseline', 'middle')
578
- .attr('transform', 'rotate(-90)')
579
- .attr('x', labelX)
580
- .attr('y', labelY)
581
- .attr('direction', 'ltr')
582
- .style('font-size', '14px')
583
- .style('font-weight', '500')
584
- .style('fill', 'rgb(var(--ax-comp-bar-chart-axis-label-color))')
585
- .text(options.yAxisLabel);
586
- }
609
+ this.createYAxis(axesGroup, options);
587
610
  }
588
611
  if (showGrid) {
589
- this.chart
590
- .append('g')
591
- .attr('class', 'ax-bar-chart-grid')
592
- .call(this.d3.axisLeft(this.yScale).tickSize(-this.width).tickFormat(() => ''))
593
- .selectAll('line')
594
- .style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))')
595
- .style('stroke-opacity', 0.2);
596
- this.chart.select('.ax-bar-chart-grid').selectAll('path, text').remove();
612
+ this.createGridLines();
613
+ }
614
+ }
615
+ createXAxisClustered(axesGroup, options, groups) {
616
+ const idToLabel = new Map(groups.map((g) => [g.id, g.label]));
617
+ // Create X axis
618
+ this.xAxis = axesGroup
619
+ .append('g')
620
+ .attr('class', 'ax-bar-chart-axis-x')
621
+ .attr('transform', `translate(0,${this.height})`)
622
+ .call(this.d3.axisBottom(this.xScale).tickFormat((id) => idToLabel.get(id) ?? String(id)));
623
+ // Style the axis text - optimized font size for Persian text
624
+ const dynamicFontSize = Math.max(10, Math.min(14, Math.round(this.width / 50)));
625
+ const xAxisTicks = this.xAxis
626
+ .selectAll('text')
627
+ .style('font-size', `${dynamicFontSize}px`)
628
+ .style('font-weight', '400')
629
+ .style('fill', 'rgba(var(--ax-comp-bar-chart-labels-color), 0.7)')
630
+ .attr('direction', 'ltr');
631
+ // Handle label rotation for long Persian text
632
+ const isRotated = this.shouldRotateXAxisLabels(idToLabel, dynamicFontSize);
633
+ if (isRotated) {
634
+ xAxisTicks.attr('transform', 'rotate(-45)').style('text-anchor', 'end').attr('dx', '-0.8em').attr('dy', '0.15em');
635
+ }
636
+ // Style axis lines
637
+ this.xAxis.selectAll('line, path').style('stroke', 'rgb(var(--ax-comp-bar-chart-grid-lines-color))');
638
+ // Add X axis title with proper spacing
639
+ if (options.xAxisLabel) {
640
+ this.createXAxisTitle(axesGroup, options.xAxisLabel, isRotated);
597
641
  }
598
642
  }
599
643
  /**
@@ -622,14 +666,24 @@ class AXBarChartComponent extends NXComponent {
622
666
  .attr('class', 'ax-bar-chart-bar-group');
623
667
  // Add bars inside groups
624
668
  const bars = barGroups
625
- .append('rect')
669
+ .append('path')
626
670
  .attr('class', 'ax-bar-chart-bar')
627
- .attr('x', (d) => this.xScale(d.id))
628
- .attr('width', this.xScale.bandwidth())
629
- .attr('y', this.height) // Start from bottom for animation
630
- .attr('height', 0) // Start with height 0 for animation
631
- .attr('rx', radius) // Rounded corners
632
- .attr('ry', radius) // Rounded corners
671
+ .attr('d', (d) => {
672
+ const x = this.xScale(d.id);
673
+ const width = this.xScale.bandwidth();
674
+ const y = this.height - 0.5; // Add small gap to prevent overlap with x-axis
675
+ const height = 0;
676
+ // Create path with only top corners rounded
677
+ if (radius > 0 && height > 0) {
678
+ const topY = y - height;
679
+ // Limit radius to prevent it from exceeding half the bar width
680
+ const effectiveRadius = Math.min(radius, width / 2);
681
+ return `M${x},${y} L${x},${topY + effectiveRadius} Q${x},${topY} ${x + effectiveRadius},${topY} L${x + width - effectiveRadius},${topY} Q${x + width},${topY} ${x + width},${topY + effectiveRadius} L${x + width},${y} Z`;
682
+ }
683
+ else {
684
+ return `M${x},${y} L${x},${y - height} L${x + width},${y - height} L${x + width},${y} Z`;
685
+ }
686
+ })
633
687
  .attr('fill', (d) => {
634
688
  // Find the index of the current bar (d) in the original data array
635
689
  const originalIndex = originalFullData.findIndex((item) => item.id === d.id);
@@ -666,7 +720,7 @@ class AXBarChartComponent extends NXComponent {
666
720
  // Only apply hover effects if initial animation is complete
667
721
  if (!this._initialAnimationComplete())
668
722
  return;
669
- const barEl = this.d3.select(event.currentTarget).select('rect');
723
+ const barEl = this.d3.select(event.currentTarget).select('path');
670
724
  // Standard hover effect - darken the bar slightly and add a subtle shadow
671
725
  barEl.transition().duration(150).style('filter', 'brightness(0.7) drop-shadow(0 0 2px rgba(0,0,0,0.1))');
672
726
  this.handleBarHover(event, d);
@@ -681,7 +735,7 @@ class AXBarChartComponent extends NXComponent {
681
735
  // Only apply hover effects if initial animation is complete
682
736
  if (!this._initialAnimationComplete())
683
737
  return;
684
- const barEl = this.d3.select(event.currentTarget).select('rect');
738
+ const barEl = this.d3.select(event.currentTarget).select('path');
685
739
  // Remove hover effect
686
740
  barEl.transition().duration(150).style('filter', null);
687
741
  this._tooltipVisible.set(false);
@@ -697,8 +751,24 @@ class AXBarChartComponent extends NXComponent {
697
751
  .transition()
698
752
  .duration(animationDuration)
699
753
  .delay((d, i) => i * 50) // Stagger each bar animation
700
- .attr('y', (d) => this.yScale(d.value))
701
- .attr('height', (d) => this.height - this.yScale(d.value))
754
+ .attrTween('d', (d) => {
755
+ const x = this.xScale(d.id);
756
+ const width = this.xScale.bandwidth();
757
+ const finalHeight = this.height - this.yScale(d.value);
758
+ return (t) => {
759
+ const currentHeight = finalHeight * t;
760
+ const currentY = this.height - currentHeight;
761
+ const bottomY = this.height - 0.5; // Add small gap to prevent overlap with x-axis
762
+ if (radius > 0 && currentHeight > 0) {
763
+ // Limit radius to prevent it from exceeding half the bar width
764
+ const effectiveRadius = Math.min(radius, width / 2);
765
+ return `M${x},${bottomY} L${x},${currentY + effectiveRadius} Q${x},${currentY} ${x + effectiveRadius},${currentY} L${x + width - effectiveRadius},${currentY} Q${x + width},${currentY} ${x + width},${currentY + effectiveRadius} L${x + width},${bottomY} Z`;
766
+ }
767
+ else {
768
+ return `M${x},${bottomY} L${x},${currentY} L${x + width},${currentY} L${x + width},${bottomY} Z`;
769
+ }
770
+ };
771
+ })
702
772
  .ease(animationEasing) // Use the configured easing function
703
773
  .end() // Wait for all animations to complete
704
774
  .then(() => {
@@ -732,15 +802,25 @@ class AXBarChartComponent extends NXComponent {
732
802
  .style('cursor', 'pointer')
733
803
  .attr('class', 'ax-bar-chart-bar-group');
734
804
  const bars = barGroups
735
- .append('rect')
805
+ .append('path')
736
806
  .attr('class', 'ax-bar-chart-bar')
737
807
  .attr('data-series', (d) => d.seriesLabel)
738
- .attr('x', (d) => this.xSubScale(d.seriesLabel))
739
- .attr('width', this.xSubScale.bandwidth())
740
- .attr('y', this.height)
741
- .attr('height', 0)
742
- .attr('rx', radius)
743
- .attr('ry', radius)
808
+ .attr('d', (d) => {
809
+ const x = this.xSubScale(d.seriesLabel);
810
+ const width = this.xSubScale.bandwidth();
811
+ const y = this.height - 0.5; // Add small gap to prevent overlap with x-axis
812
+ const height = 0;
813
+ // Create path with only top corners rounded
814
+ if (radius > 0 && height > 0) {
815
+ const topY = y - height;
816
+ // Limit radius to prevent it from exceeding half the bar width
817
+ const effectiveRadius = Math.min(radius, width / 2);
818
+ return `M${x},${y} L${x},${topY + effectiveRadius} Q${x},${topY} ${x + effectiveRadius},${topY} L${x + width - effectiveRadius},${topY} Q${x + width},${topY} ${x + width},${topY + effectiveRadius} L${x + width},${y} Z`;
819
+ }
820
+ else {
821
+ return `M${x},${y} L${x},${y - height} L${x + width},${y - height} L${x + width},${y} Z`;
822
+ }
823
+ })
744
824
  .attr('fill', (d) => {
745
825
  const item = d.group.chartData[d.seriesIndex];
746
826
  const colorIndex = d.seriesIndex;
@@ -777,7 +857,7 @@ class AXBarChartComponent extends NXComponent {
777
857
  .on('mouseenter', (event, d) => {
778
858
  if (!this._initialAnimationComplete())
779
859
  return;
780
- const barEl = this.d3.select(event.currentTarget).select('rect');
860
+ const barEl = this.d3.select(event.currentTarget).select('path');
781
861
  barEl.transition().duration(150).style('filter', 'brightness(0.7) drop-shadow(0 0 2px rgba(0,0,0,0.1))');
782
862
  const item = d.group.chartData[d.seriesIndex];
783
863
  if (item)
@@ -790,7 +870,7 @@ class AXBarChartComponent extends NXComponent {
790
870
  .on('mouseleave', (event) => {
791
871
  if (!this._initialAnimationComplete())
792
872
  return;
793
- const barEl = this.d3.select(event.currentTarget).select('rect');
873
+ const barEl = this.d3.select(event.currentTarget).select('path');
794
874
  barEl.transition().duration(150).style('filter', null);
795
875
  this._tooltipVisible.set(false);
796
876
  })
@@ -805,13 +885,24 @@ class AXBarChartComponent extends NXComponent {
805
885
  .transition()
806
886
  .duration(animationDuration)
807
887
  .delay((_, i) => i * 50)
808
- .attr('y', (d) => {
809
- const item = d.group.chartData[d.seriesIndex];
810
- return item ? this.yScale(item.value) : this.height;
811
- })
812
- .attr('height', (d) => {
888
+ .attrTween('d', (d) => {
889
+ const x = this.xSubScale(d.seriesLabel);
890
+ const width = this.xSubScale.bandwidth();
813
891
  const item = d.group.chartData[d.seriesIndex];
814
- return item ? this.height - this.yScale(item.value) : 0;
892
+ const finalHeight = item ? this.height - this.yScale(item.value) : 0;
893
+ return (t) => {
894
+ const currentHeight = finalHeight * t;
895
+ const currentY = this.height - currentHeight;
896
+ const bottomY = this.height - 0.5; // Add small gap to prevent overlap with x-axis
897
+ if (radius > 0 && currentHeight > 0) {
898
+ // Limit radius to prevent it from exceeding half the bar width
899
+ const effectiveRadius = Math.min(radius, width / 2);
900
+ return `M${x},${bottomY} L${x},${currentY + effectiveRadius} Q${x},${currentY} ${x + effectiveRadius},${currentY} L${x + width - effectiveRadius},${currentY} Q${x + width},${currentY} ${x + width},${currentY + effectiveRadius} L${x + width},${bottomY} Z`;
901
+ }
902
+ else {
903
+ return `M${x},${bottomY} L${x},${currentY} L${x + width},${currentY} L${x + width},${bottomY} Z`;
904
+ }
905
+ };
815
906
  })
816
907
  .ease(animationEasing)
817
908
  .end()
@@ -853,7 +944,7 @@ class AXBarChartComponent extends NXComponent {
853
944
  const isClustered = this.isClusteredData(dataValue);
854
945
  const flatData = isClustered
855
946
  ? dataValue.flatMap((g) => g.chartData)
856
- : (dataValue || []);
947
+ : dataValue || [];
857
948
  const index = flatData.findIndex((item) => item.id === datum.id && item.label === datum.label);
858
949
  const color = datum.color || this.getColor(index !== -1 ? index : 0);
859
950
  // Calculate percentage of total
@@ -862,7 +953,7 @@ class AXBarChartComponent extends NXComponent {
862
953
  : flatData.reduce((sum, item) => sum + item.value, 0);
863
954
  const percentage = total > 0 ? ((datum.value / total) * 100).toFixed(1) : '0';
864
955
  this._tooltipData.set({
865
- title: group ? `${datum.tooltipLabel || datum.label} — ${group.label}` : (datum.tooltipLabel || datum.label),
956
+ title: group ? `${datum.tooltipLabel || datum.label} — ${group.label}` : datum.tooltipLabel || datum.label,
866
957
  value: datum.value.toString(),
867
958
  percentage: `${percentage}%`,
868
959
  color: color,
@@ -917,19 +1008,19 @@ class AXBarChartComponent extends NXComponent {
917
1008
  .append('div')
918
1009
  // Apply generic icon class and specific bar chart icon class
919
1010
  .attr('class', 'ax-chart-message-icon ax-bar-chart-no-data-icon')
920
- .html('<i class="fa-light fa-chart-column fa-2x"></i>');
1011
+ .html(`<i class="${this.effectiveMessages().noDataIcon} fa-2x"></i>`);
921
1012
  // Add text message
922
1013
  messageContainer
923
1014
  .append('div')
924
1015
  // Apply generic text class and specific bar chart text class
925
1016
  .attr('class', 'ax-chart-message-text ax-bar-chart-no-data-text')
926
- .text('No data available');
1017
+ .text(this.effectiveMessages().noData);
927
1018
  // Add help text
928
1019
  messageContainer
929
1020
  .append('div')
930
1021
  // Apply generic help class and specific bar chart help class
931
1022
  .attr('class', 'ax-chart-message-help ax-bar-chart-no-data-help')
932
- .text('Please provide data to display the chart');
1023
+ .text(this.effectiveMessages().noDataHelp);
933
1024
  }
934
1025
  /**
935
1026
  * Shows a message when all bars are hidden
@@ -947,19 +1038,19 @@ class AXBarChartComponent extends NXComponent {
947
1038
  .append('div')
948
1039
  // Apply generic icon class and specific bar chart icon class
949
1040
  .attr('class', 'ax-chart-message-icon ax-bar-chart-no-data-icon')
950
- .html('<i class="fa-light fa-eye-slash fa-2x"></i>');
1041
+ .html(`<i class="${this.effectiveMessages().allHiddenIcon} fa-2x"></i>`);
951
1042
  // Add text message
952
1043
  messageContainer
953
1044
  .append('div')
954
1045
  // Apply generic text class and specific bar chart text class
955
1046
  .attr('class', 'ax-chart-message-text ax-bar-chart-no-data-text')
956
- .text('All bars are hidden');
1047
+ .text(this.effectiveMessages().allHidden);
957
1048
  // Add help text
958
1049
  messageContainer
959
1050
  .append('div')
960
1051
  // Apply generic help class and specific bar chart help class
961
1052
  .attr('class', 'ax-chart-message-help ax-bar-chart-no-data-help')
962
- .text('Click on legend items to show bars');
1053
+ .text(this.effectiveMessages().allHiddenHelp);
963
1054
  }
964
1055
  /**
965
1056
  * Gets the color for a bar based on its index
@@ -1111,7 +1202,10 @@ class AXBarChartComponent extends NXComponent {
1111
1202
  this.hiddenBars.delete(id);
1112
1203
  if (wasAllHidden) {
1113
1204
  if (this.chartContainerEl()?.nativeElement) {
1114
- this.d3?.select(this.chartContainerEl().nativeElement).selectAll('svg, .ax-chart-message-container').remove();
1205
+ this.d3
1206
+ ?.select(this.chartContainerEl().nativeElement)
1207
+ .selectAll('svg, .ax-chart-message-container')
1208
+ .remove();
1115
1209
  setTimeout(() => {
1116
1210
  this.createChart();
1117
1211
  }, 0);
@@ -1153,11 +1247,11 @@ class AXBarChartComponent extends NXComponent {
1153
1247
  return !this.hiddenSeries.has(id);
1154
1248
  }
1155
1249
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXBarChartComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1156
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.8", 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: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1250
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.8", 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 svg g:has(text){font-family:inherit}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: "component", type: AXChartTooltipComponent, selector: "ax-chart-tooltip", inputs: ["data", "position", "visible", "showPercentage", "style"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1157
1251
  }
1158
1252
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.8", ngImport: i0, type: AXBarChartComponent, decorators: [{
1159
1253
  type: Component,
1160
- args: [{ selector: 'ax-bar-chart', encapsulation: ViewEncapsulation.None, imports: [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"] }]
1254
+ args: [{ selector: 'ax-bar-chart', encapsulation: ViewEncapsulation.None, imports: [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 svg g:has(text){font-family:inherit}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"] }]
1161
1255
  }], ctorParameters: () => [] });
1162
1256
 
1163
1257
  /**