apexcharts 6.2.0 → 6.3.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.
Files changed (97) hide show
  1. package/dist/apexcharts.common.js +2 -2
  2. package/dist/apexcharts.esm.js +611 -96
  3. package/dist/apexcharts.js +611 -96
  4. package/dist/apexcharts.min.js +2 -2
  5. package/dist/apexcharts.ssr.common.js +2 -2
  6. package/dist/apexcharts.ssr.esm.js +611 -96
  7. package/dist/area.common.js +2 -2
  8. package/dist/area.esm.js +2 -2
  9. package/dist/bar.common.js +1 -1
  10. package/dist/bar.esm.js +1 -1
  11. package/dist/boxPlot.common.js +1 -1
  12. package/dist/boxPlot.esm.js +1 -1
  13. package/dist/bubble.common.js +2 -2
  14. package/dist/bubble.esm.js +2 -2
  15. package/dist/candlestick.common.js +1 -1
  16. package/dist/candlestick.esm.js +1 -1
  17. package/dist/column.common.js +1 -1
  18. package/dist/column.esm.js +1 -1
  19. package/dist/core.common.js +2 -2
  20. package/dist/core.esm.js +578 -76
  21. package/dist/donut.common.js +1 -1
  22. package/dist/donut.esm.js +1 -1
  23. package/dist/features/all.common.js +2 -2
  24. package/dist/features/all.esm.js +33 -20
  25. package/dist/features/annotations.common.js +1 -1
  26. package/dist/features/annotations.esm.js +1 -1
  27. package/dist/features/context-menu.common.js +1 -1
  28. package/dist/features/context-menu.esm.js +1 -1
  29. package/dist/features/drilldown.common.js +1 -1
  30. package/dist/features/drilldown.esm.js +1 -1
  31. package/dist/features/exports.common.js +1 -1
  32. package/dist/features/exports.esm.js +1 -1
  33. package/dist/features/facet.common.js +1 -1
  34. package/dist/features/facet.esm.js +1 -1
  35. package/dist/features/history.common.js +1 -1
  36. package/dist/features/history.esm.js +1 -1
  37. package/dist/features/ink.common.js +1 -1
  38. package/dist/features/ink.esm.js +1 -1
  39. package/dist/features/keyboard.common.js +1 -1
  40. package/dist/features/keyboard.esm.js +1 -1
  41. package/dist/features/legend.common.js +1 -1
  42. package/dist/features/legend.esm.js +1 -1
  43. package/dist/features/link.common.js +1 -1
  44. package/dist/features/link.esm.js +1 -1
  45. package/dist/features/marks.common.js +1 -1
  46. package/dist/features/marks.esm.js +1 -1
  47. package/dist/features/measure.common.js +1 -1
  48. package/dist/features/measure.esm.js +1 -1
  49. package/dist/features/morph.common.js +1 -1
  50. package/dist/features/morph.esm.js +1 -1
  51. package/dist/features/perspectives.common.js +1 -1
  52. package/dist/features/perspectives.esm.js +1 -1
  53. package/dist/features/renderer-canvas.common.js +2 -2
  54. package/dist/features/renderer-canvas.esm.js +15 -1
  55. package/dist/features/storyboard.common.js +1 -1
  56. package/dist/features/storyboard.esm.js +1 -1
  57. package/dist/features/toolbar.common.js +2 -2
  58. package/dist/features/toolbar.esm.js +19 -20
  59. package/dist/features/weave.common.js +1 -1
  60. package/dist/features/weave.esm.js +1 -1
  61. package/dist/heatmap.common.js +1 -1
  62. package/dist/heatmap.esm.js +1 -1
  63. package/dist/line.common.js +2 -2
  64. package/dist/line.esm.js +2 -2
  65. package/dist/pie.common.js +1 -1
  66. package/dist/pie.esm.js +1 -1
  67. package/dist/polarArea.common.js +1 -1
  68. package/dist/polarArea.esm.js +1 -1
  69. package/dist/radar.common.js +1 -1
  70. package/dist/radar.esm.js +1 -1
  71. package/dist/radialBar.common.js +1 -1
  72. package/dist/radialBar.esm.js +1 -1
  73. package/dist/rangeArea.common.js +2 -2
  74. package/dist/rangeArea.esm.js +2 -2
  75. package/dist/rangeBar.common.js +1 -1
  76. package/dist/rangeBar.esm.js +1 -1
  77. package/dist/scatter.common.js +2 -2
  78. package/dist/scatter.esm.js +2 -2
  79. package/dist/treemap.common.js +1 -1
  80. package/dist/treemap.esm.js +1 -1
  81. package/dist/violin.common.js +1 -1
  82. package/dist/violin.esm.js +1 -1
  83. package/package.json +1 -1
  84. package/src/apexcharts.js +300 -33
  85. package/src/charts/Line.js +7 -5
  86. package/src/modules/Core.js +19 -0
  87. package/src/modules/Crosshairs.js +24 -5
  88. package/src/modules/Data.js +198 -14
  89. package/src/modules/Range.js +160 -32
  90. package/src/modules/Series.js +19 -0
  91. package/src/modules/ZoomPanSelection.js +16 -11
  92. package/src/modules/helpers/UpdateHelpers.js +16 -5
  93. package/src/modules/settings/Globals.js +50 -1
  94. package/src/modules/tooltip/AxesTooltip.js +7 -1
  95. package/src/modules/tooltip/Utils.js +5 -1
  96. package/src/renderers/canvas/CanvasRenderer.js +16 -0
  97. package/src/types/internal.d.ts +23 -0
@@ -51,7 +51,7 @@ var __async = (__this, __arguments, generator) => {
51
51
  });
52
52
  };
53
53
  /*!
54
- * ApexCharts v6.2.0
54
+ * ApexCharts v6.3.0
55
55
  * (c) 2018-2026 ApexCharts
56
56
  */
57
57
  class Environment {
@@ -5761,14 +5761,54 @@ class Globals {
5761
5761
  globals
5762
5762
  );
5763
5763
  }
5764
+ /**
5765
+ * Lazy initial-series snapshot. Capturing `initialSeries` used to deep-clone
5766
+ * the entire series on every parse and every update: the single largest CPU
5767
+ * bucket at 50k+ points (profiled at ~23ms per 50k update). The setter now
5768
+ * stores a cheap per-series shallow copy (series OBJECTS copied, data arrays
5769
+ * shared) and the deep snapshot materializes only when something actually
5770
+ * reads it (resetSeries, toolbar reset-home, tooltip same-length check).
5771
+ *
5772
+ * Why sharing the data arrays is safe: internal "mutations" of a series'
5773
+ * data are property REPLACEMENTS (`series[i].data = []` on legend collapse),
5774
+ * which cannot reach the captured copies because each series object was
5775
+ * copied at capture time. The one in-place mutator (appendData's push loop)
5776
+ * re-captures immediately after mutating, so the pending snapshot never
5777
+ * spans the mutation.
5778
+ *
5779
+ * @param {Record<string, any>} globals
5780
+ */
5781
+ defineLazyInitialSeries(globals) {
5782
+ let src = [];
5783
+ let snap = null;
5784
+ Object.defineProperty(globals, "initialSeries", {
5785
+ configurable: true,
5786
+ enumerable: true,
5787
+ get() {
5788
+ if (snap === null) {
5789
+ snap = Utils$1.clone(src);
5790
+ }
5791
+ return snap;
5792
+ },
5793
+ set(value) {
5794
+ src = Array.isArray(value) ? value.map(
5795
+ (s) => s && typeof s === "object" && !Array.isArray(s) ? __spreadValues({}, s) : s
5796
+ ) : value;
5797
+ snap = null;
5798
+ globals._initialSeriesPeek = src;
5799
+ }
5800
+ });
5801
+ globals._initialSeriesPeek = src;
5802
+ }
5764
5803
  /**
5765
5804
  * @param {Record<string, any>} config
5766
5805
  */
5767
5806
  init(config) {
5768
5807
  const globals = this.globalVars(config);
5769
5808
  this.initGlobalVars(globals);
5809
+ this.defineLazyInitialSeries(globals);
5770
5810
  globals.initialConfig = Utils$1.extend({}, config);
5771
- globals.initialSeries = Utils$1.clone(config.series);
5811
+ globals.initialSeries = config.series;
5772
5812
  globals.lastXAxis = Utils$1.clone(
5773
5813
  /** @type {NonNullable<typeof globals.initialConfig>} */
5774
5814
  globals.initialConfig.xaxis
@@ -12724,7 +12764,7 @@ class Range {
12724
12764
  * @param {number | null} [endingSeriesIndex]
12725
12765
  */
12726
12766
  getMinYMaxY(startingSeriesIndex, lowestY = Number.MAX_VALUE, highestY = -Number.MAX_VALUE, endingSeriesIndex = null) {
12727
- var _a, _b, _c, _d, _e, _f, _g, _h;
12767
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
12728
12768
  const cnf = this.w.config;
12729
12769
  const gl = this.w.globals;
12730
12770
  let maxY = -Number.MAX_VALUE;
@@ -12788,14 +12828,68 @@ class Range {
12788
12828
  }
12789
12829
  }
12790
12830
  }
12831
+ const plainNumeric = seriesMin === series && seriesMax === series && cnf.chart.type !== "boxPlot" && seriesType !== "candlestick" && seriesType !== "boxPlot" && seriesType !== "violin" && seriesType !== "rangeArea" && seriesType !== "rangeBar" && !(this.w.seriesData.seriesGoals[i] && this.w.seriesData.seriesGoals[i].length);
12832
+ if (plainNumeric) {
12833
+ const arr = series[i];
12834
+ const jEnd = Math.min(lastXIndex, arr.length - 1);
12835
+ const pe = (_b = this.w.seriesData._parsedExtrema) == null ? void 0 : _b[i];
12836
+ if (pe && pe.ref === arr && pe.len === arr.length && firstXIndex === 0 && jEnd === arr.length - 1) {
12837
+ if (pe.maxY > maxY) maxY = pe.maxY;
12838
+ if (pe.lowestY < lowestY) lowestY = pe.lowestY;
12839
+ if (pe.negMinY < 0 && pe.negMinY < minY) minY = pe.negMinY;
12840
+ if (pe.yDec > gl.yValueDecimal) gl.yValueDecimal = pe.yDec;
12841
+ if (pe.hasNulls) gl.hasNullValues = true;
12842
+ } else {
12843
+ let yDec = gl.yValueDecimal;
12844
+ let hasNulls = false;
12845
+ for (let j = firstXIndex; j <= jEnd; j++) {
12846
+ const val = arr[j];
12847
+ if (val !== null && typeof val === "number" && val === val && val !== Infinity && val !== -Infinity) {
12848
+ if (val > maxY) maxY = val;
12849
+ if (val < lowestY) lowestY = val;
12850
+ if (minY > val && val < 0) minY = val;
12851
+ if (!Number.isInteger(val)) {
12852
+ const av = val < 0 ? -val : val;
12853
+ if (av >= 1e-6 && av < 1e21) {
12854
+ const str = "" + val;
12855
+ const dot = str.indexOf(".");
12856
+ const dec = dot === -1 ? 0 : str.length - dot - 1;
12857
+ if (dec > yDec) yDec = dec;
12858
+ } else {
12859
+ const nv = Utils$1.noExponents(val);
12860
+ if (Utils$1.isFloat(nv)) {
12861
+ yDec = Math.max(yDec, nv.toString().split(".")[1].length);
12862
+ }
12863
+ }
12864
+ }
12865
+ } else {
12866
+ hasNulls = true;
12867
+ }
12868
+ }
12869
+ gl.yValueDecimal = yDec;
12870
+ if (hasNulls) gl.hasNullValues = true;
12871
+ }
12872
+ highestY = maxY;
12873
+ if (seriesType === "bar" || seriesType === "column") {
12874
+ if (minY < 0 && maxY < 0) {
12875
+ maxY = 0;
12876
+ highestY = Math.max(highestY, 0);
12877
+ }
12878
+ if (minY === Number.MIN_VALUE) {
12879
+ minY = 0;
12880
+ lowestY = Math.min(lowestY, 0);
12881
+ }
12882
+ }
12883
+ continue;
12884
+ }
12791
12885
  for (let j = firstXIndex; j <= lastXIndex && j < this.w.seriesData.series[i].length; j++) {
12792
12886
  let val = series[i][j];
12793
12887
  if (val !== null && Utils$1.isNumber(val)) {
12794
- if (typeof ((_b = seriesMax[i]) == null ? void 0 : _b[j]) !== "undefined") {
12888
+ if (typeof ((_c = seriesMax[i]) == null ? void 0 : _c[j]) !== "undefined") {
12795
12889
  maxY = Math.max(maxY, seriesMax[i][j]);
12796
12890
  lowestY = Math.min(lowestY, seriesMax[i][j]);
12797
12891
  }
12798
- if (typeof ((_c = seriesMin[i]) == null ? void 0 : _c[j]) !== "undefined") {
12892
+ if (typeof ((_d = seriesMin[i]) == null ? void 0 : _d[j]) !== "undefined") {
12799
12893
  lowestY = Math.min(lowestY, seriesMin[i][j]);
12800
12894
  highestY = Math.max(highestY, seriesMin[i][j]);
12801
12895
  }
@@ -12824,7 +12918,7 @@ class Range {
12824
12918
  break;
12825
12919
  case "violin":
12826
12920
  {
12827
- if (typeof ((_d = this.w.violinData.seriesViolinMax[i]) == null ? void 0 : _d[j]) !== "undefined") {
12921
+ if (typeof ((_e = this.w.violinData.seriesViolinMax[i]) == null ? void 0 : _e[j]) !== "undefined") {
12828
12922
  maxY = Math.max(maxY, this.w.violinData.seriesViolinMax[i][j]);
12829
12923
  lowestY = Math.min(
12830
12924
  lowestY,
@@ -12847,7 +12941,7 @@ class Range {
12847
12941
  );
12848
12942
  }
12849
12943
  if (this.w.config.chart.type === "boxPlot" || seriesType === "boxPlot") {
12850
- const boxPts = (_f = (_e = this.w.candleData.seriesBoxPoints) == null ? void 0 : _e[i]) == null ? void 0 : _f[j];
12944
+ const boxPts = (_g = (_f = this.w.candleData.seriesBoxPoints) == null ? void 0 : _f[i]) == null ? void 0 : _g[j];
12851
12945
  if (boxPts) {
12852
12946
  for (let p = 0; p < boxPts.length; p++) {
12853
12947
  const pv = boxPts[p];
@@ -12866,7 +12960,7 @@ class Range {
12866
12960
  val.toString().split(".")[1].length
12867
12961
  );
12868
12962
  }
12869
- if (minY > ((_g = seriesMin[i]) == null ? void 0 : _g[j]) && ((_h = seriesMin[i]) == null ? void 0 : _h[j]) < 0) {
12963
+ if (minY > ((_h = seriesMin[i]) == null ? void 0 : _h[j]) && ((_i = seriesMin[i]) == null ? void 0 : _i[j]) < 0) {
12870
12964
  minY = seriesMin[i][j];
12871
12965
  }
12872
12966
  } else {
@@ -13020,38 +13114,33 @@ class Range {
13020
13114
  const cnf = this.w.config;
13021
13115
  const isXNumeric = cnf.xaxis.type === "numeric" || cnf.xaxis.type === "datetime" || cnf.xaxis.type === "category" && !this.w.axisFlags.noLabelsProvided || this.w.axisFlags.noLabelsProvided || this.w.axisFlags.isXNumeric;
13022
13116
  const getInitialMinXMaxX = () => {
13117
+ var _a;
13118
+ let minX = gl.minX;
13119
+ let maxX = gl.maxX;
13023
13120
  for (let i = 0; i < this.w.seriesData.series.length; i++) {
13024
- if (this.w.labelData.labels[i]) {
13025
- for (let j = 0; j < this.w.labelData.labels[i].length; j++) {
13026
- if (this.w.labelData.labels[i][j] !== null && Utils$1.isNumber(this.w.labelData.labels[i][j])) {
13027
- gl.maxX = Math.max(
13028
- gl.maxX,
13029
- /** @type {number} */
13030
- /** @type {any} */
13031
- this.w.labelData.labels[i][j]
13032
- );
13033
- gl.initialMaxX = Math.max(
13034
- gl.maxX,
13035
- /** @type {number} */
13036
- /** @type {any} */
13037
- this.w.labelData.labels[i][j]
13038
- );
13039
- gl.minX = Math.min(
13040
- gl.minX,
13041
- /** @type {number} */
13042
- /** @type {any} */
13043
- this.w.labelData.labels[i][j]
13044
- );
13045
- gl.initialMinX = Math.min(
13046
- gl.minX,
13047
- /** @type {number} */
13048
- /** @type {any} */
13049
- this.w.labelData.labels[i][j]
13050
- );
13051
- }
13121
+ const lbls = (
13122
+ /** @type {any} */
13123
+ this.w.labelData.labels[i]
13124
+ );
13125
+ if (!lbls) continue;
13126
+ const pe = (_a = this.w.seriesData._parsedExtrema) == null ? void 0 : _a[i];
13127
+ if (pe && pe.xNumeric && pe.xref === lbls && pe.len === lbls.length) {
13128
+ if (pe.maxX > maxX) maxX = pe.maxX;
13129
+ if (pe.minX < minX) minX = pe.minX;
13130
+ continue;
13131
+ }
13132
+ for (let j = 0; j < lbls.length; j++) {
13133
+ const v = lbls[j];
13134
+ if (v !== null && typeof v === "number" && v === v) {
13135
+ if (v > maxX) maxX = v;
13136
+ if (v < minX) minX = v;
13052
13137
  }
13053
13138
  }
13054
13139
  }
13140
+ gl.maxX = maxX;
13141
+ gl.initialMaxX = maxX;
13142
+ gl.minX = minX;
13143
+ gl.initialMinX = minX;
13055
13144
  };
13056
13145
  if (this.w.axisFlags.isXNumeric) {
13057
13146
  getInitialMinXMaxX();
@@ -13193,13 +13282,40 @@ class Range {
13193
13282
  _getMinXDiff() {
13194
13283
  const gl = this.w.globals;
13195
13284
  if (this.w.axisFlags.isXNumeric) {
13196
- this.w.seriesData.seriesX.forEach((sX) => {
13285
+ this.w.seriesData.seriesX.forEach((sX, si) => {
13286
+ var _a;
13197
13287
  if (sX.length) {
13198
13288
  if (sX.length === 1) {
13199
13289
  sX.push(
13200
13290
  this.w.seriesData.seriesX[gl.maxValsInArrayIndex][this.w.seriesData.seriesX[gl.maxValsInArrayIndex].length - 1]
13201
13291
  );
13202
13292
  }
13293
+ const pe = (_a = this.w.seriesData._parsedExtrema) == null ? void 0 : _a[si];
13294
+ if (pe && pe.xNumeric && pe.xSorted && pe.xref === sX && pe.len === sX.length) {
13295
+ if (pe.minXDiff < gl.minXDiff) gl.minXDiff = pe.minXDiff;
13296
+ if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
13297
+ gl.minXDiff = 0.5;
13298
+ }
13299
+ return;
13300
+ }
13301
+ let presorted = true;
13302
+ let minDiff = gl.minXDiff;
13303
+ for (let j = 1; j < sX.length; j++) {
13304
+ const d = sX[j] - sX[j - 1];
13305
+ if (d > 0) {
13306
+ if (d < minDiff) minDiff = d;
13307
+ } else if (d < 0) {
13308
+ presorted = false;
13309
+ break;
13310
+ }
13311
+ }
13312
+ if (presorted) {
13313
+ gl.minXDiff = minDiff;
13314
+ if (gl.dataPoints === 1 || gl.minXDiff === Number.MAX_VALUE) {
13315
+ gl.minXDiff = 0.5;
13316
+ }
13317
+ return;
13318
+ }
13203
13319
  const seriesX = sX.slice();
13204
13320
  seriesX.sort((a, b) => a - b);
13205
13321
  seriesX.forEach((s, j) => {
@@ -13976,6 +14092,7 @@ class Crosshairs {
13976
14092
  }
13977
14093
  drawXCrosshairs() {
13978
14094
  const w = this.w;
14095
+ w.dom.elGraphical.node.querySelectorAll(":scope > .apexcharts-xcrosshairs").forEach((el) => el.remove());
13979
14096
  const graphics = new Graphics(this.w);
13980
14097
  const filters = new Filters(this.w);
13981
14098
  const crosshairGradient = w.config.xaxis.crosshairs.fill.gradient;
@@ -14007,10 +14124,7 @@ class Crosshairs {
14007
14124
  []
14008
14125
  );
14009
14126
  }
14010
- let xcrosshairs = graphics.drawRect();
14011
- if (w.config.xaxis.crosshairs.width === 1) {
14012
- xcrosshairs = graphics.drawLine(0, 0, 0, 0);
14013
- }
14127
+ let xcrosshairs = w.config.xaxis.crosshairs.width === 1 ? graphics.drawLine(0, 0, 0, 0) : graphics.drawRect();
14014
14128
  let gridHeight = w.layout.gridHeight;
14015
14129
  if (!Utils$1.isNumber(gridHeight) || gridHeight < 0) {
14016
14130
  gridHeight = 0;
@@ -14047,6 +14161,9 @@ class Crosshairs {
14047
14161
  }
14048
14162
  drawYCrosshairs() {
14049
14163
  const w = this.w;
14164
+ w.dom.elGraphical.node.querySelectorAll(
14165
+ ":scope > .apexcharts-ycrosshairs, :scope > .apexcharts-ycrosshairs-hidden"
14166
+ ).forEach((el) => el.remove());
14050
14167
  const graphics = new Graphics(this.w);
14051
14168
  const crosshair = (
14052
14169
  /** @type {any[]} */
@@ -15237,6 +15354,24 @@ class Series {
15237
15354
  (_a = this._toggleDataSeries) == null ? void 0 : _a.call(this, isSeriesHidden.realIndex, false);
15238
15355
  }
15239
15356
  }
15357
+ /**
15358
+ * Cheap pre-update reset for the data-replacement paths (updateSeries /
15359
+ * appendSeries). Clears the same bookkeeping resetSeries() clears (series
15360
+ * cache, previous paths, collapsed-series state) WITHOUT restoring
15361
+ * config.series from the initialSeries snapshot: the caller is about to
15362
+ * replace the series anyway (parseData assigns config.series = newSeries),
15363
+ * so materializing and cloning the snapshot per update is pure waste (two
15364
+ * O(n) deep clones per streaming tick at 50k points).
15365
+ */
15366
+ prepareDataUpdate() {
15367
+ const w = this.w;
15368
+ this.clearSeriesCache();
15369
+ w.globals.previousPaths = [];
15370
+ w.globals.collapsedSeries = [];
15371
+ w.globals.ancillaryCollapsedSeries = [];
15372
+ w.globals.collapsedSeriesIndices = [];
15373
+ w.globals.ancillaryCollapsedSeriesIndices = [];
15374
+ }
15240
15375
  resetSeries(shouldUpdateChart = true, shouldResetZoom = true, shouldResetCollapsed = true) {
15241
15376
  var _a, _b;
15242
15377
  const w = this.w;
@@ -17738,6 +17873,24 @@ class Core {
17738
17873
  }
17739
17874
  }
17740
17875
  if (canvasMode) {
17876
+ const rr = (
17877
+ /** @type {any} */
17878
+ ctx.renderer
17879
+ );
17880
+ if (rr && rr._repaintHostInPlace) {
17881
+ rr._repaintHostInPlace = false;
17882
+ const wrapNode = this.w.dom.elGraphical.node.querySelector(
17883
+ ".apexcharts-canvas-series-wrap"
17884
+ );
17885
+ if (wrapNode && rr.canRepaintInPlace && rr.canRepaintInPlace()) {
17886
+ rr.repaintInPlace();
17887
+ const groups = Array.isArray(elGraph) ? elGraph : [elGraph];
17888
+ groups.forEach((g) => {
17889
+ if (g && g.node) wrapNode.appendChild(g.node);
17890
+ });
17891
+ return [];
17892
+ }
17893
+ }
17741
17894
  const host = ctx.renderer.present();
17742
17895
  if (host) {
17743
17896
  const wrap = new Graphics(w).group({
@@ -18135,6 +18288,108 @@ class Data {
18135
18288
  const firstDataPoint = this.getFirstDataPoint();
18136
18289
  return firstDataPoint && Array.isArray(firstDataPoint);
18137
18290
  }
18291
+ /**
18292
+ * Typed single pass for the dominant [[x, y], ...] shape: scalar numeric or
18293
+ * null y, no z, no OHLC tuples. One monomorphic loop fills preallocated
18294
+ * x/y arrays and fuses the y-extrema scan that Range.getMinYMaxY would
18295
+ * otherwise repeat over every value (the extrema entry is ref+length
18296
+ * guarded, so any later reshaping of the series array simply falls back to
18297
+ * the scan). Returns false untouched on any non-conforming point so the
18298
+ * general loop below handles mixed/exotic data with unchanged output.
18299
+ * @param {any[]} data
18300
+ * @param {number} i
18301
+ * @returns {boolean}
18302
+ */
18303
+ _fast2DArrayParse(data, i) {
18304
+ var _a, _b;
18305
+ const n = data.length;
18306
+ if (n === 0) return false;
18307
+ const ys = new Array(n);
18308
+ const xs = new Array(n);
18309
+ let maxY = -Number.MAX_VALUE;
18310
+ let lowestY = Number.MAX_VALUE;
18311
+ let negMinY = Infinity;
18312
+ let hasNulls = false;
18313
+ let yDec = 0;
18314
+ let xNumeric = true;
18315
+ let minX = Infinity;
18316
+ let maxX = -Infinity;
18317
+ let xSorted = true;
18318
+ let minXDiff = Infinity;
18319
+ let prevX = NaN;
18320
+ for (let j = 0; j < n; j++) {
18321
+ const point = data[j];
18322
+ if (!Array.isArray(point) || point.length > 2) return false;
18323
+ const x = point[0];
18324
+ const y = point[1];
18325
+ if (xNumeric) {
18326
+ if (typeof x === "number") {
18327
+ if (x === x) {
18328
+ if (x < minX) minX = x;
18329
+ if (x > maxX) maxX = x;
18330
+ }
18331
+ const d = x - prevX;
18332
+ if (d > 0) {
18333
+ if (d < minXDiff) minXDiff = d;
18334
+ } else if (d < 0) {
18335
+ xSorted = false;
18336
+ }
18337
+ prevX = x;
18338
+ } else {
18339
+ xNumeric = false;
18340
+ }
18341
+ }
18342
+ if (typeof y === "number") {
18343
+ if (y === y && y !== Infinity && y !== -Infinity) {
18344
+ if (y > maxY) maxY = y;
18345
+ if (y < lowestY) lowestY = y;
18346
+ if (y < 0 && y < negMinY) negMinY = y;
18347
+ if (!Number.isInteger(y)) {
18348
+ const av = y < 0 ? -y : y;
18349
+ if (av >= 1e-6 && av < 1e21) {
18350
+ const str = "" + y;
18351
+ const dot = str.indexOf(".");
18352
+ const dec = dot === -1 ? 0 : str.length - dot - 1;
18353
+ if (dec > yDec) yDec = dec;
18354
+ } else {
18355
+ const nv = Utils$1.noExponents(y);
18356
+ if (Utils$1.isFloat(nv)) {
18357
+ yDec = Math.max(yDec, nv.toString().split(".")[1].length);
18358
+ }
18359
+ }
18360
+ }
18361
+ } else {
18362
+ hasNulls = true;
18363
+ }
18364
+ } else if (y === null) {
18365
+ hasNulls = true;
18366
+ } else {
18367
+ return false;
18368
+ }
18369
+ ys[j] = y;
18370
+ xs[j] = x;
18371
+ }
18372
+ this.twoDSeries = ys;
18373
+ this.twoDSeriesX = xs;
18374
+ this.w.axisFlags.dataFormatXNumeric = true;
18375
+ const extrema = (_b = (_a = this.w.seriesData)._parsedExtrema) != null ? _b : _a._parsedExtrema = [];
18376
+ extrema[i] = {
18377
+ ref: ys,
18378
+ len: n,
18379
+ maxY,
18380
+ lowestY,
18381
+ negMinY,
18382
+ hasNulls,
18383
+ yDec,
18384
+ xref: xs,
18385
+ xNumeric,
18386
+ minX,
18387
+ maxX,
18388
+ xSorted,
18389
+ minXDiff
18390
+ };
18391
+ return true;
18392
+ }
18138
18393
  /**
18139
18394
  * @param {any[]} ser
18140
18395
  * @param {number} i
@@ -18144,6 +18399,9 @@ class Data {
18144
18399
  const data = ser[i].data;
18145
18400
  const isBoxPlot = cnf.chart.type === "boxPlot" || /** @type {any} */
18146
18401
  cnf.series[i].type === "boxPlot";
18402
+ if (!isBoxPlot && cnf.xaxis.type !== "datetime" && this._fast2DArrayParse(data, i)) {
18403
+ return;
18404
+ }
18147
18405
  for (let j = 0; j < data.length; j++) {
18148
18406
  const point = data[j];
18149
18407
  const x = point[0];
@@ -18540,6 +18798,7 @@ class Data {
18540
18798
  const cnf = this.w.config;
18541
18799
  const gl = this.w.globals;
18542
18800
  const dt = new DateTime(this.w);
18801
+ this.w.seriesData._parsedExtrema = [];
18543
18802
  const xlabels = cnf.labels.length > 0 ? cnf.labels.slice() : cnf.xaxis.categories.slice();
18544
18803
  this.w.axisFlags.isRangeBar = cnf.chart.type === "rangeBar" && gl.isBarHorizontal;
18545
18804
  this.w.labelData.hasXaxisGroups = cnf.xaxis.type === "category" && cnf.xaxis.group.groups.length > 0;
@@ -18929,7 +19188,11 @@ class Data {
18929
19188
  if (this.w.axisFlags.dataWasParsed) {
18930
19189
  return series;
18931
19190
  }
18932
- if (!globalParsing && !series.some((s) => s.parsing)) {
19191
+ const hasGlobalParsing = !!(globalParsing && (globalParsing.x || globalParsing.y || globalParsing.z));
19192
+ const hasSeriesParsing = series.some(
19193
+ (s) => s.parsing && (s.parsing.x || s.parsing.y || s.parsing.z)
19194
+ );
19195
+ if (!hasGlobalParsing && !hasSeriesParsing) {
18933
19196
  return series;
18934
19197
  }
18935
19198
  const processedSeries = series.map((serie, index) => {
@@ -19232,7 +19495,7 @@ class Data {
19232
19495
  });
19233
19496
  });
19234
19497
  } else {
19235
- gl.initialSeries = Utils$1.clone(ser);
19498
+ gl.initialSeries = ser;
19236
19499
  }
19237
19500
  this.excludeCollapsedSeriesInYAxis();
19238
19501
  this.fallbackToCategory = false;
@@ -19252,10 +19515,23 @@ class Data {
19252
19515
  }
19253
19516
  this.coreUtils.getSeriesTotals();
19254
19517
  if (gl.axisCharts) {
19255
- this.w.seriesData.stackedSeriesTotals = this.coreUtils.getStackedSeriesTotals();
19256
- this.w.seriesData.stackedSeriesTotalsByGroups = this.coreUtils.getStackedSeriesTotalsByGroups();
19518
+ Data._defineLazyResult(
19519
+ this.w.seriesData,
19520
+ "stackedSeriesTotals",
19521
+ () => this.coreUtils.getStackedSeriesTotals()
19522
+ );
19523
+ Data._defineLazyResult(
19524
+ this.w.seriesData,
19525
+ "stackedSeriesTotalsByGroups",
19526
+ () => this.coreUtils.getStackedSeriesTotalsByGroups()
19527
+ );
19528
+ Data._defineLazyResult(gl, "seriesPercent", () => {
19529
+ this.coreUtils.getPercentSeries();
19530
+ return gl.seriesPercent;
19531
+ });
19532
+ } else {
19533
+ this.coreUtils.getPercentSeries();
19257
19534
  }
19258
- this.coreUtils.getPercentSeries();
19259
19535
  if (!this.w.axisFlags.dataFormatXNumeric && (!this.w.axisFlags.isXNumeric || cnf.xaxis.type === "numeric" && cnf.labels.length === 0 && cnf.xaxis.categories.length === 0)) {
19260
19536
  this.handleExternalLabelsData(ser);
19261
19537
  }
@@ -19268,6 +19544,12 @@ class Data {
19268
19544
  }
19269
19545
  return {
19270
19546
  // w.seriesData (future slice)
19547
+ // initialSeries/originalSeries and the stacked totals are deliberately
19548
+ // ABSENT: they already live as lazy accessors on gl / w.seriesData, so
19549
+ // a snapshot field would either force their materialization (a deep
19550
+ // clone plus three O(n) passes per parse that most charts never need)
19551
+ // or, as a delegating getter, recurse into itself when a writer copies
19552
+ // it back onto the object it delegates to.
19271
19553
  seriesData: {
19272
19554
  series: this.w.seriesData.series,
19273
19555
  seriesNames: this.w.seriesData.seriesNames,
@@ -19275,10 +19557,6 @@ class Data {
19275
19557
  seriesZ: this.w.seriesData.seriesZ,
19276
19558
  seriesColors: this.w.seriesData.seriesColors,
19277
19559
  seriesGoals: this.w.seriesData.seriesGoals,
19278
- initialSeries: gl.initialSeries,
19279
- originalSeries: gl.originalSeries,
19280
- stackedSeriesTotals: this.w.seriesData.stackedSeriesTotals,
19281
- stackedSeriesTotalsByGroups: this.w.seriesData.stackedSeriesTotalsByGroups,
19282
19560
  noLabelsProvided: this.w.axisFlags.noLabelsProvided
19283
19561
  },
19284
19562
  // w.rangeData (future slice)
@@ -19327,6 +19605,40 @@ class Data {
19327
19605
  * @param {number|null|undefined} xmax
19328
19606
  * @returns {any[]} Sliced array (new array, never the input reference).
19329
19607
  */
19608
+ /**
19609
+ * Define `key` on `obj` as a lazily computed property: `compute` runs on
19610
+ * first read after this call and its result is cached; assigning to the
19611
+ * property stores the assigned value directly (so code that writes the
19612
+ * field, like getPercentSeries, keeps working). Re-calling resets the cache
19613
+ * (used once per parse).
19614
+ * @param {any} obj
19615
+ * @param {string} key
19616
+ * @param {() => any} compute
19617
+ */
19618
+ static _defineLazyResult(obj, key, compute) {
19619
+ let has = false;
19620
+ let value;
19621
+ Object.defineProperty(obj, key, {
19622
+ configurable: true,
19623
+ enumerable: true,
19624
+ get() {
19625
+ if (!has) {
19626
+ has = true;
19627
+ value = compute();
19628
+ }
19629
+ return value;
19630
+ },
19631
+ set(v) {
19632
+ has = true;
19633
+ value = v;
19634
+ }
19635
+ });
19636
+ }
19637
+ /**
19638
+ * @param {any[]} data
19639
+ * @param {any} xmin
19640
+ * @param {any} xmax
19641
+ */
19330
19642
  static sliceByXRange(data, xmin, xmax) {
19331
19643
  const len = data.length;
19332
19644
  if (len === 0) return data;
@@ -19550,7 +19862,7 @@ class UpdateHelpers {
19550
19862
  if (!redraw) {
19551
19863
  w.globals.resized = true;
19552
19864
  w.globals.dataChanged = true;
19553
- if (animate) {
19865
+ if (animate && w.config.chart.animations.enabled) {
19554
19866
  ch.series.getPreviousPaths();
19555
19867
  }
19556
19868
  }
@@ -19596,7 +19908,7 @@ class UpdateHelpers {
19596
19908
  w.globals.lastXAxis = options2.xaxis ? Utils$1.clone(options2.xaxis) : [];
19597
19909
  w.globals.lastYAxis = options2.yaxis ? Utils$1.clone(options2.yaxis) : [];
19598
19910
  w.globals.initialConfig = Utils$1.extend({}, w.config);
19599
- w.globals.initialSeries = Utils$1.clone(w.config.series);
19911
+ w.globals.initialSeries = w.config.series;
19600
19912
  if (options2.series) {
19601
19913
  for (let i = 0; i < w.globals.collapsedSeriesIndices.length; i++) {
19602
19914
  const series = w.config.series[w.globals.collapsedSeriesIndices[i]];
@@ -19641,7 +19953,7 @@ class UpdateHelpers {
19641
19953
  xMax: w.globals.maxX
19642
19954
  });
19643
19955
  PerformanceCache.invalidateSelectors(w);
19644
- if (animate) {
19956
+ if (animate && w.config.chart.animations.enabled) {
19645
19957
  this.ctx.series.getPreviousPaths();
19646
19958
  }
19647
19959
  const prevSeriesCount = w.config.series.length;
@@ -19661,15 +19973,16 @@ class UpdateHelpers {
19661
19973
  this.ctx._writeParsedAxisFlags(parsedState.axisFlags);
19662
19974
  if (overwriteInitialSeries) {
19663
19975
  if (w.globals.initialConfig) {
19664
- w.globals.initialConfig.series = Utils$1.clone(w.config.series);
19976
+ w.globals.initialConfig.series = w.config.series;
19665
19977
  }
19666
- w.globals.initialSeries = Utils$1.clone(w.config.series);
19978
+ w.globals.initialSeries = w.config.series;
19667
19979
  }
19668
19980
  if (this._canUseFastPath(newSeries, prevSeriesCount, prevDataLengths, w)) {
19669
19981
  return this.ctx.fastUpdate(animate, prevAxisScaleSig).then(() => {
19670
19982
  resolve(this.ctx);
19671
19983
  });
19672
19984
  }
19985
+ if (this.ctx._updateStats) this.ctx._updateStats.full++;
19673
19986
  return this.ctx.update().then(() => {
19674
19987
  resolve(this.ctx);
19675
19988
  });
@@ -20192,11 +20505,11 @@ class Utils2 {
20192
20505
  return false;
20193
20506
  }
20194
20507
  isInitialSeriesSameLen() {
20195
- var _a, _b, _c;
20508
+ var _a, _b, _c, _d;
20196
20509
  let sameLen = true;
20197
20510
  const initialSeries = (
20198
20511
  /** @type {any[]} */
20199
- ((_a = this.w.globals.initialSeries) == null ? void 0 : _a.filter(
20512
+ ((_b = (_a = this.w.globals._initialSeriesPeek) != null ? _a : this.w.globals.initialSeries) == null ? void 0 : _b.filter(
20200
20513
  /**
20201
20514
  * @param {Record<string, any>} s
20202
20515
  * @param {number} i
@@ -20208,7 +20521,7 @@ class Utils2 {
20208
20521
  )) || []
20209
20522
  );
20210
20523
  for (let i = 0; i < initialSeries.length - 1; i++) {
20211
- if (!((_b = initialSeries[i]) == null ? void 0 : _b.data) || !((_c = initialSeries[i + 1]) == null ? void 0 : _c.data)) return true;
20524
+ if (!((_c = initialSeries[i]) == null ? void 0 : _c.data) || !((_d = initialSeries[i + 1]) == null ? void 0 : _d.data)) return true;
20212
20525
  if (initialSeries[i].data.length !== initialSeries[i + 1].data.length) {
20213
20526
  sameLen = false;
20214
20527
  break;
@@ -22072,7 +22385,7 @@ class AxesTooltip {
22072
22385
  const tooltipCssClass = isRight ? `apexcharts-yaxistooltip apexcharts-yaxistooltip-${i} apexcharts-yaxistooltip-right` : `apexcharts-yaxistooltip apexcharts-yaxistooltip-${i} apexcharts-yaxistooltip-left`;
22073
22386
  const renderTo = w.dom.elWrap;
22074
22387
  const yaxisTooltip = w.dom.baseEl.querySelector(
22075
- `.apexcharts-yaxistooltip apexcharts-yaxistooltip-${i}`
22388
+ `.apexcharts-yaxistooltip.apexcharts-yaxistooltip-${i}`
22076
22389
  );
22077
22390
  if (yaxisTooltip === null) {
22078
22391
  ttCtx.yaxisTooltip = BrowserAPIs.createElementNS(
@@ -24782,6 +25095,8 @@ const _ApexCharts = class _ApexCharts {
24782
25095
  /** @type {any} */
24783
25096
  __publicField(this, "_keyboardNavigation");
24784
25097
  /** @type {any} */
25098
+ __publicField(this, "_zoomPanSelection");
25099
+ /** @type {any} */
24785
25100
  __publicField(this, "windowResizeHandler");
24786
25101
  /** @type {any} */
24787
25102
  __publicField(this, "parentResizeHandler");
@@ -24823,6 +25138,7 @@ const _ApexCharts = class _ApexCharts {
24823
25138
  const initCtx = new InitCtxVariables(this);
24824
25139
  initCtx.initModules();
24825
25140
  this.lastUpdateOptions = null;
25141
+ this._updateStats = { fast: 0, fastWithAxes: 0, full: 0 };
24826
25142
  this.create = this.create.bind(this);
24827
25143
  if (Environment.isBrowser()) {
24828
25144
  this.windowResizeHandler = this._windowResizeHandler.bind(this);
@@ -25203,7 +25519,7 @@ const _ApexCharts = class _ApexCharts {
25203
25519
  if (Utils$1.shallowEqual(this.lastUpdateOptions, options2)) {
25204
25520
  return Promise.resolve(this);
25205
25521
  }
25206
- if (options2.series && this.lastUpdateOptions.series) {
25522
+ if (options2.series && this.lastUpdateOptions.series && !_ApexCharts._optionsTooBigToCompare(options2)) {
25207
25523
  if (JSON.stringify(this.lastUpdateOptions.series) === JSON.stringify(options2.series)) {
25208
25524
  const optionsWithoutSeries = __spreadValues({}, options2);
25209
25525
  const lastWithoutSeries = __spreadValues({}, this.lastUpdateOptions);
@@ -25257,7 +25573,7 @@ const _ApexCharts = class _ApexCharts {
25257
25573
  */
25258
25574
  updateSeries(newSeries = [], animate = true, overwriteInitialSeries = true) {
25259
25575
  this.data.resetParsingFlags();
25260
- this.series.resetSeries(false);
25576
+ this.series.prepareDataUpdate();
25261
25577
  this.updateHelpers.revertDefaultAxisMinMax();
25262
25578
  return this.updateHelpers._updateSeries(
25263
25579
  newSeries,
@@ -25280,7 +25596,7 @@ const _ApexCharts = class _ApexCharts {
25280
25596
  /** @type {any} */
25281
25597
  newSerie
25282
25598
  );
25283
- this.series.resetSeries(false);
25599
+ this.series.prepareDataUpdate();
25284
25600
  this.updateHelpers.revertDefaultAxisMinMax();
25285
25601
  return this.updateHelpers._updateSeries(
25286
25602
  newSeries,
@@ -25300,7 +25616,9 @@ const _ApexCharts = class _ApexCharts {
25300
25616
  const me = this;
25301
25617
  me.data.resetParsingFlags();
25302
25618
  me.w.globals.dataChanged = true;
25303
- me.series.getPreviousPaths();
25619
+ if (me.w.config.chart.animations.enabled) {
25620
+ me.series.getPreviousPaths();
25621
+ }
25304
25622
  const newSeries = me.w.config.series.slice();
25305
25623
  for (let i = 0; i < newSeries.length; i++) {
25306
25624
  if (newData[i] !== null && typeof newData[i] !== "undefined") {
@@ -25320,19 +25638,37 @@ const _ApexCharts = class _ApexCharts {
25320
25638
  trimStreamingSeries(newSeries, me.w);
25321
25639
  me.w.config.series = newSeries;
25322
25640
  if (overwriteInitialSeries) {
25323
- me.w.globals.initialSeries = Utils$1.clone(me.w.config.series);
25641
+ me.w.globals.initialSeries = me.w.config.series;
25324
25642
  }
25325
25643
  return this.update();
25326
25644
  }
25645
+ /**
25646
+ * True when an options object carries enough series data that a
25647
+ * JSON.stringify equality check (and the Utils.clone needed to store it for
25648
+ * later comparison) would cost more than the re-render it tries to avoid.
25649
+ * @param {any} options
25650
+ * @returns {boolean}
25651
+ */
25652
+ static _optionsTooBigToCompare(options2) {
25653
+ const series = options2 && options2.series;
25654
+ if (!Array.isArray(series)) return false;
25655
+ let points = 0;
25656
+ for (let i = 0; i < series.length; i++) {
25657
+ const d = series[i] && series[i].data;
25658
+ points += Array.isArray(d) ? d.length : 1;
25659
+ if (points > 1e3) return true;
25660
+ }
25661
+ return false;
25662
+ }
25327
25663
  /**
25328
25664
  * @param {object} [options]
25329
25665
  */
25330
25666
  update(options2) {
25331
25667
  return new Promise((resolve, reject) => {
25332
- if (this.lastUpdateOptions && JSON.stringify(this.lastUpdateOptions) === JSON.stringify(options2)) {
25668
+ if (options2 && this.lastUpdateOptions && !_ApexCharts._optionsTooBigToCompare(options2) && JSON.stringify(this.lastUpdateOptions) === JSON.stringify(options2)) {
25333
25669
  return resolve(this);
25334
25670
  }
25335
- this.lastUpdateOptions = Utils$1.clone(options2);
25671
+ this.lastUpdateOptions = options2 && !_ApexCharts._optionsTooBigToCompare(options2) ? Utils$1.clone(options2) : null;
25336
25672
  new Destroy(this.ctx).clear({ isUpdating: true });
25337
25673
  const graphData = this.create(this.w.config.series, options2 != null ? options2 : {});
25338
25674
  if (!graphData) return resolve(this);
@@ -25351,6 +25687,140 @@ const _ApexCharts = class _ApexCharts {
25351
25687
  });
25352
25688
  });
25353
25689
  }
25690
+ /**
25691
+ * Redraws the scale-dependent chrome (grid lines, x-axis, y-axes) IN PLACE
25692
+ * within the frozen layout after a data-only update changed the axis
25693
+ * domain. The rebuilt groups replace the old nodes positionally, so z-order
25694
+ * (grid back/front) is preserved without re-running mount. Legend,
25695
+ * annotations containers, toolbar, defs/masks, and the plot geometry are
25696
+ * untouched.
25697
+ *
25698
+ * Returns false when the refresh cannot faithfully reproduce the chart and
25699
+ * the caller must fall back to a full render:
25700
+ * - horizontal bar charts (inversed axes draw through a different path)
25701
+ * - charts with annotations or ink notes (their positions are scale-bound
25702
+ * and are laid out by the full render)
25703
+ * - the new y labels no longer fit the width reserved at layout time
25704
+ *
25705
+ * @param {any} _xyRatios
25706
+ * @returns {boolean} true when the chrome was refreshed in place
25707
+ */
25708
+ _fastAxisChromeRefresh(_xyRatios) {
25709
+ const w = this.w;
25710
+ const gl = w.globals;
25711
+ this._fastAxisBailReason = "";
25712
+ try {
25713
+ if (gl.isBarHorizontal) {
25714
+ this._fastAxisBailReason = "barHorizontal";
25715
+ return false;
25716
+ }
25717
+ if (w.config.chart.sparkline.enabled) return true;
25718
+ const a = w.config.annotations;
25719
+ if (a && (a.yaxis && a.yaxis.length || a.xaxis && a.xaxis.length || a.points && a.points.length || a.texts && a.texts.length || a.images && a.images.length)) {
25720
+ this._fastAxisBailReason = "annotations";
25721
+ return false;
25722
+ }
25723
+ if (w.config.chart.ink && w.config.chart.ink.enabled) {
25724
+ this._fastAxisBailReason = "ink";
25725
+ return false;
25726
+ }
25727
+ const dim = this.dimensions;
25728
+ if (!dim || !dim.dimYAxis) {
25729
+ this._fastAxisBailReason = "noDimensions";
25730
+ return false;
25731
+ }
25732
+ const prevYLabelsCoords = w.layout.yLabelsCoords;
25733
+ const prevYTitleCoords = w.layout.yTitleCoords;
25734
+ const yaxisLabelCoords = dim.dimYAxis.getyAxisLabelsCoords();
25735
+ const yTitleCoords = dim.dimYAxis.getyAxisTitleCoords();
25736
+ w.layout.yLabelsCoords = [];
25737
+ w.layout.yTitleCoords = [];
25738
+ w.config.yaxis.map((_yaxe, index) => {
25739
+ w.layout.yLabelsCoords.push({
25740
+ width: yaxisLabelCoords[index].width,
25741
+ index
25742
+ });
25743
+ w.layout.yTitleCoords.push(
25744
+ /** @type {any} */
25745
+ { width: yTitleCoords[index].width, index }
25746
+ );
25747
+ });
25748
+ const newYAxisWidth = dim.dimYAxis.getTotalYAxisWidth();
25749
+ if (newYAxisWidth > dim.yAxisWidth + 2) {
25750
+ w.layout.yLabelsCoords = prevYLabelsCoords;
25751
+ w.layout.yTitleCoords = prevYTitleCoords;
25752
+ this._fastAxisBailReason = `labelWidth ${newYAxisWidth} > ${dim.yAxisWidth}`;
25753
+ return false;
25754
+ }
25755
+ const innerEl = w.dom.elGraphical.node;
25756
+ const oldGrid = innerEl.querySelector(".apexcharts-grid");
25757
+ const oldGridBorders = innerEl.querySelector(".apexcharts-grid-borders");
25758
+ if (!oldGrid) {
25759
+ this._fastAxisBailReason = "missingGridNode";
25760
+ return false;
25761
+ }
25762
+ const gridParent = oldGrid.parentNode;
25763
+ const gridNext = oldGridBorders ? oldGridBorders.nextSibling : oldGrid.nextSibling;
25764
+ oldGrid.remove();
25765
+ if (oldGridBorders) oldGridBorders.remove();
25766
+ innerEl.querySelectorAll(".apexcharts-xaxis-tick").forEach((t) => t.remove());
25767
+ this.grid = new Grid(w, this);
25768
+ const elgrid = this.grid.drawGrid();
25769
+ if (elgrid && elgrid.el) {
25770
+ gridParent.insertBefore(elgrid.el.node, gridNext);
25771
+ if (elgrid.elGridBorders && elgrid.elGridBorders.node) {
25772
+ gridParent.insertBefore(elgrid.elGridBorders.node, gridNext);
25773
+ }
25774
+ }
25775
+ const xAxis = new XAxis(this.w, this.ctx, elgrid);
25776
+ const oldXaxis = innerEl.querySelector(".apexcharts-xaxis");
25777
+ if (oldXaxis) {
25778
+ const xParent = oldXaxis.parentNode;
25779
+ const xNext = oldXaxis.nextSibling;
25780
+ oldXaxis.remove();
25781
+ const elXaxis = xAxis.drawXaxis();
25782
+ xParent.insertBefore(elXaxis.node, xNext);
25783
+ }
25784
+ const yAxis = new YAxis(
25785
+ this.w,
25786
+ { theme: this.theme, timeScale: this.timeScale },
25787
+ elgrid
25788
+ );
25789
+ for (let index = 0; index < w.config.yaxis.length; index++) {
25790
+ if (gl.ignoreYAxisIndexes.indexOf(index) !== -1) continue;
25791
+ const oldY = w.dom.baseEl.querySelector(
25792
+ `.apexcharts-yaxis[rel='${index}']`
25793
+ );
25794
+ if (!oldY) {
25795
+ this._fastAxisBailReason = "missingYAxisNode";
25796
+ return false;
25797
+ }
25798
+ const yParent = oldY.parentNode;
25799
+ if (!yParent) {
25800
+ this._fastAxisBailReason = "missingYAxisParent";
25801
+ return false;
25802
+ }
25803
+ const yNext = oldY.nextSibling;
25804
+ oldY.remove();
25805
+ const elYaxis = yAxis.drawYaxis(index);
25806
+ yParent.insertBefore(elYaxis.node, yNext);
25807
+ }
25808
+ if (elgrid !== null) {
25809
+ xAxis.xAxisLabelCorrections();
25810
+ yAxis.setYAxisTextAlignments();
25811
+ w.config.yaxis.map((yaxe, index) => {
25812
+ if (gl.ignoreYAxisIndexes.indexOf(index) === -1) {
25813
+ yAxis.yAxisTitleRotate(index, yaxe.opposite);
25814
+ }
25815
+ });
25816
+ }
25817
+ return true;
25818
+ } catch (e) {
25819
+ this._fastAxisBailReason = "error: " + (e && /** @type {any} */
25820
+ e.message);
25821
+ return false;
25822
+ }
25823
+ }
25354
25824
  /**
25355
25825
  * Fast update path for data-only series changes.
25356
25826
  *
@@ -25408,18 +25878,32 @@ const _ApexCharts = class _ApexCharts {
25408
25878
  }
25409
25879
  }
25410
25880
  const xyRatios = this.core.xySettings();
25881
+ if (this._zoomPanSelection) this._zoomPanSelection.xyRatios = xyRatios;
25411
25882
  const newAxisScaleSig = JSON.stringify({
25412
25883
  y: (gl.yAxisScale || []).map((s) => s ? s.result : null),
25413
25884
  xMin: gl.minX,
25414
25885
  xMax: gl.maxX
25415
25886
  });
25416
- if (gl.axisCharts && prevAxisScaleSig != null && newAxisScaleSig !== prevAxisScaleSig) {
25887
+ const scaleChanged = gl.axisCharts && prevAxisScaleSig != null && newAxisScaleSig !== prevAxisScaleSig;
25888
+ if (scaleChanged && !this._fastAxisChromeRefresh(xyRatios)) {
25889
+ this._updateStats.full++;
25417
25890
  return this.update().then(() => resolve(this)).catch(reject);
25418
25891
  }
25892
+ if (scaleChanged) {
25893
+ this._updateStats.fastWithAxes++;
25894
+ } else {
25895
+ this._updateStats.fast++;
25896
+ }
25419
25897
  (_a = this.weave) == null ? void 0 : _a.dispatch("afterScales", { pass: "fast", xyRatios });
25898
+ const rr = (
25899
+ /** @type {any} */
25900
+ this.ctx.renderer
25901
+ );
25902
+ const reuseCanvasHost = !!(rr && rr.kind === "canvas" && rr.canRepaintInPlace && rr.canRepaintInPlace());
25903
+ if (reuseCanvasHost) rr._repaintHostInPlace = true;
25420
25904
  const innerEl = w.dom.elGraphical.node;
25421
25905
  const toRemove = innerEl.querySelectorAll(
25422
- ".apexcharts-canvas-series-wrap, .apexcharts-series, .apexcharts-datalabels, .apexcharts-datalabels-background"
25906
+ (reuseCanvasHost ? "" : ".apexcharts-canvas-series-wrap, ") + ".apexcharts-plot-series, .apexcharts-series, .apexcharts-datalabels, .apexcharts-datalabels-background"
25423
25907
  );
25424
25908
  toRemove.forEach(
25425
25909
  (el) => {
@@ -25429,11 +25913,13 @@ const _ApexCharts = class _ApexCharts {
25429
25913
  );
25430
25914
  const elGraph = this.core.plotChartType(w.config.series, xyRatios);
25431
25915
  const gridEl = innerEl.querySelector(".apexcharts-grid");
25916
+ const xaxisEl = innerEl.querySelector(".apexcharts-xaxis");
25432
25917
  const graphs = Array.isArray(elGraph) ? elGraph : [elGraph];
25433
- if (gridEl && w.config.grid.position === "front") {
25918
+ const anchor = gridEl && w.config.grid.position === "front" ? gridEl : xaxisEl;
25919
+ if (anchor) {
25434
25920
  graphs.forEach((g) => {
25435
25921
  const node = g && g.node ? g.node : g;
25436
- if (node) innerEl.insertBefore(node, gridEl);
25922
+ if (node) innerEl.insertBefore(node, anchor);
25437
25923
  });
25438
25924
  } else {
25439
25925
  graphs.forEach((g) => {
@@ -26193,41 +26679,57 @@ const _ApexCharts = class _ApexCharts {
26193
26679
  return this.ctx.drilldown.drillToRoot();
26194
26680
  }
26195
26681
  // ─── Slice write-back stubs ─────────────────────────────────────────────────
26682
+ /**
26683
+ * Copy own DATA properties of a parse-state slice onto a live w.* slice.
26684
+ * Never Object.assign here: several w.* fields (and, historically, snapshot
26685
+ * fields) are lazy accessors, and [[Get]]-ing an accessor while copying
26686
+ * forces its deferred computation (a deep initialSeries clone plus O(n)
26687
+ * stacked-totals passes on every render/update) and can replace the live
26688
+ * accessor with a materialized value for the life of the instance.
26689
+ * @param {any} target
26690
+ * @param {any} slice
26691
+ */
26692
+ static _writeDataProps(target, slice) {
26693
+ for (const key of Object.keys(slice)) {
26694
+ const d = Object.getOwnPropertyDescriptor(slice, key);
26695
+ if (d && "value" in d) target[key] = d.value;
26696
+ }
26697
+ }
26196
26698
  /**
26197
26699
  * @param {Partial<import('./types/internal').SeriesData>} slice
26198
26700
  */
26199
26701
  _writeParsedSeriesData(slice) {
26200
- Object.assign(this.w.seriesData, slice);
26702
+ _ApexCharts._writeDataProps(this.w.seriesData, slice);
26201
26703
  }
26202
26704
  /**
26203
26705
  * @param {Partial<import('./types/internal').RangeData>} slice
26204
26706
  */
26205
26707
  _writeParsedRangeData(slice) {
26206
- Object.assign(this.w.rangeData, slice);
26708
+ _ApexCharts._writeDataProps(this.w.rangeData, slice);
26207
26709
  }
26208
26710
  /**
26209
26711
  * @param {Partial<import('./types/internal').CandleData>} slice
26210
26712
  */
26211
26713
  _writeParsedCandleData(slice) {
26212
- Object.assign(this.w.candleData, slice);
26714
+ _ApexCharts._writeDataProps(this.w.candleData, slice);
26213
26715
  }
26214
26716
  /**
26215
26717
  * @param {Partial<import('./types/internal').LabelData>} slice
26216
26718
  */
26217
26719
  _writeParsedLabelData(slice) {
26218
- Object.assign(this.w.labelData, slice);
26720
+ _ApexCharts._writeDataProps(this.w.labelData, slice);
26219
26721
  }
26220
26722
  /**
26221
26723
  * @param {Partial<import('./types/internal').AxisFlags>} slice
26222
26724
  */
26223
26725
  _writeParsedAxisFlags(slice) {
26224
- Object.assign(this.w.axisFlags, slice);
26726
+ _ApexCharts._writeDataProps(this.w.axisFlags, slice);
26225
26727
  }
26226
26728
  /**
26227
26729
  * @param {Partial<import('./types/internal').LayoutCoords>} slice
26228
26730
  */
26229
26731
  _writeLayoutCoords(slice) {
26230
- Object.assign(this.w.layout, slice);
26732
+ _ApexCharts._writeDataProps(this.w.layout, slice);
26231
26733
  }
26232
26734
  _parentResizeCallback() {
26233
26735
  if (this.w.globals.animationEnded && this.w.config.chart.redrawOnParentResize) {
@@ -28765,7 +29267,6 @@ class ZoomPanSelection extends Toolbar {
28765
29267
  this.xyRatios = xyRatios;
28766
29268
  this.zoomRect = this.graphics.drawRect(0, 0, 0, 0);
28767
29269
  this.selectionRect = this.graphics.drawRect(0, 0, 0, 0);
28768
- this.gridRect = w.dom.baseEl.querySelector(".apexcharts-grid");
28769
29270
  this.constraints = new Box(0, 0, w.layout.gridWidth, w.layout.gridHeight);
28770
29271
  this.zoomRect.node.classList.add("apexcharts-zoom-rect");
28771
29272
  this.selectionRect.node.classList.add("apexcharts-selection-rect");
@@ -28829,14 +29330,12 @@ class ZoomPanSelection extends Toolbar {
28829
29330
  }
28830
29331
  this.selectionRect = null;
28831
29332
  this.zoomRect = null;
28832
- this.gridRect = null;
28833
29333
  }
28834
29334
  /**
28835
29335
  * @param {import('../types/internal').XYRatios} xyRatios
28836
29336
  * @param {any} e
28837
29337
  */
28838
29338
  svgMouseEvents(xyRatios, e) {
28839
- var _a;
28840
29339
  const w = this.w;
28841
29340
  const toolbar = this.ctx.toolbar;
28842
29341
  if (w.interact.momentum && w.interact.momentum.busy) return;
@@ -28867,7 +29366,7 @@ class ZoomPanSelection extends Toolbar {
28867
29366
  this.clientX = e.type === "touchmove" || e.type === "touchstart" ? e.touches[0].clientX : e.type === "touchend" ? e.changedTouches[0].clientX : e.clientX;
28868
29367
  this.clientY = e.type === "touchmove" || e.type === "touchstart" ? e.touches[0].clientY : e.type === "touchend" ? e.changedTouches[0].clientY : e.clientY;
28869
29368
  if (e.type === "mousedown" && e.which === 1 || e.type === "touchstart") {
28870
- const gridRectDim = (_a = this.gridRect) == null ? void 0 : _a.getBoundingClientRect();
29369
+ const gridRectDim = this._gridRect();
28871
29370
  if (!gridRectDim) return;
28872
29371
  this.startX = this.clientX - gridRectDim.left - w.globals.barPadForNumericAxis;
28873
29372
  this.startY = this.clientY - gridRectDim.top;
@@ -28882,7 +29381,7 @@ class ZoomPanSelection extends Toolbar {
28882
29381
  this.panDragging({
28883
29382
  context: this,
28884
29383
  zoomtype,
28885
- xyRatios
29384
+ xyRatios: this.xyRatios
28886
29385
  });
28887
29386
  }
28888
29387
  } else {
@@ -28901,9 +29400,8 @@ class ZoomPanSelection extends Toolbar {
28901
29400
  }
28902
29401
  /** @param {{ zoomtype?: any, isResized?: any }} opts */
28903
29402
  handleMouseUp({ zoomtype, isResized }) {
28904
- var _a;
28905
29403
  const w = this.w;
28906
- const gridRectDim = (_a = this.gridRect) == null ? void 0 : _a.getBoundingClientRect();
29404
+ const gridRectDim = this._gridRect();
28907
29405
  if (gridRectDim && (this.w.interact.mousedown || isResized)) {
28908
29406
  this.endX = this.clientX - gridRectDim.left - w.globals.barPadForNumericAxis;
28909
29407
  this.endY = this.clientY - gridRectDim.top;
@@ -28945,11 +29443,11 @@ class ZoomPanSelection extends Toolbar {
28945
29443
  * @param {any} e
28946
29444
  */
28947
29445
  executeMouseWheelZoom(e) {
28948
- var _a, _b, _c;
29446
+ var _a, _b;
28949
29447
  const w = this.w;
28950
29448
  this.minX = w.axisFlags.isRangeBar ? w.globals.minY : w.globals.minX;
28951
29449
  this.maxX = w.axisFlags.isRangeBar ? w.globals.maxY : w.globals.maxX;
28952
- const gridRectDim = (_a = this.gridRect) == null ? void 0 : _a.getBoundingClientRect();
29450
+ const gridRectDim = this._gridRect();
28953
29451
  if (!gridRectDim) return;
28954
29452
  const mouseX = (e.clientX - gridRectDim.left) / gridRectDim.width;
28955
29453
  const currentMinX = this.minX;
@@ -28970,8 +29468,8 @@ class ZoomPanSelection extends Toolbar {
28970
29468
  newMaxX = currentMaxX + zoomRange / 2;
28971
29469
  }
28972
29470
  if (!w.axisFlags.isRangeBar) {
28973
- const clampMin = (_b = w.globals.dataReducerRawMinX) != null ? _b : w.globals.initialMinX;
28974
- const clampMax = (_c = w.globals.dataReducerRawMaxX) != null ? _c : w.globals.initialMaxX;
29471
+ const clampMin = (_a = w.globals.dataReducerRawMinX) != null ? _a : w.globals.initialMinX;
29472
+ const clampMax = (_b = w.globals.dataReducerRawMaxX) != null ? _b : w.globals.initialMaxX;
28975
29473
  newMinX = Math.max(newMinX, clampMin);
28976
29474
  newMaxX = Math.min(newMaxX, clampMax);
28977
29475
  const minXDiff = w.globals.minXDiff > 0 && isFinite(w.globals.minXDiff) ? w.globals.minXDiff : 0;
@@ -29108,10 +29606,9 @@ class ZoomPanSelection extends Toolbar {
29108
29606
  }
29109
29607
  }
29110
29608
  selectionDrawing({ context, zoomtype }) {
29111
- var _a;
29112
29609
  const w = this.w;
29113
29610
  const me = context;
29114
- const gridRectDim = (_a = this.gridRect) == null ? void 0 : _a.getBoundingClientRect();
29611
+ const gridRectDim = this._gridRect();
29115
29612
  if (!gridRectDim) return;
29116
29613
  const startX = me.startX - 1;
29117
29614
  const startY = me.startY;
@@ -29217,8 +29714,8 @@ class ZoomPanSelection extends Toolbar {
29217
29714
  if ((typeof w.config.chart.events.selection === "function" || linkActive) && w.interact.selectionEnabled) {
29218
29715
  clearTimeout((_a = this.w.globals.selectionResizeTimer) != null ? _a : void 0);
29219
29716
  this.w.globals.selectionResizeTimer = window.setTimeout(() => {
29220
- var _a2, _b;
29221
- const gridRectDim = (_a2 = this.gridRect) == null ? void 0 : _a2.getBoundingClientRect();
29717
+ var _a2;
29718
+ const gridRectDim = this._gridRect();
29222
29719
  if (!gridRectDim) return;
29223
29720
  const selectionRect = selRect.node.getBoundingClientRect();
29224
29721
  let minX, maxX, minY, maxY;
@@ -29252,7 +29749,7 @@ class ZoomPanSelection extends Toolbar {
29252
29749
  if (w.config.chart.brush.enabled && w.config.chart.events.brushScrolled !== void 0) {
29253
29750
  w.config.chart.events.brushScrolled(this.ctx, xyAxis);
29254
29751
  }
29255
- (_b = this.ctx.linkedViews) == null ? void 0 : _b.onSourceSelection(xyAxis.xaxis);
29752
+ (_a2 = this.ctx.linkedViews) == null ? void 0 : _a2.onSourceSelection(xyAxis.xaxis);
29256
29753
  }, timerInterval);
29257
29754
  }
29258
29755
  }
@@ -29264,7 +29761,8 @@ class ZoomPanSelection extends Toolbar {
29264
29761
  const xyRatios = this.xyRatios;
29265
29762
  const toolbar = this.ctx.toolbar;
29266
29763
  const selRect = w.interact.zoomEnabled ? me.zoomRect.node.getBoundingClientRect() : me.selectionRect.node.getBoundingClientRect();
29267
- const gridRectDim = me.gridRect.getBoundingClientRect();
29764
+ const gridRectDim = me._gridRect();
29765
+ if (!gridRectDim) return;
29268
29766
  const localStartX = selRect.left - gridRectDim.left - w.globals.barPadForNumericAxis;
29269
29767
  const localEndX = selRect.right - gridRectDim.left - w.globals.barPadForNumericAxis;
29270
29768
  const localStartY = selRect.top - gridRectDim.top;
@@ -29522,8 +30020,11 @@ class ZoomPanSelection extends Toolbar {
29522
30020
  const w = this.w;
29523
30021
  return w.axisFlags.isRangeBar ? { min: w.globals.minY, max: w.globals.maxY } : { min: w.globals.minX, max: w.globals.maxX };
29524
30022
  }
29525
- /** Live grid rect from the current DOM (this.gridRect goes stale/null after
29526
- * the re-render a gesture frame triggers). */
30023
+ /** Live grid rect from the current DOM. Never cache the grid node on the
30024
+ * instance: a full render replaces this whole instance, but the fast update
30025
+ * path (fastUpdate/_fastAxisChromeRefresh) keeps the instance while swapping
30026
+ * the grid node, and a cached node would go stale (detached nodes report an
30027
+ * all-zero bounding rect, silently corrupting selection geometry). */
29527
30028
  _gridRect() {
29528
30029
  const baseEl = this.w.dom.baseEl;
29529
30030
  const grid = baseEl && baseEl.querySelector(".apexcharts-grid");
@@ -35336,6 +35837,20 @@ class CanvasRenderer {
35336
35837
  clear() {
35337
35838
  this._compositor.clear();
35338
35839
  }
35840
+ /**
35841
+ * Whether the existing <canvas> host can be repainted in place (it exists
35842
+ * and is still mounted). Used by the data-only fast update path to skip
35843
+ * recreating the foreignObject + backing store on every tick.
35844
+ * @returns {boolean}
35845
+ */
35846
+ canRepaintInPlace() {
35847
+ const host = this._compositor.getHost();
35848
+ return !!(host && host.node && host.node.isConnected);
35849
+ }
35850
+ /** Repaint the freshly recorded display list into the EXISTING canvas. */
35851
+ repaintInPlace() {
35852
+ this._compositor.paint(this._g.displayList(), this._g);
35853
+ }
35339
35854
  // ── emit primitives (delegate to the display-list shim) ──
35340
35855
  /** @param {any} attrs */
35341
35856
  group(attrs) {
@@ -43949,7 +44464,7 @@ class Line {
43949
44464
  let { pathFromLine, pathFromArea } = pathsFrom;
43950
44465
  const r = this.ctx && this.ctx.renderer;
43951
44466
  const canvasMode = !!(r && r.kind && r.kind !== "svg");
43952
- const buildStrings = !canvasMode || w.globals.dataChanged;
44467
+ const buildStrings = !canvasMode || w.globals.dataChanged && !!w.globals.prevStreamFrame;
43953
44468
  const nxs = canvasMode ? new Float64Array(n) : null;
43954
44469
  const nys = canvasMode ? new Float64Array(n) : null;
43955
44470
  if (nxs && nys) {