@acorex/charts 20.2.0-next.8 → 20.2.0

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,5 +1,5 @@
1
1
  import { NXComponent } from '@acorex/cdk/common';
2
- import { AX_CHART_COLOR_PALETTE, getChartColor } from '@acorex/charts';
2
+ import { AX_CHART_COLOR_PALETTE, getChartColor, computeTooltipPosition } from '@acorex/charts';
3
3
  import { AXChartTooltipComponent } from '@acorex/charts/chart-tooltip';
4
4
  import { AXPlatform } from '@acorex/core/platform';
5
5
  import * as i0 from '@angular/core';
@@ -30,6 +30,14 @@ const AXLineChartDefaultConfig = {
30
30
  showCrosshair: false,
31
31
  animationDuration: 1000,
32
32
  animationEasing: 'cubic-out',
33
+ messages: {
34
+ noData: 'No data available',
35
+ noDataHelp: 'Please provide data to display the chart',
36
+ allHidden: 'All series are hidden',
37
+ allHiddenHelp: 'Click legend items to show series in the chart',
38
+ noDataIcon: 'fa-light fa-chart-line',
39
+ allHiddenIcon: 'fa-light fa-eye-slash',
40
+ },
33
41
  };
34
42
  const AX_LINE_CHART_CONFIG = new InjectionToken('AX_LINE_CHART_CONFIG', {
35
43
  providedIn: 'root',
@@ -92,6 +100,23 @@ class AXLineChartComponent extends NXComponent {
92
100
  ...this.options(),
93
101
  };
94
102
  }, ...(ngDevMode ? [{ debugName: "effectiveOptions" }] : []));
103
+ // Messages with defaults
104
+ effectiveMessages = computed(() => {
105
+ const defaultMessages = {
106
+ noData: 'No data available',
107
+ noDataHelp: 'Please provide data to display the chart',
108
+ allHidden: 'All series are hidden',
109
+ allHiddenHelp: 'Click legend items to show series in the chart',
110
+ noDataIcon: 'fa-light fa-chart-line',
111
+ allHiddenIcon: 'fa-light fa-eye-slash',
112
+ };
113
+ return {
114
+ ...defaultMessages,
115
+ ...this.effectiveOptions().messages,
116
+ };
117
+ }, ...(ngDevMode ? [{ debugName: "effectiveMessages" }] : []));
118
+ // Tooltip gap in pixels for consistent spacing
119
+ TOOLTIP_GAP = 10;
95
120
  ngOnInit() {
96
121
  this.loadD3();
97
122
  }
@@ -200,7 +225,11 @@ class AXLineChartComponent extends NXComponent {
200
225
  return;
201
226
  const containerElement = this.chartContainerEl().nativeElement;
202
227
  const allSeriesData = this._fullNormalizedData;
203
- this.d3.select(containerElement).select('svg').remove();
228
+ // Clear previous SVG and any empty-state messages (preserve tooltip component)
229
+ this.d3
230
+ .select(containerElement)
231
+ .selectAll('svg, .ax-line-chart-no-data-message, .ax-line-chart-all-hidden-message')
232
+ .remove();
204
233
  if (allSeriesData.length === 0 || allSeriesData.every((series) => !series.data || series.data.length === 0)) {
205
234
  this.showNoDataMessage(containerElement);
206
235
  return;
@@ -262,13 +291,13 @@ class AXLineChartComponent extends NXComponent {
262
291
  const svg = this.d3
263
292
  .select(containerElement)
264
293
  .append('svg')
265
- .attr('width', '100%')
266
- .attr('height', '100%')
294
+ .attr('width', totalWidth)
295
+ .attr('height', totalHeight)
267
296
  .attr('viewBox', `0 0 ${totalWidth} ${totalHeight}`)
268
297
  .attr('preserveAspectRatio', 'xMidYMid meet')
269
298
  .attr('style', `
270
- width: 100%;
271
- height: 100%;
299
+ width: ${totalWidth}px;
300
+ height: ${totalHeight}px;
272
301
  max-width: 100%;
273
302
  max-height: 100%;
274
303
  overflow: visible;
@@ -802,7 +831,6 @@ class AXLineChartComponent extends NXComponent {
802
831
  this._tooltipData.set({
803
832
  title: dataPoint.tooltipLabel || series.tooltipLabel || series.label || `Series ${originalIndex + 1}`,
804
833
  value: dataPoint.y.toString(),
805
- seriesName: `x: ${dataPoint.x}`,
806
834
  color: color,
807
835
  });
808
836
  this._tooltipVisible.set(true);
@@ -853,22 +881,16 @@ class AXLineChartComponent extends NXComponent {
853
881
  .attr('pointer-events', 'none');
854
882
  }
855
883
  updateTooltipPosition(event) {
856
- const container = this.chartContainerEl().nativeElement.getBoundingClientRect();
857
- const tooltipEl = this.chartContainerEl().nativeElement.querySelector('.chart-tooltip');
858
- if (!tooltipEl) {
859
- const x = event.clientX - container.left;
860
- const y = event.clientY - container.top;
861
- this._tooltipPosition.set({ x, y });
884
+ const containerEl = this.chartContainerEl()?.nativeElement;
885
+ if (!containerEl)
862
886
  return;
863
- }
864
- const tooltipRect = tooltipEl.getBoundingClientRect();
865
- let x = event.clientX - container.left;
866
- const y = event.clientY - container.top;
867
- if (x + tooltipRect.width + 20 > container.width) {
868
- x = x - tooltipRect.width - 15;
869
- }
870
- this._tooltipPosition.set({ x, y });
887
+ const rect = containerEl.getBoundingClientRect();
888
+ const tooltipEl = containerEl.querySelector('.chart-tooltip');
889
+ const tooltipRect = tooltipEl ? tooltipEl.getBoundingClientRect() : null;
890
+ const pos = computeTooltipPosition(rect, tooltipRect, event.clientX, event.clientY, this.TOOLTIP_GAP);
891
+ this._tooltipPosition.set(pos);
871
892
  }
893
+ // computeTooltipPosition moved to shared chart utils
872
894
  handlePointClick(event, dataPoint, series) {
873
895
  this.pointClick.emit({
874
896
  series: series, // series still refers to the full series data with originalIndex
@@ -880,7 +902,11 @@ class AXLineChartComponent extends NXComponent {
880
902
  });
881
903
  }
882
904
  showNoDataMessage(containerElement) {
883
- this.d3.select(containerElement).selectAll('*').remove();
905
+ // Remove only chart SVG and previous empty-state messages to avoid removing tooltip
906
+ this.d3
907
+ .select(containerElement)
908
+ .selectAll('svg, .ax-line-chart-no-data-message, .ax-line-chart-all-hidden-message')
909
+ .remove();
884
910
  const messageContainer = this.d3
885
911
  .select(containerElement)
886
912
  .append('div')
@@ -888,36 +914,33 @@ class AXLineChartComponent extends NXComponent {
888
914
  .style('position', 'absolute')
889
915
  .style('left', '50%')
890
916
  .style('top', '50%')
891
- .style('transform', 'translate(-50%, -50%)')
892
- .style('text-align', 'center')
893
- .style('background-color', 'rgb(var(--ax-comp-line-chart-bg-color))')
894
- .style('padding', '1.5rem')
895
- .style('border-radius', '0.5rem')
896
- .style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
897
- .style('width', '80%')
898
- .style('max-width', '300px');
917
+ .style('transform', 'translate(-50%, -50%)');
899
918
  messageContainer
900
919
  .append('div')
901
920
  .attr('class', 'ax-line-chart-no-data-icon')
902
921
  .style('opacity', '0.6')
903
922
  .style('margin-bottom', '0.75rem')
904
- .html('<i class="fa-light fa-chart-line fa-2x"></i>');
923
+ .html(`<i class="${this.effectiveMessages().noDataIcon} fa-2x"></i>`);
905
924
  messageContainer
906
925
  .append('div')
907
926
  .attr('class', 'ax-line-chart-no-data-text')
908
927
  .style('font-size', '1rem')
909
928
  .style('font-weight', '600')
910
929
  .style('margin-bottom', '0.5rem')
911
- .text('No data available');
930
+ .text(this.effectiveMessages().noData);
912
931
  messageContainer
913
932
  .append('div')
914
933
  .attr('class', 'ax-line-chart-no-data-help')
915
934
  .style('font-size', '0.8rem')
916
935
  .style('opacity', '0.6')
917
- .text('Please provide data to display the chart');
936
+ .text(this.effectiveMessages().noDataHelp);
918
937
  }
919
938
  showAllSeriesHiddenMessage(containerElement) {
920
- this.d3.select(containerElement).selectAll('*').remove(); // Clear existing chart elements
939
+ // Remove only chart SVG and previous empty-state messages to avoid removing tooltip
940
+ this.d3
941
+ .select(containerElement)
942
+ .selectAll('svg, .ax-line-chart-no-data-message, .ax-line-chart-all-hidden-message')
943
+ .remove();
921
944
  const messageContainer = this.d3
922
945
  .select(containerElement)
923
946
  .append('div')
@@ -925,50 +948,34 @@ class AXLineChartComponent extends NXComponent {
925
948
  .style('position', 'absolute')
926
949
  .style('left', '50%')
927
950
  .style('top', '50%')
928
- .style('transform', 'translate(-50%, -50%)')
929
- .style('text-align', 'center')
930
- .style('background-color', 'rgb(var(--ax-comp-line-chart-bg-color))')
931
- .style('padding', '1.5rem')
932
- .style('border-radius', '0.5rem')
933
- .style('box-shadow', '0 2px 12px rgba(0, 0, 0, 0.08)')
934
- .style('width', '80%')
935
- .style('max-width', '350px'); // Slightly wider for longer text
951
+ .style('transform', 'translate(-50%, -50%)');
936
952
  messageContainer
937
953
  .append('div')
938
954
  .attr('class', 'ax-line-chart-all-hidden-icon')
939
955
  .style('opacity', '0.6')
940
956
  .style('margin-bottom', '0.75rem')
941
- .html('<i class="fa-light fa-eye-slash fa-2x"></i>'); // Different icon
957
+ .html(`<i class="${this.effectiveMessages().allHiddenIcon} fa-2x"></i>`); // Different icon
942
958
  messageContainer
943
959
  .append('div')
944
960
  .attr('class', 'ax-line-chart-all-hidden-text')
945
961
  .style('font-size', '1rem')
946
962
  .style('font-weight', '600')
947
963
  .style('margin-bottom', '0.5rem')
948
- .text('All series are hidden');
964
+ .text(this.effectiveMessages().allHidden);
949
965
  messageContainer
950
966
  .append('div')
951
967
  .attr('class', 'ax-line-chart-all-hidden-help')
952
968
  .style('font-size', '0.8rem')
953
969
  .style('opacity', '0.6')
954
- .text('Click legend items to show series in the chart.');
970
+ .text(this.effectiveMessages().allHiddenHelp);
955
971
  }
956
972
  handleOverlappingPointsHover(event, overlappingPoints) {
957
973
  if (this.effectiveOptions().showTooltip === false)
958
974
  return;
959
975
  const tooltipData = {
960
- title: 'Multiple Series',
976
+ title: overlappingPoints.map(({ series }) => series.label),
961
977
  value: overlappingPoints[0].point.y.toString(),
962
- seriesName: '',
963
- color: '',
964
- items: overlappingPoints.map(({ point, series, originalIndex }) => {
965
- const color = series.lineColor || getChartColor(originalIndex, this.chartColors);
966
- return {
967
- label: series.label || `Series ${originalIndex + 1}`,
968
- value: point.y.toString(),
969
- color: color,
970
- };
971
- }),
978
+ color: overlappingPoints.map(({ series }) => series.lineColor || getChartColor(series.originalIndex, this.chartColors)),
972
979
  };
973
980
  this._tooltipData.set(tooltipData);
974
981
  this._tooltipVisible.set(true);
@@ -1001,12 +1008,12 @@ class AXLineChartComponent extends NXComponent {
1001
1008
  return this.d3.easeCubicOut;
1002
1009
  }
1003
1010
  }
1004
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXLineChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1005
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.1.3", type: AXLineChartComponent, isStandalone: true, selector: "ax-line-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: { pointClick: "pointClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-line-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"false\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-line-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-line-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-axis-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-bg-color: var(--ax-sys-color-lightest-surface);--ax-comp-line-chart-text-color: var(--ax-sys-color-on-lightest-surface)}ax-line-chart .ax-line-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-comp-line-chart-text-color));background-color:rgb(var(--ax-comp-line-chart-bg-color))}ax-line-chart .ax-line-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-line-chart .ax-line-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);background-color:rgb(var(--ax-comp-line-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-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 });
1011
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXLineChartComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1012
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.2.0", version: "20.3.3", type: AXLineChartComponent, isStandalone: true, selector: "ax-line-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: { pointClick: "pointClick" }, viewQueries: [{ propertyName: "chartContainerEl", first: true, predicate: ["chartContainer"], descendants: true, isSignal: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-line-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"false\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-line-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-line-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-axis-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-bg-color: 0, 0, 0, 0;--ax-comp-line-chart-text-color: var(--ax-sys-color-on-lightest-surface)}ax-line-chart .ax-line-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgba(var(--ax-comp-line-chart-text-color));background-color:rgb(var(--ax-comp-line-chart-bg-color))}ax-line-chart .ax-line-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-line-chart .ax-line-chart svg g:has(text){font-family:inherit}ax-line-chart .ax-line-chart-no-data-message{text-align:center;background-color:rgb(var(--ax-comp-line-chart-bg-color));padding:1.5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-surface));width:80%;max-width:300px}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-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 });
1006
1013
  }
1007
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.1.3", ngImport: i0, type: AXLineChartComponent, decorators: [{
1014
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.3", ngImport: i0, type: AXLineChartComponent, decorators: [{
1008
1015
  type: Component,
1009
- args: [{ selector: 'ax-line-chart', standalone: true, encapsulation: ViewEncapsulation.None, imports: [AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-line-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"false\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-line-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-line-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-axis-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-bg-color: var(--ax-sys-color-lightest-surface);--ax-comp-line-chart-text-color: var(--ax-sys-color-on-lightest-surface)}ax-line-chart .ax-line-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgb(var(--ax-comp-line-chart-text-color));background-color:rgb(var(--ax-comp-line-chart-bg-color))}ax-line-chart .ax-line-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-line-chart .ax-line-chart-no-data-message{position:absolute;text-align:center;transform:translate(-50%,-50%);background-color:rgb(var(--ax-comp-line-chart-bg-color));padding:1.5rem;border-radius:.5rem;box-shadow:0 2px 12px #00000014;width:80%;max-width:300px}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-help{font-size:.8rem;opacity:.6}\n"] }]
1016
+ args: [{ selector: 'ax-line-chart', standalone: true, encapsulation: ViewEncapsulation.None, imports: [AXChartTooltipComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"ax-line-chart\" #chartContainer>\n <!-- Shared tooltip component -->\n <ax-chart-tooltip\n [visible]=\"tooltipVisible()\"\n [position]=\"tooltipPosition()\"\n [data]=\"tooltipData()\"\n [showPercentage]=\"false\"\n ></ax-chart-tooltip>\n</div>\n", styles: ["ax-line-chart{display:block;width:100%;height:100%;min-height:200px;--ax-comp-line-chart-labels-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-axis-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-grid-lines-color: var(--ax-sys-color-on-lightest-surface);--ax-comp-line-chart-bg-color: 0, 0, 0, 0;--ax-comp-line-chart-text-color: var(--ax-sys-color-on-lightest-surface)}ax-line-chart .ax-line-chart{width:100%;height:100%;position:relative;display:flex;align-items:center;justify-content:center;border-radius:.5rem;overflow:hidden;color:rgba(var(--ax-comp-line-chart-text-color));background-color:rgb(var(--ax-comp-line-chart-bg-color))}ax-line-chart .ax-line-chart svg{width:100%;height:100%;max-width:100%;max-height:100%;overflow:visible}ax-line-chart .ax-line-chart svg g:has(text){font-family:inherit}ax-line-chart .ax-line-chart-no-data-message{text-align:center;background-color:rgb(var(--ax-comp-line-chart-bg-color));padding:1.5rem;border-radius:.5rem;border:1px solid rgba(var(--ax-sys-color-surface));width:80%;max-width:300px}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-icon{opacity:.6;margin-bottom:.75rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-text{font-size:1rem;font-weight:600;margin-bottom:.5rem}ax-line-chart .ax-line-chart-no-data-message .ax-line-chart-no-data-help{font-size:.8rem;opacity:.6}\n"] }]
1010
1017
  }] });
1011
1018
 
1012
1019
  /**