ng-prime-tools 1.0.95 → 1.0.96

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.
@@ -7724,46 +7724,109 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImpo
7724
7724
  }]
7725
7725
  }] });
7726
7726
 
7727
+ const PT_CHART_COMPARISON_DEFAULT_WIDTH = '100%';
7728
+ const PT_CHART_COMPARISON_DEFAULT_HEIGHT = '100%';
7729
+ const PT_CHART_COMPARISON_DEFAULT_MEDIAN_TITLE = 'Médiane';
7730
+ const PT_CHART_COMPARISON_DEFAULT_X_AXIS_TITLE = 'Time';
7731
+ const PT_CHART_COMPARISON_DEFAULT_Y_AXIS_TITLE = 'Value';
7732
+ const PT_CHART_COMPARISON_DEFAULT_RESIZE_DELAY = 100;
7733
+ const PT_CHART_COMPARISON_MEDIAN_DATASET = {
7734
+ borderColor: '#0000ff',
7735
+ borderWidth: 3,
7736
+ backgroundColor: 'transparent',
7737
+ pointRadius: 0,
7738
+ pointHoverRadius: 0,
7739
+ fill: false,
7740
+ tension: 0.1,
7741
+ borderDash: [],
7742
+ };
7743
+ const PT_CHART_COMPARISON_DEFAULT_TOOLTIP = {
7744
+ mode: 'index',
7745
+ intersect: false,
7746
+ position: 'nearest',
7747
+ };
7748
+ const PT_CHART_COMPARISON_DEFAULT_X_TICK_FONT_SIZE = 12;
7749
+ const PT_CHART_COMPARISON_DEFAULT_Y_TICK_FONT = {
7750
+ size: 16,
7751
+ weight: 'bold',
7752
+ };
7753
+ const PT_CHART_COMPARISON_DEFAULT_Y_TICK_COLOR = '#333333';
7754
+ const PT_CHART_COMPARISON_DEFAULT_Y_GRID_COLOR = 'rgba(0, 0, 0, 0.10)';
7755
+ const PT_CHART_COMPARISON_DEFAULT_Y_BORDER_COLOR = '#000000';
7756
+ const createComparisonChartBaseOptions = () => ({
7757
+ responsive: true,
7758
+ maintainAspectRatio: false,
7759
+ resizeDelay: PT_CHART_COMPARISON_DEFAULT_RESIZE_DELAY,
7760
+ });
7761
+
7727
7762
  class PTChartComparisonComponent {
7728
7763
  constructor() {
7729
- this.medianTitle = 'Médiane';
7730
- this.xAxisTitle = 'Time';
7731
- this.yAxisTitle = 'Value';
7732
- this.chartHeight = '400px';
7733
- this.chartWidth = '1200px';
7764
+ this.medianTitle = PT_CHART_COMPARISON_DEFAULT_MEDIAN_TITLE;
7765
+ this.xAxisTitle = PT_CHART_COMPARISON_DEFAULT_X_AXIS_TITLE;
7766
+ this.yAxisTitle = PT_CHART_COMPARISON_DEFAULT_Y_AXIS_TITLE;
7767
+ this.viewInitialized = false;
7734
7768
  Chart.register(...registerables, ChartDataLabels);
7735
7769
  }
7736
- ngOnInit() {
7770
+ ngAfterViewInit() {
7771
+ this.viewInitialized = true;
7737
7772
  this.initializeChart();
7773
+ this.observeResize();
7774
+ this.scheduleResize();
7775
+ }
7776
+ ngOnChanges(changes) {
7777
+ if (!this.viewInitialized) {
7778
+ return;
7779
+ }
7780
+ if (changes['chartConfig'] ||
7781
+ changes['chartHeight'] ||
7782
+ changes['chartWidth'] ||
7783
+ changes['medianTitle'] ||
7784
+ changes['xAxisTitle'] ||
7785
+ changes['yAxisTitle'] ||
7786
+ changes['yMin'] ||
7787
+ changes['yMax'] ||
7788
+ changes['yStepSize']) {
7789
+ this.initializeChart();
7790
+ }
7738
7791
  }
7739
7792
  ngOnDestroy() {
7793
+ this.resizeObserver?.disconnect();
7740
7794
  this.destroyChart();
7741
7795
  }
7796
+ get resolvedChartWidth() {
7797
+ return (this.chartConfig?.chartWidth?.trim() ||
7798
+ this.chartWidth?.trim() ||
7799
+ PT_CHART_COMPARISON_DEFAULT_WIDTH);
7800
+ }
7801
+ get resolvedChartHeight() {
7802
+ return (this.chartConfig?.chartHeight?.trim() ||
7803
+ this.chartHeight?.trim() ||
7804
+ PT_CHART_COMPARISON_DEFAULT_HEIGHT);
7805
+ }
7742
7806
  initializeChart() {
7807
+ if (!this.chartConfig || !this.canvasRef) {
7808
+ return;
7809
+ }
7743
7810
  const canvas = this.canvasRef.nativeElement;
7744
7811
  this.destroyChart();
7745
- const config = {
7812
+ const configuration = {
7746
7813
  type: this.chartConfig.type || 'line',
7747
7814
  data: this.getFormattedChartData(),
7748
7815
  options: this.getChartOptions(),
7749
7816
  };
7750
- this.chart = new Chart(canvas, config);
7817
+ this.chart = new Chart(canvas, configuration);
7818
+ this.scheduleResize();
7751
7819
  }
7752
7820
  getFormattedChartData() {
7753
- const medianValues = this.calculateMedian();
7754
7821
  return {
7755
7822
  labels: this.chartConfig.data.labels,
7756
7823
  datasets: [
7757
7824
  {
7758
- label: this.chartConfig.medianTitle || this.medianTitle || 'Médiane',
7759
- data: medianValues,
7760
- borderColor: '#0000FF',
7761
- borderWidth: 3,
7762
- backgroundColor: 'transparent',
7763
- pointRadius: 0,
7764
- fill: false,
7765
- tension: 0.1,
7766
- borderDash: [], // ✅ médiane continue
7825
+ label: this.chartConfig.medianTitle?.trim() ||
7826
+ this.medianTitle ||
7827
+ PT_CHART_COMPARISON_DEFAULT_MEDIAN_TITLE,
7828
+ data: this.calculateMedian(),
7829
+ ...PT_CHART_COMPARISON_MEDIAN_DATASET,
7767
7830
  },
7768
7831
  ...this.chartConfig.data.datasets,
7769
7832
  ],
@@ -7771,75 +7834,134 @@ class PTChartComparisonComponent {
7771
7834
  }
7772
7835
  calculateMedian() {
7773
7836
  const datasets = this.chartConfig.data.datasets;
7774
- return this.chartConfig.data.labels.map((_, index) => {
7837
+ const labels = this.chartConfig.data.labels ?? [];
7838
+ return labels.map((_, index) => {
7775
7839
  const valuesAtTime = datasets
7776
7840
  .map((dataset) => dataset.data[index])
7777
- .filter((val) => typeof val === 'number' && !Number.isNaN(val));
7778
- if (valuesAtTime.length === 0)
7841
+ .filter((value) => typeof value === 'number' && Number.isFinite(value))
7842
+ .sort((left, right) => left - right);
7843
+ if (!valuesAtTime.length) {
7779
7844
  return 0;
7780
- valuesAtTime.sort((a, b) => a - b);
7781
- const middle = Math.floor(valuesAtTime.length / 2);
7782
- return valuesAtTime.length % 2 === 0
7783
- ? (valuesAtTime[middle - 1] + valuesAtTime[middle]) / 2
7784
- : valuesAtTime[middle];
7845
+ }
7846
+ const middleIndex = Math.floor(valuesAtTime.length / 2);
7847
+ if (valuesAtTime.length % 2 !== 0) {
7848
+ return valuesAtTime[middleIndex];
7849
+ }
7850
+ return (valuesAtTime[middleIndex - 1] + valuesAtTime[middleIndex]) / 2;
7785
7851
  });
7786
7852
  }
7787
7853
  getChartOptions() {
7788
7854
  const externalOptions = this.chartConfig.options ?? {};
7855
+ const externalPlugins = externalOptions.plugins ?? {};
7856
+ const externalScales = externalOptions.scales;
7857
+ const configuredYMin = this.chartConfig.scales?.y?.min ?? this.yMin;
7858
+ const configuredYMax = this.chartConfig.scales?.y?.max ?? this.yMax;
7859
+ const configuredYStepSize = this.chartConfig.scales?.y?.ticks?.stepSize ?? this.yStepSize;
7789
7860
  return {
7861
+ ...createComparisonChartBaseOptions(),
7862
+ ...externalOptions,
7790
7863
  responsive: true,
7791
7864
  maintainAspectRatio: false,
7792
7865
  plugins: {
7793
- legend: { display: true, position: 'top' },
7794
- tooltip: { mode: 'index', intersect: false },
7866
+ ...externalPlugins,
7867
+ legend: {
7868
+ display: true,
7869
+ position: 'top',
7870
+ ...(externalPlugins.legend ?? {}),
7871
+ },
7872
+ tooltip: {
7873
+ ...PT_CHART_COMPARISON_DEFAULT_TOOLTIP,
7874
+ ...(externalPlugins.tooltip ?? {}),
7875
+ },
7795
7876
  datalabels: {
7796
- display: false, // ✅ supprime les nombres au-dessus des lignes
7877
+ display: false,
7878
+ ...(externalPlugins.datalabels ?? {}),
7797
7879
  },
7798
- ...(externalOptions.plugins ?? {}),
7799
7880
  },
7800
7881
  scales: {
7801
7882
  x: {
7802
- title: { display: true, text: this.chartConfig.xAxisTitle || 'Time' },
7803
- ticks: { font: { size: 12 } },
7804
- ...externalOptions.scales?.x,
7883
+ title: {
7884
+ display: true,
7885
+ text: this.chartConfig.xAxisTitle?.trim() ||
7886
+ this.xAxisTitle ||
7887
+ PT_CHART_COMPARISON_DEFAULT_X_AXIS_TITLE,
7888
+ },
7889
+ ticks: {
7890
+ font: {
7891
+ size: PT_CHART_COMPARISON_DEFAULT_X_TICK_FONT_SIZE,
7892
+ },
7893
+ },
7894
+ ...(externalScales?.['x'] ?? {}),
7805
7895
  },
7806
7896
  y: {
7807
7897
  title: {
7808
7898
  display: true,
7809
- text: this.chartConfig.yAxisTitle || 'Value',
7899
+ text: this.chartConfig.yAxisTitle?.trim() ||
7900
+ this.yAxisTitle ||
7901
+ PT_CHART_COMPARISON_DEFAULT_Y_AXIS_TITLE,
7810
7902
  },
7811
- min: this.chartConfig.scales?.y?.min,
7812
- max: this.chartConfig.scales?.y?.max,
7903
+ min: configuredYMin,
7904
+ max: configuredYMax,
7813
7905
  ticks: {
7814
- stepSize: this.chartConfig.scales?.y?.ticks?.stepSize,
7815
- font: { size: 16, weight: 'bold' },
7816
- color: '#333',
7906
+ stepSize: configuredYStepSize,
7907
+ font: PT_CHART_COMPARISON_DEFAULT_Y_TICK_FONT,
7908
+ color: PT_CHART_COMPARISON_DEFAULT_Y_TICK_COLOR,
7817
7909
  },
7818
7910
  grid: {
7819
- color: 'rgba(0,0,0,0.1)',
7911
+ color: PT_CHART_COMPARISON_DEFAULT_Y_GRID_COLOR,
7820
7912
  },
7821
7913
  border: {
7822
7914
  display: true,
7823
- color: '#000',
7915
+ color: PT_CHART_COMPARISON_DEFAULT_Y_BORDER_COLOR,
7824
7916
  },
7825
- ...externalOptions.scales?.y,
7917
+ ...(externalScales?.['y'] ?? {}),
7826
7918
  },
7827
7919
  },
7828
- ...externalOptions,
7829
7920
  };
7830
7921
  }
7831
- destroyChart() {
7832
- if (this.chart) {
7833
- this.chart.destroy();
7834
- this.chart = undefined;
7922
+ observeResize() {
7923
+ if (typeof ResizeObserver === 'undefined') {
7924
+ return;
7925
+ }
7926
+ const canvas = this.canvasRef.nativeElement;
7927
+ const chartInner = canvas.parentElement;
7928
+ const chartScrollContainer = chartInner?.parentElement;
7929
+ const hostElement = chartScrollContainer?.parentElement;
7930
+ this.resizeObserver = new ResizeObserver(() => {
7931
+ this.scheduleResize();
7932
+ });
7933
+ if (chartInner) {
7934
+ this.resizeObserver.observe(chartInner);
7935
+ }
7936
+ if (chartScrollContainer) {
7937
+ this.resizeObserver.observe(chartScrollContainer);
7938
+ }
7939
+ if (hostElement) {
7940
+ this.resizeObserver.observe(hostElement);
7835
7941
  }
7836
7942
  }
7943
+ scheduleResize() {
7944
+ if (!this.chart) {
7945
+ return;
7946
+ }
7947
+ requestAnimationFrame(() => {
7948
+ if (!this.chart) {
7949
+ return;
7950
+ }
7951
+ this.chart.resize();
7952
+ this.chart.update('none');
7953
+ });
7954
+ }
7955
+ destroyChart() {
7956
+ this.chart?.destroy();
7957
+ this.chart = undefined;
7958
+ }
7837
7959
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTChartComparisonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
7838
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PTChartComparisonComponent, isStandalone: false, selector: "pt-chart-comparison", inputs: { chartConfig: "chartConfig", medianTitle: "medianTitle", xAxisTitle: "xAxisTitle", yAxisTitle: "yAxisTitle", yMin: "yMin", yMax: "yMax", yStepSize: "yStepSize", chartHeight: "chartHeight", chartWidth: "chartWidth" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["chartCanvas"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"chart-scroll-container\">\n <div\n class=\"chart-inner\"\n [style.width]=\"chartConfig.chartWidth || '1200px'\"\n [style.height]=\"chartConfig.chartHeight || '400px'\"\n >\n <canvas #chartCanvas></canvas>\n </div>\n</div>\n", styles: [".chart-scroll-container{width:100%;overflow-x:auto;white-space:nowrap;padding-bottom:10px}.chart-inner{display:inline-block}\n"] }); }
7960
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.14", type: PTChartComparisonComponent, isStandalone: false, selector: "pt-chart-comparison", inputs: { chartConfig: "chartConfig", medianTitle: "medianTitle", xAxisTitle: "xAxisTitle", yAxisTitle: "yAxisTitle", yMin: "yMin", yMax: "yMax", yStepSize: "yStepSize", chartHeight: "chartHeight", chartWidth: "chartWidth" }, viewQueries: [{ propertyName: "canvasRef", first: true, predicate: ["chartCanvas"], descendants: true, static: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"chart-scroll-container\">\n <div\n class=\"chart-inner\"\n [style.width]=\"resolvedChartWidth\"\n [style.height]=\"resolvedChartHeight\"\n >\n <canvas #chartCanvas></canvas>\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;min-width:0;min-height:0}.chart-scroll-container{width:100%;height:100%;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;box-sizing:border-box;padding-bottom:.625rem}.chart-inner{display:block;min-width:0;min-height:0;box-sizing:border-box}.chart-inner canvas{display:block;width:100%!important;height:100%!important;max-width:none;max-height:none}\n"] }); }
7839
7961
  }
7840
7962
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.14", ngImport: i0, type: PTChartComparisonComponent, decorators: [{
7841
7963
  type: Component,
7842
- args: [{ selector: 'pt-chart-comparison', standalone: false, template: "<div class=\"chart-scroll-container\">\n <div\n class=\"chart-inner\"\n [style.width]=\"chartConfig.chartWidth || '1200px'\"\n [style.height]=\"chartConfig.chartHeight || '400px'\"\n >\n <canvas #chartCanvas></canvas>\n </div>\n</div>\n", styles: [".chart-scroll-container{width:100%;overflow-x:auto;white-space:nowrap;padding-bottom:10px}.chart-inner{display:inline-block}\n"] }]
7964
+ args: [{ selector: 'pt-chart-comparison', standalone: false, template: "<div class=\"chart-scroll-container\">\n <div\n class=\"chart-inner\"\n [style.width]=\"resolvedChartWidth\"\n [style.height]=\"resolvedChartHeight\"\n >\n <canvas #chartCanvas></canvas>\n </div>\n</div>\n", styles: [":host{display:block;width:100%;height:100%;min-width:0;min-height:0}.chart-scroll-container{width:100%;height:100%;min-width:0;min-height:0;overflow-x:auto;overflow-y:hidden;box-sizing:border-box;padding-bottom:.625rem}.chart-inner{display:block;min-width:0;min-height:0;box-sizing:border-box}.chart-inner canvas{display:block;width:100%!important;height:100%!important;max-width:none;max-height:none}\n"] }]
7843
7965
  }], ctorParameters: () => [], propDecorators: { chartConfig: [{
7844
7966
  type: Input
7845
7967
  }], medianTitle: [{