apexcharts 6.3.0 → 6.4.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 (106) hide show
  1. package/dist/apexcharts.common.js +2 -2
  2. package/dist/apexcharts.esm.js +769 -117
  3. package/dist/apexcharts.js +769 -117
  4. package/dist/apexcharts.min.js +2 -2
  5. package/dist/apexcharts.ssr.common.js +2 -2
  6. package/dist/apexcharts.ssr.esm.js +769 -117
  7. package/dist/area.common.js +2 -2
  8. package/dist/area.esm.js +3 -3
  9. package/dist/bar.common.js +2 -2
  10. package/dist/bar.esm.js +208 -109
  11. package/dist/boxPlot.common.js +2 -2
  12. package/dist/boxPlot.esm.js +208 -109
  13. package/dist/bubble.common.js +2 -2
  14. package/dist/bubble.esm.js +3 -3
  15. package/dist/candlestick.common.js +2 -2
  16. package/dist/candlestick.esm.js +208 -109
  17. package/dist/column.common.js +2 -2
  18. package/dist/column.esm.js +208 -109
  19. package/dist/core.common.js +2 -2
  20. package/dist/core.esm.js +372 -62
  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 +282 -9
  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 +280 -7
  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 +1 -1
  58. package/dist/features/toolbar.esm.js +1 -1
  59. package/dist/features/weave.common.js +1 -1
  60. package/dist/features/weave.esm.js +1 -1
  61. package/dist/heatmap.common.js +2 -2
  62. package/dist/heatmap.esm.js +79 -41
  63. package/dist/line.common.js +2 -2
  64. package/dist/line.esm.js +3 -3
  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 +3 -3
  75. package/dist/rangeBar.common.js +2 -2
  76. package/dist/rangeBar.esm.js +208 -109
  77. package/dist/scatter.common.js +2 -2
  78. package/dist/scatter.esm.js +3 -3
  79. package/dist/treemap.common.js +1 -1
  80. package/dist/treemap.esm.js +1 -1
  81. package/dist/violin.common.js +2 -2
  82. package/dist/violin.esm.js +208 -109
  83. package/package.json +1 -1
  84. package/src/apexcharts.js +7 -0
  85. package/src/charts/Bar.js +38 -6
  86. package/src/charts/HeatMap.js +126 -55
  87. package/src/charts/common/bar/DataLabels.js +16 -0
  88. package/src/modules/Data.js +14 -2
  89. package/src/modules/Filters.js +34 -6
  90. package/src/modules/Graphics.js +4 -4
  91. package/src/modules/Series.js +6 -0
  92. package/src/modules/animations/AxisTransition.js +57 -15
  93. package/src/modules/animations/DataLabelTransition.js +235 -0
  94. package/src/modules/animations/LengthTransition.js +15 -2
  95. package/src/modules/axes/YAxis.js +21 -1
  96. package/src/modules/settings/Defaults.js +12 -1
  97. package/src/modules/settings/Options.js +16 -0
  98. package/src/modules/tooltip/Intersect.js +145 -32
  99. package/src/modules/tooltip/Labels.js +9 -0
  100. package/src/modules/tooltip/Tooltip.js +28 -7
  101. package/src/renderers/Renderer.js +8 -2
  102. package/src/renderers/canvas/CanvasCompositor.js +100 -1
  103. package/src/renderers/canvas/CanvasGraphics.js +184 -0
  104. package/src/renderers/canvas/CanvasRenderer.js +46 -6
  105. package/src/types/internal.d.ts +8 -0
  106. package/types/apexcharts.d.ts +30 -0
@@ -51,7 +51,7 @@ var __async = (__this, __arguments, generator) => {
51
51
  });
52
52
  };
53
53
  /*!
54
- * ApexCharts v6.3.0
54
+ * ApexCharts v6.4.0
55
55
  * (c) 2018-2026 ApexCharts
56
56
  */
57
57
  class Environment {
@@ -2815,7 +2815,14 @@ class Defaults {
2815
2815
  heatmap() {
2816
2816
  return {
2817
2817
  chart: {
2818
- stacked: false
2818
+ stacked: false,
2819
+ // A heatmap is a fixed grid: zooming/panning only distorts the cells
2820
+ // and (on a datetime axis) collapses the month labels to repeats, so
2821
+ // it is off by default, mirroring treemap. Users can opt back in with
2822
+ // chart.zoom.enabled: true.
2823
+ zoom: {
2824
+ enabled: false
2825
+ }
2819
2826
  },
2820
2827
  fill: {
2821
2828
  opacity: 1
@@ -2829,7 +2836,11 @@ class Defaults {
2829
2836
  colors: ["#fff"]
2830
2837
  },
2831
2838
  tooltip: {
2832
- followCursor: true,
2839
+ // Anchor the tooltip above the hovered cell with a downward arrow
2840
+ // (flipping below near the top edge), the same treatment horizontal
2841
+ // bars get, rather than trailing the cursor. Opt back into the old
2842
+ // behavior with tooltip.followCursor: true.
2843
+ followCursor: false,
2833
2844
  marker: {
2834
2845
  show: false
2835
2846
  },
@@ -4510,6 +4521,20 @@ class Options {
4510
4521
  blur: 1,
4511
4522
  color: "#000",
4512
4523
  opacity: 0.8
4524
+ },
4525
+ // Ride data labels to their new position on a data-change update
4526
+ // (e.g. a bar chart race), instead of snapping. Off by default so
4527
+ // existing charts are unchanged. Speed/easing follow
4528
+ // chart.animations.dynamicAnimation. Bar/column only.
4529
+ animate: {
4530
+ enabled: false
4531
+ },
4532
+ // Count the numeric value up/down from its previous value on update,
4533
+ // like countUp.js. Off by default. The dataLabels.formatter runs each
4534
+ // frame, so number formatting (decimals, separators, prefixes) is
4535
+ // preserved. Bar/column only.
4536
+ countUp: {
4537
+ enabled: false
4513
4538
  }
4514
4539
  },
4515
4540
  fill: {
@@ -4701,13 +4726,15 @@ class Options {
4701
4726
  states: {
4702
4727
  hover: {
4703
4728
  filter: {
4704
- type: "lighten"
4729
+ type: "lighten",
4730
+ value: 0.15
4705
4731
  }
4706
4732
  },
4707
4733
  active: {
4708
4734
  allowMultipleDataPointsSelection: false,
4709
4735
  filter: {
4710
- type: "darken"
4736
+ type: "darken",
4737
+ value: 0.35
4711
4738
  }
4712
4739
  }
4713
4740
  },
@@ -8187,6 +8214,7 @@ class Animations {
8187
8214
  });
8188
8215
  }
8189
8216
  }
8217
+ const DEFAULT_INTENSITY = { lighten: 0.15, darken: 0.35 };
8190
8218
  class Filters {
8191
8219
  /**
8192
8220
  * @param {import('../types/internal').ChartStateW} w
@@ -8212,8 +8240,9 @@ class Filters {
8212
8240
  * @param {any} el
8213
8241
  * @param {number} i
8214
8242
  * @param {string} filterType
8243
+ * @param {number} [intensity] Blend strength (0 to 1). Defaults per type.
8215
8244
  */
8216
- applyFilter(el, i, filterType) {
8245
+ applyFilter(el, i, filterType, intensity) {
8217
8246
  var _a, _b, _c;
8218
8247
  const w = this.w;
8219
8248
  if (el.unfilter) {
@@ -8224,15 +8253,21 @@ class Filters {
8224
8253
  return;
8225
8254
  }
8226
8255
  const shadowAttr = w.config.chart.dropShadow;
8227
- const brightnessFactor = filterType === "lighten" ? 2 : 0.3;
8256
+ const fallback = filterType === "lighten" ? DEFAULT_INTENSITY.lighten : DEFAULT_INTENSITY.darken;
8257
+ const t = Math.max(
8258
+ 0,
8259
+ Math.min(1, typeof intensity === "number" ? intensity : fallback)
8260
+ );
8261
+ const diag = 1 - t;
8262
+ const offset = filterType === "lighten" ? t : 0;
8228
8263
  if (el.filterWith) {
8229
8264
  el.filterWith((add) => {
8230
8265
  add.colorMatrix({
8231
8266
  type: "matrix",
8232
8267
  values: `
8233
- ${brightnessFactor} 0 0 0 0
8234
- 0 ${brightnessFactor} 0 0 0
8235
- 0 0 ${brightnessFactor} 0 0
8268
+ ${diag} 0 0 0 ${offset}
8269
+ 0 ${diag} 0 0 ${offset}
8270
+ 0 0 ${diag} 0 ${offset}
8236
8271
  0 0 0 1 0
8237
8272
  `,
8238
8273
  in: "SourceGraphic",
@@ -8331,7 +8366,7 @@ class Filters {
8331
8366
  el.node.setAttribute("selected", true);
8332
8367
  const activeFilter = w.config.states.active.filter;
8333
8368
  if (activeFilter !== "none") {
8334
- this.applyFilter(el, realIndex, activeFilter.type);
8369
+ this.applyFilter(el, realIndex, activeFilter.type, activeFilter.value);
8335
8370
  }
8336
8371
  }
8337
8372
  }
@@ -9170,7 +9205,7 @@ class Graphics {
9170
9205
  if (w.config.states.hover.filter.type !== "none") {
9171
9206
  if (!w.interact.isTouchDevice) {
9172
9207
  const hoverFilter = w.config.states.hover.filter;
9173
- filters.applyFilter(path, i, hoverFilter.type);
9208
+ filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value);
9174
9209
  }
9175
9210
  }
9176
9211
  }
@@ -9255,12 +9290,12 @@ class Graphics {
9255
9290
  if (selected === "true") {
9256
9291
  const activeFilter = w.config.states.active.filter;
9257
9292
  if (activeFilter !== "none") {
9258
- filters.applyFilter(path, i, activeFilter.type);
9293
+ filters.applyFilter(path, i, activeFilter.type, activeFilter.value);
9259
9294
  } else {
9260
9295
  if (w.config.states.hover.filter !== "none") {
9261
9296
  if (!w.interact.isTouchDevice) {
9262
9297
  const hoverFilter = w.config.states.hover.filter;
9263
- filters.applyFilter(path, i, hoverFilter.type);
9298
+ filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value);
9264
9299
  }
9265
9300
  }
9266
9301
  }
@@ -9268,7 +9303,7 @@ class Graphics {
9268
9303
  if (w.config.states.active.filter.type !== "none") {
9269
9304
  if (w.config.states.hover.filter.type !== "none" && !w.interact.isTouchDevice) {
9270
9305
  const hoverFilter = w.config.states.hover.filter;
9271
- filters.applyFilter(path, i, hoverFilter.type);
9306
+ filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value);
9272
9307
  } else {
9273
9308
  filters.getDefaultFilter(path, i);
9274
9309
  }
@@ -9907,12 +9942,13 @@ function computeMarkCount(w) {
9907
9942
  const markerSize = w.config.markers && w.config.markers.size;
9908
9943
  const markersOn = Array.isArray(markerSize) ? markerSize.some((s) => s > 0) : (markerSize || 0) > 0;
9909
9944
  const labelsOn = !!(w.config.dataLabels && w.config.dataLabels.enabled);
9945
+ const isHeatmap = type === "heatmap";
9910
9946
  let total = 0;
9911
9947
  let maxLen = 0;
9912
9948
  series.forEach((s) => {
9913
9949
  const n = Array.isArray(s.data) ? s.data.length : 0;
9914
9950
  if (n > maxLen) maxLen = n;
9915
- if (scatterish || markersOn) total += n;
9951
+ if (scatterish || markersOn || isHeatmap) total += n;
9916
9952
  if (labelsOn) total += n;
9917
9953
  });
9918
9954
  const LARGE_D = 5e4;
@@ -13474,6 +13510,13 @@ class YAxis {
13474
13510
  realIndex,
13475
13511
  w.globals.yAxisScale[realIndex].result.slice()
13476
13512
  );
13513
+ let labelStep = 1;
13514
+ if (w.config.chart.type === "heatmap" && !w.config.yaxis[realIndex].labels.formatter) {
13515
+ const fs = parseInt(yaxisFontSize, 10) || 11;
13516
+ const maxLabels = Math.max(1, Math.floor(w.layout.gridHeight / (fs * 1.4)));
13517
+ const count = tickAmount + 1;
13518
+ if (count > maxLabels) labelStep = Math.ceil(count / maxLabels);
13519
+ }
13477
13520
  if (w.config.yaxis[realIndex].labels.show) {
13478
13521
  let lY = w.layout.translateY + w.config.yaxis[realIndex].labels.offsetY;
13479
13522
  if (w.globals.isBarHorizontal) lY = 0;
@@ -13481,7 +13524,8 @@ class YAxis {
13481
13524
  lY += parseInt(yaxisFontSize, 10) / 3;
13482
13525
  let firstLabel = null;
13483
13526
  for (let i = tickAmount; i >= 0; i--) {
13484
- const val = lbFormatter(labels[i], i, w);
13527
+ const thinned = labelStep > 1 && i % labelStep !== 0;
13528
+ const val = thinned ? "" : lbFormatter(labels[i], i, w);
13485
13529
  let xPad = w.config.yaxis[realIndex].labels.padding;
13486
13530
  if (w.config.yaxis[realIndex].opposite && w.config.yaxis.length !== 0)
13487
13531
  xPad *= -1;
@@ -14716,7 +14760,7 @@ function uniquifyKeys(keys) {
14716
14760
  return count === 0 ? k : `${k}#${count}`;
14717
14761
  });
14718
14762
  }
14719
- function seriesJoin(w, realIndex, includeIdentity = false) {
14763
+ function seriesJoin(w, realIndex, includeIdentity = false, allowReorder = false) {
14720
14764
  var _a, _b;
14721
14765
  if (!lengthTransitionEnabled(w)) return null;
14722
14766
  const frame = w.globals.prevStreamFrame;
@@ -14730,7 +14774,7 @@ function seriesJoin(w, realIndex, includeIdentity = false) {
14730
14774
  );
14731
14775
  const newKeys = uniquifyKeys(newY.map((_, j) => datumKey(w, realIndex, j)));
14732
14776
  const join = joinKeys(oldKeys, newKeys);
14733
- if (!join.ordered) return null;
14777
+ if (!join.ordered && !allowReorder) return null;
14734
14778
  if (!join.changed && !includeIdentity) return null;
14735
14779
  return { join, oldKeys, newKeys };
14736
14780
  }
@@ -15039,7 +15083,7 @@ function captureAxisChrome(w) {
15039
15083
  gl.prevChromeFrame = null;
15040
15084
  }
15041
15085
  }
15042
- function fadeIn(w, node, duration, ease) {
15086
+ function fadeIn$1(w, node, duration, ease) {
15043
15087
  const style = (
15044
15088
  /** @type {any} */
15045
15089
  node.style
@@ -15136,34 +15180,59 @@ function transitionAxis(w, {
15136
15180
  const spanHi = Math.max(...spanPs);
15137
15181
  const margin = Math.max(40, (spanHi - spanLo) * 0.25);
15138
15182
  const clamp = (p) => Math.max(spanLo - margin, Math.min(spanHi + margin, p));
15183
+ const tweenPairedLine = (line, old) => {
15184
+ if (!line) return;
15185
+ const lineTo = parseFloat(line.getAttribute(lineAttrs[0]) || "");
15186
+ const lineFrom = oldLines[old.i];
15187
+ if (isFinite(lineTo) && isFinite(lineFrom)) {
15188
+ tweenPos(w, line, lineAttrs, lineFrom, lineTo, duration, ease);
15189
+ }
15190
+ };
15139
15191
  newLabels.forEach((label, i) => {
15140
15192
  const to = parseFloat(label.getAttribute(posAttr) || "");
15141
15193
  const old = oldByText.get(label.textContent || "");
15142
15194
  const line = newLinesAligned ? newLines[i] : null;
15143
15195
  if (old) matchedOld.add(old.i);
15144
- if (!old || !isFinite(old.pos) || old.transform || label.getAttribute("transform")) {
15196
+ const labelTransform = label.getAttribute("transform");
15197
+ if (!old || !isFinite(old.pos)) {
15145
15198
  if (!old) {
15146
- if (project && isFinite(to) && !label.getAttribute("transform")) {
15199
+ if (project && isFinite(to) && !labelTransform) {
15147
15200
  const from = isFinite(project.toOld(to)) ? clamp(project.toOld(to)) : NaN;
15148
15201
  if (isFinite(from) && Math.abs(from - to) > 0.5) {
15149
15202
  tweenPos(w, label, [posAttr], from, to, duration, ease);
15150
15203
  if (line) tweenPos(w, line, lineAttrs, from, to, duration, ease);
15151
15204
  }
15152
15205
  }
15153
- fadeIn(w, label, duration, ease);
15154
- if (line) fadeIn(w, line, duration, ease);
15206
+ fadeIn$1(w, label, duration, ease);
15207
+ if (line) fadeIn$1(w, line, duration, ease);
15155
15208
  }
15156
15209
  return;
15157
15210
  }
15158
15211
  if (!isFinite(to) || Math.abs(old.pos - to) < 0.5) return;
15159
- tweenPos(w, label, [posAttr], old.pos, to, duration, ease);
15160
- if (line) {
15161
- const lineTo = parseFloat(line.getAttribute(lineAttrs[0]) || "");
15162
- const lineFrom = oldLines[old.i];
15163
- if (isFinite(lineTo) && isFinite(lineFrom)) {
15164
- tweenPos(w, line, lineAttrs, lineFrom, lineTo, duration, ease);
15212
+ if (labelTransform || old.transform) {
15213
+ const delta = old.pos - to;
15214
+ if (isFinite(delta)) {
15215
+ const base = labelTransform || "";
15216
+ rafTween(
15217
+ w,
15218
+ duration,
15219
+ ease,
15220
+ (eased) => {
15221
+ const v = delta * (1 - eased);
15222
+ const t = posAttr === "x" ? `translate(${v} 0)` : `translate(0 ${v})`;
15223
+ label.setAttribute("transform", `${t} ${base}`.trim());
15224
+ },
15225
+ () => {
15226
+ if (base) label.setAttribute("transform", base);
15227
+ else label.removeAttribute("transform");
15228
+ }
15229
+ );
15165
15230
  }
15231
+ tweenPairedLine(line, old);
15232
+ return;
15166
15233
  }
15234
+ tweenPos(w, label, [posAttr], old.pos, to, duration, ease);
15235
+ tweenPairedLine(line, old);
15167
15236
  });
15168
15237
  if (!project || !newLabels.length) return;
15169
15238
  let ghosts = 0;
@@ -15202,7 +15271,7 @@ function applyAxisTransition(w) {
15202
15271
  if (!chrome || !gl.axisCharts || !Environment.isBrowser()) return;
15203
15272
  if (!lengthTransitionEnabled(w)) return;
15204
15273
  const anyMotion = (w.seriesData.series || []).some(
15205
- (_, i) => seriesJoin(w, i, true) !== null
15274
+ (_, i) => seriesJoin(w, i, true, true) !== null
15206
15275
  );
15207
15276
  if (!anyMotion) return;
15208
15277
  const root = w.dom.baseEl;
@@ -15246,6 +15315,158 @@ function applyAxisTransition(w) {
15246
15315
  } catch (_) {
15247
15316
  }
15248
15317
  }
15318
+ const DL_GROUP_SEL = ".apexcharts-data-labels[data\\:dlKey]";
15319
+ const DL_TEXT_SEL = ".apexcharts-datalabel";
15320
+ function dataLabelMotionEnabled(w) {
15321
+ var _a, _b;
15322
+ const dl = w.config.dataLabels;
15323
+ return !!(((_a = dl == null ? void 0 : dl.animate) == null ? void 0 : _a.enabled) || ((_b = dl == null ? void 0 : dl.countUp) == null ? void 0 : _b.enabled));
15324
+ }
15325
+ function decimalsOf(n) {
15326
+ if (!isFinite(n)) return 0;
15327
+ const s = String(n);
15328
+ const dot = s.indexOf(".");
15329
+ return dot === -1 ? 0 : Math.min(6, s.length - dot - 1);
15330
+ }
15331
+ function writeLabel(textEl, s) {
15332
+ const tspan = textEl.querySelector("tspan");
15333
+ if (tspan) tspan.textContent = s;
15334
+ else textEl.textContent = s;
15335
+ }
15336
+ function captureDataLabels(w) {
15337
+ const gl = w.globals;
15338
+ gl.prevDataLabels = null;
15339
+ if (!gl.axisCharts || !Environment.isBrowser()) return;
15340
+ if (!dataLabelMotionEnabled(w)) return;
15341
+ const root = w.dom.baseEl;
15342
+ if (!Utils$1.elementExists(root)) return;
15343
+ try {
15344
+ const map = /* @__PURE__ */ new Map();
15345
+ root.querySelectorAll(DL_GROUP_SEL).forEach((group) => {
15346
+ const key = group.getAttribute("data:dlKey");
15347
+ if (!key) return;
15348
+ const textEl = group.querySelector(DL_TEXT_SEL);
15349
+ if (!textEl) return;
15350
+ map.set(key, {
15351
+ cx: parseFloat(textEl.getAttribute("cx") || ""),
15352
+ cy: parseFloat(textEl.getAttribute("cy") || ""),
15353
+ val: parseFloat(group.getAttribute("data:dlVal") || "")
15354
+ });
15355
+ });
15356
+ gl.prevDataLabels = map.size ? map : null;
15357
+ } catch (_) {
15358
+ gl.prevDataLabels = null;
15359
+ }
15360
+ }
15361
+ function fadeIn(w, node, duration, ease) {
15362
+ const style = (
15363
+ /** @type {any} */
15364
+ node.style
15365
+ );
15366
+ style.opacity = "0";
15367
+ rafTween(
15368
+ w,
15369
+ duration,
15370
+ ease,
15371
+ (eased) => {
15372
+ style.opacity = String(eased);
15373
+ },
15374
+ () => {
15375
+ style.opacity = "";
15376
+ }
15377
+ );
15378
+ }
15379
+ function applyDataLabelTransition(w) {
15380
+ var _a, _b;
15381
+ const gl = w.globals;
15382
+ const prev = gl.prevDataLabels;
15383
+ gl.prevDataLabels = null;
15384
+ if (!prev || !gl.axisCharts || !Environment.isBrowser()) return;
15385
+ if (!dataLabelMotionEnabled(w)) return;
15386
+ if (!lengthTransitionEnabled(w)) return;
15387
+ const root = w.dom.baseEl;
15388
+ if (!Utils$1.elementExists(root)) return;
15389
+ const dl = w.config.dataLabels;
15390
+ const ride = !!((_a = dl.animate) == null ? void 0 : _a.enabled);
15391
+ const countUp = !!((_b = dl.countUp) == null ? void 0 : _b.enabled);
15392
+ const formatter = dl.formatter;
15393
+ const duration = Math.max(1, w.config.chart.animations.dynamicAnimation.speed || 1);
15394
+ const ease = morphEasing(w);
15395
+ try {
15396
+ root.querySelectorAll(DL_GROUP_SEL).forEach((group) => {
15397
+ const key = group.getAttribute("data:dlKey");
15398
+ if (!key) return;
15399
+ const textEl = group.querySelector(DL_TEXT_SEL);
15400
+ if (!textEl) return;
15401
+ const old = prev.get(key);
15402
+ if (ride) {
15403
+ if (old && isFinite(old.cx) && isFinite(old.cy)) {
15404
+ const newCx = parseFloat(textEl.getAttribute("cx") || "");
15405
+ const newCy = parseFloat(textEl.getAttribute("cy") || "");
15406
+ const dx = old.cx - newCx;
15407
+ const dy = old.cy - newCy;
15408
+ if (isFinite(dx) && isFinite(dy) && Math.abs(dx) + Math.abs(dy) > 0.5) {
15409
+ const base = group.getAttribute("transform") || "";
15410
+ rafTween(
15411
+ w,
15412
+ duration,
15413
+ ease,
15414
+ (eased) => {
15415
+ const t = 1 - eased;
15416
+ group.setAttribute(
15417
+ "transform",
15418
+ `translate(${dx * t} ${dy * t}) ${base}`.trim()
15419
+ );
15420
+ },
15421
+ () => {
15422
+ group.setAttribute("transform", base);
15423
+ }
15424
+ );
15425
+ }
15426
+ } else if (!old) {
15427
+ fadeIn(w, group, duration, ease);
15428
+ }
15429
+ }
15430
+ if (countUp && old && isFinite(old.val)) {
15431
+ const newVal = parseFloat(group.getAttribute("data:dlVal") || "");
15432
+ if (isFinite(newVal) && Math.abs(newVal - old.val) > 1e-9) {
15433
+ const from = old.val;
15434
+ const dec = Math.max(decimalsOf(from), decimalsOf(newVal));
15435
+ const realIndex = parseInt(key, 10);
15436
+ const j = parseInt(group.getAttribute("data:dlJ") || "", 10);
15437
+ const format = (v) => {
15438
+ const rounded = Number(v.toFixed(dec));
15439
+ let out = rounded;
15440
+ if (typeof formatter === "function") {
15441
+ try {
15442
+ out = formatter(rounded, __spreadProps(__spreadValues({}, w), {
15443
+ seriesIndex: realIndex,
15444
+ dataPointIndex: isFinite(j) ? j : 0,
15445
+ w
15446
+ }));
15447
+ } catch (_) {
15448
+ out = rounded;
15449
+ }
15450
+ }
15451
+ return String(out);
15452
+ };
15453
+ rafTween(
15454
+ w,
15455
+ duration,
15456
+ ease,
15457
+ (eased) => {
15458
+ writeLabel(textEl, format(from + (newVal - from) * eased));
15459
+ },
15460
+ () => {
15461
+ writeLabel(textEl, format(newVal));
15462
+ }
15463
+ );
15464
+ }
15465
+ }
15466
+ });
15467
+ } catch (_) {
15468
+ }
15469
+ }
15249
15470
  class Series {
15250
15471
  /**
15251
15472
  * @param {import('../types/internal').ChartStateW} w
@@ -15619,6 +15840,7 @@ class Series {
15619
15840
  const w = this.w;
15620
15841
  captureStreamFrame(w);
15621
15842
  captureAxisChrome(w);
15843
+ captureDataLabels(w);
15622
15844
  if (!w.globals.axisCharts) {
15623
15845
  w.globals.previousPaths = w.seriesData.series;
15624
15846
  return;
@@ -19459,7 +19681,7 @@ class Data {
19459
19681
  * @param {any[]} ser
19460
19682
  */
19461
19683
  parseData(ser) {
19462
- var _a, _b, _c, _d, _e, _f;
19684
+ var _a, _b, _c, _d, _e, _f, _g;
19463
19685
  const w = this.w;
19464
19686
  const cnf = w.config;
19465
19687
  const gl = w.globals;
@@ -19485,8 +19707,11 @@ class Data {
19485
19707
  gl.dataReducerRawMaxX = rawMaxX;
19486
19708
  }
19487
19709
  }
19488
- cnf.series = ser;
19489
19710
  if (gl.dataReducerRawSeries && ((_f = cnf.chart.dataReducer) == null ? void 0 : _f.enabled)) {
19711
+ ser = ser.map((s) => __spreadValues({}, s));
19712
+ }
19713
+ cnf.series = ser;
19714
+ if (gl.dataReducerRawSeries && ((_g = cnf.chart.dataReducer) == null ? void 0 : _g.enabled)) {
19490
19715
  const stash = gl.dataReducerRawSeries;
19491
19716
  gl.initialSeries = ser.map((s, i) => {
19492
19717
  var _a2, _b2, _c2;
@@ -21127,12 +21352,14 @@ class Labels {
21127
21352
  w
21128
21353
  });
21129
21354
  if (tooltipEl) {
21355
+ const arrowEl = tooltipEl.querySelector(".apexcharts-tooltip-arrow");
21130
21356
  if (typeof customTooltip === "string" || typeof customTooltip === "number") {
21131
21357
  tooltipEl.innerHTML = String(customTooltip);
21132
21358
  } else if (customTooltip instanceof Element || typeof customTooltip.nodeName === "string") {
21133
21359
  tooltipEl.innerHTML = "";
21134
21360
  tooltipEl.appendChild(customTooltip.cloneNode(true));
21135
21361
  }
21362
+ if (arrowEl) tooltipEl.appendChild(arrowEl);
21136
21363
  }
21137
21364
  }
21138
21365
  }
@@ -21985,33 +22212,107 @@ class Intersect {
21985
22212
  var _a, _b;
21986
22213
  const ttCtx = this.ttCtx;
21987
22214
  const w = this.w;
21988
- if (e.target.classList.contains(`apexcharts-${type}-rect`)) {
21989
- const i = this.getAttr(e, "i");
21990
- const j = this.getAttr(e, "j");
21991
- const cx = this.getAttr(e, "cx");
21992
- const cy = this.getAttr(e, "cy");
21993
- const width = this.getAttr(e, "width");
21994
- const height = this.getAttr(e, "height");
21995
- ttCtx.tooltipLabels.drawSeriesTexts({
21996
- ttItems: opt.ttItems,
21997
- i,
21998
- j,
21999
- shared: false,
22000
- e
22001
- });
22002
- w.interact.capturedSeriesIndex = i;
22003
- w.interact.capturedDataPointIndex = j;
22004
- x = cx + ttCtx.tooltipRect.ttWidth / 2 + width;
22005
- y = cy + ttCtx.tooltipRect.ttHeight / 2 - height / 2;
22006
- ttCtx.tooltipPosition.moveXCrosshairs(cx + width / 2);
22007
- if (x > w.layout.gridWidth / 2) {
22008
- x = cx - ttCtx.tooltipRect.ttWidth / 2 + width;
22009
- }
22010
- if (ttCtx.w.config.tooltip.followCursor) {
22011
- const seriesBound = w.dom.elWrap.getBoundingClientRect();
22012
- x = ((_a = w.interact.clientX) != null ? _a : 0) - seriesBound.left - (x > w.layout.gridWidth / 2 ? ttCtx.tooltipRect.ttWidth : 0);
22013
- y = ((_b = w.interact.clientY) != null ? _b : 0) - seriesBound.top - (y > w.layout.gridHeight / 2 ? ttCtx.tooltipRect.ttHeight : 0);
22215
+ const renderer = w.globals.activeRenderer;
22216
+ const canvasCells = type === "heatmap" && renderer && renderer.kind === "canvas" && typeof renderer.hitTest === "function";
22217
+ let i, j, cx, cy, width, height;
22218
+ if (canvasCells) {
22219
+ const seriesBound = opt.elGrid.getBoundingClientRect();
22220
+ const clientX = e.type === "touchmove" ? e.touches[0].clientX : e.clientX;
22221
+ const clientY = e.type === "touchmove" ? e.touches[0].clientY : e.clientY;
22222
+ const hit = renderer.hitTest(
22223
+ clientX - seriesBound.left,
22224
+ clientY - seriesBound.top
22225
+ );
22226
+ if (!hit) {
22227
+ return { x, y, noHit: true };
22228
+ }
22229
+ i = hit.seriesIndex;
22230
+ j = hit.dataPointIndex;
22231
+ cx = hit.x;
22232
+ cy = hit.y;
22233
+ width = hit.width;
22234
+ height = hit.height;
22235
+ } else if (e.target.classList.contains(`apexcharts-${type}-rect`)) {
22236
+ i = this.getAttr(e, "i");
22237
+ j = this.getAttr(e, "j");
22238
+ cx = this.getAttr(e, "cx");
22239
+ cy = this.getAttr(e, "cy");
22240
+ width = this.getAttr(e, "width");
22241
+ height = this.getAttr(e, "height");
22242
+ } else {
22243
+ return { x, y };
22244
+ }
22245
+ ttCtx.tooltipLabels.drawSeriesTexts({
22246
+ ttItems: opt.ttItems,
22247
+ i,
22248
+ j,
22249
+ shared: false,
22250
+ e
22251
+ });
22252
+ w.interact.capturedSeriesIndex = i;
22253
+ w.interact.capturedDataPointIndex = j;
22254
+ ttCtx.tooltipPosition.moveXCrosshairs(cx + width / 2);
22255
+ const tooltipEl = ttCtx.getElTooltip();
22256
+ if (type === "heatmap" && w.config.tooltip.arrow && !w.config.tooltip.followCursor && tooltipEl) {
22257
+ const elGridRect = opt.elGrid.getBoundingClientRect();
22258
+ const elWrapRect = w.dom.elWrap.getBoundingClientRect();
22259
+ const gridOffsetXInElWrap = elGridRect.left - elWrapRect.left;
22260
+ let clLeft, clTop, clRight, clBottom;
22261
+ if (canvasCells) {
22262
+ clLeft = cx;
22263
+ clTop = cy;
22264
+ clRight = cx + width;
22265
+ clBottom = cy + height;
22266
+ } else {
22267
+ const r = e.target.getBoundingClientRect();
22268
+ clLeft = r.left - elGridRect.left;
22269
+ clTop = r.top - elGridRect.top;
22270
+ clRight = r.right - elGridRect.left;
22271
+ clBottom = r.bottom - elGridRect.top;
22272
+ }
22273
+ const ttW = ttCtx.tooltipRect.ttWidth || 0;
22274
+ const ttH = ttCtx.tooltipRect.ttHeight || 0;
22275
+ const ARROW_TIP_OVERHANG = 7;
22276
+ const cellCenterXInElWrap = (clLeft + clRight) / 2 + gridOffsetXInElWrap;
22277
+ const cellTopInElWrap = clTop + w.layout.translateY;
22278
+ const cellBottomInElWrap = clBottom + w.layout.translateY;
22279
+ const gridTop = w.layout.translateY;
22280
+ const gridBottom = w.layout.translateY + w.layout.gridHeight;
22281
+ const gridLeft = gridOffsetXInElWrap;
22282
+ const gridRight = gridOffsetXInElWrap + w.layout.gridWidth;
22283
+ let placement = "top";
22284
+ let finalY = cellTopInElWrap - ttH - ARROW_TIP_OVERHANG;
22285
+ if (finalY < gridTop) {
22286
+ const belowTop = cellBottomInElWrap + ARROW_TIP_OVERHANG;
22287
+ if (belowTop + ttH <= gridBottom) {
22288
+ placement = "bottom";
22289
+ finalY = belowTop;
22290
+ } else {
22291
+ finalY = gridTop;
22292
+ }
22014
22293
  }
22294
+ let finalX = cellCenterXInElWrap - ttW / 2;
22295
+ if (finalX < gridLeft) finalX = gridLeft;
22296
+ if (finalX + ttW > gridRight) finalX = gridRight - ttW;
22297
+ const arrowX = Math.max(10, Math.min(ttW - 10, cellCenterXInElWrap - finalX));
22298
+ ttCtx.tooltipPosition.applyTooltipPosition(tooltipEl, {
22299
+ x: finalX,
22300
+ y: finalY,
22301
+ placement,
22302
+ arrowY: null,
22303
+ arrowX
22304
+ });
22305
+ return { x: finalX, y: finalY, positioned: true };
22306
+ }
22307
+ x = cx + ttCtx.tooltipRect.ttWidth / 2 + width;
22308
+ y = cy + ttCtx.tooltipRect.ttHeight / 2 - height / 2;
22309
+ if (x > w.layout.gridWidth / 2) {
22310
+ x = cx - ttCtx.tooltipRect.ttWidth / 2 + width;
22311
+ }
22312
+ if (ttCtx.w.config.tooltip.followCursor) {
22313
+ const seriesBound = w.dom.elWrap.getBoundingClientRect();
22314
+ x = ((_a = w.interact.clientX) != null ? _a : 0) - seriesBound.left - (x > w.layout.gridWidth / 2 ? ttCtx.tooltipRect.ttWidth : 0);
22315
+ y = ((_b = w.interact.clientY) != null ? _b : 0) - seriesBound.top - (y > w.layout.gridHeight / 2 ? ttCtx.tooltipRect.ttHeight : 0);
22015
22316
  }
22016
22317
  return {
22017
22318
  x,
@@ -22650,7 +22951,7 @@ class Tooltip {
22650
22951
  this.tConfig.style.background
22651
22952
  );
22652
22953
  }
22653
- const isSharedMulti = this.tConfig.shared && w.config.series.length > 1 && !w.globals.isBarHorizontal;
22954
+ const isSharedMulti = this.tConfig.shared && w.config.series.length > 1 && !w.globals.isBarHorizontal && w.config.chart.type !== "heatmap";
22654
22955
  const shouldDrawArrow = this.tConfig.arrow && !this.tConfig.followCursor && !this.tConfig.fixed.enabled && !isSharedMulti && !this.tConfig.fillSeriesColor && w.globals.axisCharts;
22655
22956
  if (shouldDrawArrow) {
22656
22957
  const arrowEl = BrowserAPIs.createElementNS(
@@ -22827,6 +23128,8 @@ class Tooltip {
22827
23128
  this.addPathsEventListeners([hoverArea], seriesHoverParams);
22828
23129
  } else if (commonBar && !w.globals.comboCharts || chartWithmarkers && this.showOnIntersect) {
22829
23130
  this.addDatapointEventsListeners(seriesHoverParams);
23131
+ } else if (type === "heatmap" && w.globals.activeRenderer && w.globals.activeRenderer.kind === "canvas") {
23132
+ this.addPathsEventListeners([hoverArea], seriesHoverParams);
22830
23133
  } else if (!w.globals.axisCharts || type === "heatmap" || type === "treemap") {
22831
23134
  const seriesAll = w.dom.baseEl.querySelectorAll(".apexcharts-series");
22832
23135
  this.addPathsEventListeners(seriesAll, seriesHoverParams);
@@ -23076,10 +23379,16 @@ class Tooltip {
23076
23379
  y,
23077
23380
  type: w.config.chart.type
23078
23381
  });
23382
+ if (markerXY.noHit) {
23383
+ this.handleMouseOut(opt);
23384
+ return;
23385
+ }
23079
23386
  x = markerXY.x;
23080
23387
  y = markerXY.y;
23081
- tooltipEl.style.left = x + "px";
23082
- tooltipEl.style.top = y + "px";
23388
+ if (!markerXY.positioned) {
23389
+ tooltipEl.style.left = x + "px";
23390
+ tooltipEl.style.top = y + "px";
23391
+ }
23083
23392
  } else {
23084
23393
  if (this.tooltipUtil.hasBars()) {
23085
23394
  this.intersect.handleBarTooltip({
@@ -25676,6 +25985,7 @@ const _ApexCharts = class _ApexCharts {
25676
25985
  var _a;
25677
25986
  (_a = this.morphTypeChange) == null ? void 0 : _a.applyChromeFade();
25678
25987
  applyAxisTransition(this.w);
25988
+ applyDataLabelTransition(this.w);
25679
25989
  if (typeof this.w.config.chart.events.updated === "function") {
25680
25990
  this.w.config.chart.events.updated(this, this.w);
25681
25991
  }
@@ -34930,6 +35240,30 @@ class CanvasMarkerRef {
34930
35240
  return NOOP_RUNNER;
34931
35241
  }
34932
35242
  }
35243
+ const SHARED_RECT_REF = {
35244
+ __isCanvasMark: true,
35245
+ node: SHARED_MARKER_NODE,
35246
+ /** @returns {any} */
35247
+ attr() {
35248
+ return SHARED_RECT_REF;
35249
+ },
35250
+ add() {
35251
+ return SHARED_RECT_REF;
35252
+ },
35253
+ addTo() {
35254
+ return SHARED_RECT_REF;
35255
+ },
35256
+ remove() {
35257
+ return SHARED_RECT_REF;
35258
+ },
35259
+ /** @returns {any} */
35260
+ css() {
35261
+ return SHARED_RECT_REF;
35262
+ },
35263
+ animate() {
35264
+ return NOOP_RUNNER;
35265
+ }
35266
+ };
34933
35267
  class CanvasMark {
34934
35268
  /** @param {any} cmd */
34935
35269
  constructor(cmd) {
@@ -35057,6 +35391,16 @@ class CanvasGraphics {
35057
35391
  this._msi = new Int32Array(16);
35058
35392
  this._mn = 0;
35059
35393
  this._mcap = 16;
35394
+ this._crx = new Float64Array(16);
35395
+ this._cry = new Float64Array(16);
35396
+ this._crw = new Float64Array(16);
35397
+ this._crh = new Float64Array(16);
35398
+ this._crstyle = new Int32Array(16);
35399
+ this._crsi = new Int32Array(16);
35400
+ this._crdi = new Int32Array(16);
35401
+ this._crn = 0;
35402
+ this._crcap = 16;
35403
+ this._cellRadius = 0;
35060
35404
  this._styles = [];
35061
35405
  this._styleMap = /* @__PURE__ */ new Map();
35062
35406
  this._lf = NEVER;
@@ -35069,6 +35413,12 @@ class CanvasGraphics {
35069
35413
  this._lofFill = NEVER;
35070
35414
  this._lofBase = -1;
35071
35415
  this._lofId = -1;
35416
+ this._rlf = NEVER;
35417
+ this._rls = NEVER;
35418
+ this._rlsw = NEVER;
35419
+ this._rlfo = NEVER;
35420
+ this._rlso = NEVER;
35421
+ this._rlid = -1;
35072
35422
  }
35073
35423
  _resetStyleCache() {
35074
35424
  this._lf = NEVER;
@@ -35081,6 +35431,12 @@ class CanvasGraphics {
35081
35431
  this._lofFill = NEVER;
35082
35432
  this._lofBase = -1;
35083
35433
  this._lofId = -1;
35434
+ this._rlf = NEVER;
35435
+ this._rls = NEVER;
35436
+ this._rlsw = NEVER;
35437
+ this._rlfo = NEVER;
35438
+ this._rlso = NEVER;
35439
+ this._rlid = -1;
35084
35440
  }
35085
35441
  /** Start a fresh scene (columnar marker store + object-command list). */
35086
35442
  reset() {
@@ -35097,6 +35453,46 @@ class CanvasGraphics {
35097
35453
  }
35098
35454
  cap = Math.ceil(cap * 1.15) + 16;
35099
35455
  if (cap > this._mcap) this._allocMarkers(cap);
35456
+ this._crn = 0;
35457
+ this._cellRadius = 0;
35458
+ if (cap > this._crcap) this._allocRects(cap);
35459
+ }
35460
+ /** @param {number} cap */
35461
+ _allocRects(cap) {
35462
+ this._crcap = cap;
35463
+ this._crx = new Float64Array(cap);
35464
+ this._cry = new Float64Array(cap);
35465
+ this._crw = new Float64Array(cap);
35466
+ this._crh = new Float64Array(cap);
35467
+ this._crstyle = new Int32Array(cap);
35468
+ this._crsi = new Int32Array(cap);
35469
+ this._crdi = new Int32Array(cap);
35470
+ }
35471
+ /** Grow the rect columns (rare: capacity estimate was low). */
35472
+ _growRects() {
35473
+ const cap = this._crcap * 2;
35474
+ const nx = new Float64Array(cap);
35475
+ nx.set(this._crx);
35476
+ this._crx = nx;
35477
+ const ny = new Float64Array(cap);
35478
+ ny.set(this._cry);
35479
+ this._cry = ny;
35480
+ const nw = new Float64Array(cap);
35481
+ nw.set(this._crw);
35482
+ this._crw = nw;
35483
+ const nh = new Float64Array(cap);
35484
+ nh.set(this._crh);
35485
+ this._crh = nh;
35486
+ const nst = new Int32Array(cap);
35487
+ nst.set(this._crstyle);
35488
+ this._crstyle = nst;
35489
+ const nsi = new Int32Array(cap);
35490
+ nsi.set(this._crsi);
35491
+ this._crsi = nsi;
35492
+ const ndi = new Int32Array(cap);
35493
+ ndi.set(this._crdi);
35494
+ this._crdi = ndi;
35495
+ this._crcap = cap;
35100
35496
  }
35101
35497
  /** @param {number} cap */
35102
35498
  _allocMarkers(cap) {
@@ -35206,6 +35602,65 @@ class CanvasGraphics {
35206
35602
  shapeName(id) {
35207
35603
  return SHAPE_NAME[id] || "circle";
35208
35604
  }
35605
+ // ── columnar rect cell (heatmap): parallel unboxed arrays, no per-cell object ──
35606
+ /**
35607
+ * Record a heatmap-style cell (a filled, optionally stroked rect). Geometry
35608
+ * and style are captured up front into the columns; the returned handle is a
35609
+ * shared no-op (the emit site sets nothing back on it in canvas mode).
35610
+ * @param {number} x @param {number} y @param {number} w @param {number} h
35611
+ * @param {any} opts {fill, fillOpacity, stroke, strokeWidth, radius, seriesIndex, dataPointIndex}
35612
+ * @returns {any}
35613
+ */
35614
+ drawRectCell(x, y, w, h, opts = {}) {
35615
+ const styleId = this._rectStyleId(opts);
35616
+ if (this._crn >= this._crcap) this._growRects();
35617
+ const i = this._crn++;
35618
+ this._crx[i] = x || 0;
35619
+ this._cry[i] = y || 0;
35620
+ this._crw[i] = w > 0 ? w : 0;
35621
+ this._crh[i] = h > 0 ? h : 0;
35622
+ this._crstyle[i] = styleId;
35623
+ this._crsi[i] = opts.seriesIndex == null ? -1 : opts.seriesIndex;
35624
+ this._crdi[i] = opts.dataPointIndex == null ? -1 : opts.dataPointIndex;
35625
+ if (opts.radius) this._cellRadius = opts.radius;
35626
+ return SHARED_RECT_REF;
35627
+ }
35628
+ /**
35629
+ * Resolve (and dedupe) a rect-cell style → shared-palette id. A last-style
35630
+ * cache keeps the Map/string work off the path for runs of same-style cells.
35631
+ * @param {any} opts
35632
+ * @returns {number}
35633
+ */
35634
+ _rectStyleId(opts) {
35635
+ const fill = opts.fill;
35636
+ const stroke = opts.stroke;
35637
+ const sw = opts.strokeWidth;
35638
+ const fo = opts.fillOpacity;
35639
+ const so = opts.strokeOpacity;
35640
+ if (fill === this._rlf && stroke === this._rls && sw === this._rlsw && fo === this._rlfo && so === this._rlso) {
35641
+ return this._rlid;
35642
+ }
35643
+ const id = this._internStyle(fill, stroke, sw, 0, fo, so);
35644
+ this._rlf = fill;
35645
+ this._rls = stroke;
35646
+ this._rlsw = sw;
35647
+ this._rlfo = fo;
35648
+ this._rlso = so;
35649
+ this._rlid = id;
35650
+ return id;
35651
+ }
35652
+ /** @returns {number} number of recorded rect cells */
35653
+ rectCount() {
35654
+ return this._crn;
35655
+ }
35656
+ /** @param {number} i @returns {any} the style object for a rect cell */
35657
+ rectStyle(i) {
35658
+ return this._styles[this._crstyle[i]];
35659
+ }
35660
+ /** @param {number} i @returns {number} series (realIndex) of a cell, -1 if none */
35661
+ rectSeries(i) {
35662
+ return this._crsi[i];
35663
+ }
35209
35664
  /**
35210
35665
  * @param {string} tag
35211
35666
  * @param {number} z
@@ -35521,9 +35976,97 @@ class CanvasCompositor {
35521
35976
  this._paintOne(ctx, c);
35522
35977
  }
35523
35978
  }
35979
+ this._paintRects(ctx, shim2);
35524
35980
  this._paintMarkers(ctx, shim2);
35525
35981
  this._alpha = 1;
35526
35982
  }
35983
+ /**
35984
+ * Paint the columnar rect cells (heatmap) as STYLE BATCHES: one fill/stroke
35985
+ * state application per run of consecutive same-style cells, then a fast
35986
+ * fillRect (or a roundRect path when the shared corner radius is non-zero)
35987
+ * per cell. Clipped to the plot rect so cells never bleed into the canvas
35988
+ * margin (mirrors the SVG gridRectMask). Per-cell globalAlpha carries the
35989
+ * hover/legend dim multiplier when a dim spec is active.
35990
+ * @param {any} ctx
35991
+ * @param {any} shim
35992
+ */
35993
+ _paintRects(ctx, shim2) {
35994
+ const n = shim2.rectCount ? shim2.rectCount() : 0;
35995
+ if (!n) return;
35996
+ const rx = shim2._crx;
35997
+ const ry = shim2._cry;
35998
+ const rw = shim2._crw;
35999
+ const rh = shim2._crh;
36000
+ const rstyle = shim2._crstyle;
36001
+ const radius = shim2._cellRadius || 0;
36002
+ const cx = (
36003
+ /** @type {any} */
36004
+ ctx
36005
+ );
36006
+ const useRound = radius > 0 && typeof cx.roundRect === "function";
36007
+ const dimming = !!this._dim;
36008
+ const gw = Math.max(0, this.w.layout.gridWidth || 0);
36009
+ const gh = Math.max(0, this.w.layout.gridHeight || 0);
36010
+ ctx.save();
36011
+ ctx.beginPath();
36012
+ ctx.rect(0, 0, gw, gh);
36013
+ ctx.clip();
36014
+ let i = 0;
36015
+ while (i < n) {
36016
+ const styleId = rstyle[i];
36017
+ const style = shim2.rectStyle(i);
36018
+ if (!style) {
36019
+ i++;
36020
+ continue;
36021
+ }
36022
+ const fill = style.fill;
36023
+ const doFill = fill && fill !== "none" && !(typeof fill === "string" && fill.indexOf("url(") === 0);
36024
+ const stroke = style.stroke;
36025
+ const sw = style.strokeWidth == null ? 0 : Number(style.strokeWidth);
36026
+ const doStroke = stroke && stroke !== "none" && sw > 0 && !(typeof stroke === "string" && stroke.indexOf("url(") === 0);
36027
+ if (doFill) ctx.fillStyle = fill;
36028
+ if (doStroke) {
36029
+ ctx.strokeStyle = stroke;
36030
+ ctx.lineWidth = sw;
36031
+ ctx.setLineDash([]);
36032
+ }
36033
+ const baseFillA = style.fillOpacity == null ? 1 : Number(style.fillOpacity);
36034
+ const baseStrokeA = style.strokeOpacity == null ? 1 : Number(style.strokeOpacity);
36035
+ let j = i;
36036
+ while (j < n && rstyle[j] === styleId) {
36037
+ const w = rw[j];
36038
+ const h = rh[j];
36039
+ if (w > 0 && h > 0) {
36040
+ const f = dimming ? this._seriesAlpha(shim2.rectSeries(j)) : 1;
36041
+ if (useRound) {
36042
+ ctx.beginPath();
36043
+ cx.roundRect(rx[j], ry[j], w, h, radius);
36044
+ if (doFill) {
36045
+ ctx.globalAlpha = baseFillA * f;
36046
+ ctx.fill();
36047
+ }
36048
+ if (doStroke) {
36049
+ ctx.globalAlpha = baseStrokeA * f;
36050
+ ctx.stroke();
36051
+ }
36052
+ } else {
36053
+ if (doFill) {
36054
+ ctx.globalAlpha = baseFillA * f;
36055
+ ctx.fillRect(rx[j], ry[j], w, h);
36056
+ }
36057
+ if (doStroke) {
36058
+ ctx.globalAlpha = baseStrokeA * f;
36059
+ ctx.strokeRect(rx[j], ry[j], w, h);
36060
+ }
36061
+ }
36062
+ }
36063
+ j++;
36064
+ }
36065
+ i = j;
36066
+ }
36067
+ ctx.globalAlpha = 1;
36068
+ ctx.restore();
36069
+ }
35527
36070
  /**
35528
36071
  * Reusable unit Path2D for a (shape, size): the shape's geometry built at the
35529
36072
  * origin once, then translated per marker via setTransform. Returns null when
@@ -35874,6 +36417,16 @@ class CanvasRenderer {
35874
36417
  this._g.drawRect(...args)
35875
36418
  );
35876
36419
  }
36420
+ /**
36421
+ * Columnar heatmap-cell rect (dense same-shape rects): recorded into typed
36422
+ * arrays, painted as style batches. Distinct from drawRect (object command)
36423
+ * so 100k cells don't allocate 100k retained commands.
36424
+ * @param {number} x @param {number} y @param {number} w @param {number} h
36425
+ * @param {any} opts
36426
+ */
36427
+ drawRectCell(x, y, w, h, opts) {
36428
+ return this._g.drawRectCell(x, y, w, h, opts);
36429
+ }
35877
36430
  /**
35878
36431
  * @param {number} r
35879
36432
  * @param {any} attrs
@@ -35903,14 +36456,44 @@ class CanvasRenderer {
35903
36456
  return feature === "solidFill" || feature === "dashArray";
35904
36457
  }
35905
36458
  // ── interaction ──
35906
- // Shared tooltip/zoom/click resolve via coordinate lookup (pointsArray), so
35907
- // there is no per-mark hit surface to query; hitTest stays a no-op unless a
35908
- // future per-point feature needs it.
35909
- /**
35910
- * @param {number} _px
35911
- * @param {number} _py
35912
- */
35913
- hitTest(_px, _py) {
36459
+ // Line/area/bar/scatter tooltips resolve via coordinate lookup (pointsArray),
36460
+ // so those need no per-mark query. Heatmap cells, however, are hovered by
36461
+ // point (the SVG path hit-tests the <rect> under the cursor); with cells on
36462
+ // canvas there is no node, so hitTest resolves the columnar rect store.
36463
+ /**
36464
+ * Find the cell under a plot-local point (0,0 = plot origin, the same space
36465
+ * as the recorded cell geometry). Reverse scan so a later-painted cell wins
36466
+ * when cells overlap (continuous-x edges). A linear scan stays well under a
36467
+ * frame even at 100k cells (~100k integer compares). Returns the cell's
36468
+ * series/dataPoint index plus its geometry for tooltip positioning, or null
36469
+ * when the point is off every cell.
36470
+ * @param {number} px
36471
+ * @param {number} py
36472
+ * @returns {({seriesIndex:number,dataPointIndex:number,x:number,y:number,width:number,height:number})|null}
36473
+ */
36474
+ hitTest(px, py) {
36475
+ const g = this._g;
36476
+ const n = g.rectCount ? g.rectCount() : 0;
36477
+ if (!n) return null;
36478
+ const rx = g._crx;
36479
+ const ry = g._cry;
36480
+ const rw = g._crw;
36481
+ const rh = g._crh;
36482
+ for (let k = n - 1; k >= 0; k--) {
36483
+ const w = rw[k];
36484
+ const h = rh[k];
36485
+ if (w <= 0 || h <= 0) continue;
36486
+ if (px >= rx[k] && px < rx[k] + w && py >= ry[k] && py < ry[k] + h) {
36487
+ return {
36488
+ seriesIndex: g._crsi[k],
36489
+ dataPointIndex: g._crdi[k],
36490
+ x: rx[k],
36491
+ y: ry[k],
36492
+ width: w,
36493
+ height: h
36494
+ };
36495
+ }
36496
+ }
35914
36497
  return null;
35915
36498
  }
35916
36499
  /**
@@ -39771,6 +40354,7 @@ class BarDataLabels {
39771
40354
  barWidth,
39772
40355
  dataLabelsConfig
39773
40356
  }) {
40357
+ var _a, _b;
39774
40358
  const w = this.w;
39775
40359
  let rotate = "rotate(0)";
39776
40360
  if (w.config.plotOptions.bar.dataLabels.orientation === "vertical")
@@ -39785,6 +40369,17 @@ class BarDataLabels {
39785
40369
  class: "apexcharts-data-labels",
39786
40370
  transform: rotate
39787
40371
  });
40372
+ const dlCfg = w.config.dataLabels;
40373
+ if (((_a = dlCfg.animate) == null ? void 0 : _a.enabled) || ((_b = dlCfg.countUp) == null ? void 0 : _b.enabled)) {
40374
+ elDataLabelsWrap.node.setAttribute(
40375
+ "data:dlKey",
40376
+ `${i}::${datumKey(w, i, j)}`
40377
+ );
40378
+ elDataLabelsWrap.node.setAttribute("data:dlJ", String(j));
40379
+ if (typeof val === "number" && isFinite(val)) {
40380
+ elDataLabelsWrap.node.setAttribute("data:dlVal", String(val));
40381
+ }
40382
+ }
39788
40383
  let text = "";
39789
40384
  if (typeof val !== "undefined") {
39790
40385
  text = formatter(val, __spreadProps(__spreadValues({}, w), {
@@ -40742,6 +41337,7 @@ class Bar {
40742
41337
  this.pathArr = [];
40743
41338
  this._prevKeyed = null;
40744
41339
  this._ltCache = null;
41340
+ this._layoutShiftCache = null;
40745
41341
  this.series = [];
40746
41342
  this.elSeries = null;
40747
41343
  this.visibleI = 0;
@@ -40770,7 +41366,7 @@ class Bar {
40770
41366
  * @return {Element} element which is supplied to parent chart draw method for appending
40771
41367
  **/
40772
41368
  draw(series, seriesIndex) {
40773
- var _a, _b;
41369
+ var _a, _b, _c;
40774
41370
  const w = this.w;
40775
41371
  const graphics = new Graphics(this.w);
40776
41372
  const coreUtils = new CoreUtils(this.w);
@@ -40844,8 +41440,10 @@ class Bar {
40844
41440
  el: elDataLabelsWrap.node,
40845
41441
  // On a layout-changing update the labels must stay hidden through the
40846
41442
  // reflow morph (the updateOptions flow otherwise reveals them at
40847
- // frame 0, where they float over sliding bars).
40848
- holdUntilComplete: this.isLengthTransition(realIndex)
41443
+ // frame 0, where they float over sliding bars). When dataLabels.animate
41444
+ // is on the labels instead RIDE the morph (see DataLabelTransition), so
41445
+ // keep them visible: holding would hide the very motion we want to show.
41446
+ holdUntilComplete: !((_a = w.config.dataLabels.animate) == null ? void 0 : _a.enabled) && this.isLengthTransition(realIndex)
40849
41447
  });
40850
41448
  elDataLabelsWrap.node.classList.add("apexcharts-element-hidden");
40851
41449
  const elGoalsMarkers = graphics.group({
@@ -40898,9 +41496,9 @@ class Bar {
40898
41496
  j,
40899
41497
  realIndex
40900
41498
  );
40901
- if (this.isFunnel && !this.isPyramid && this.barOptions.isFunnel3d && ((_a = w.config.plotOptions.funnel) == null ? void 0 : _a.shape) !== "trapezoid" && this.pathArr.length && j > 0) {
41499
+ if (this.isFunnel && !this.isPyramid && this.barOptions.isFunnel3d && ((_b = w.config.plotOptions.funnel) == null ? void 0 : _b.shape) !== "trapezoid" && this.pathArr.length && j > 0) {
40902
41500
  const barShadow = this.barHelpers.drawBarShadow({
40903
- color: typeof pathFill.color === "string" && ((_b = pathFill.color) == null ? void 0 : _b.indexOf("url")) === -1 ? pathFill.color : Utils$1.hexToRgba(w.globals.colors[i]),
41501
+ color: typeof pathFill.color === "string" && ((_c = pathFill.color) == null ? void 0 : _c.indexOf("url")) === -1 ? pathFill.color : Utils$1.hexToRgba(w.globals.colors[i]),
40904
41502
  prevPaths: this.pathArr[this.pathArr.length - 1],
40905
41503
  currPaths: paths,
40906
41504
  realIndex,
@@ -41072,7 +41670,7 @@ class Bar {
41072
41670
  }
41073
41671
  const animCfg = w.config.chart.animations;
41074
41672
  const gradCfg = animCfg.animateGradually;
41075
- const staggerEnabled = gradCfg && gradCfg.enabled !== false && !(w.globals.dataChanged && this.isLengthTransition(realIndex));
41673
+ const staggerEnabled = gradCfg && gradCfg.enabled !== false && !(w.globals.dataChanged && this.isLayoutShift(realIndex));
41076
41674
  let delay = 0;
41077
41675
  if (staggerEnabled) {
41078
41676
  const totalBars = w.globals.dataPoints || 1;
@@ -41486,6 +42084,26 @@ class Bar {
41486
42084
  this._ltCache[realIndex] = result;
41487
42085
  return result;
41488
42086
  }
42087
+ /**
42088
+ * Whether this update moves survivors to new slots: a length change
42089
+ * (enter/exit, via isLengthTransition) OR a pure reorder (a "bar chart race"
42090
+ * swap, same datum set in a new order). Used to drop the per-bar stagger so
42091
+ * all bars slide on one shared clock, staying locked to the axis/data labels.
42092
+ * Broader than isLengthTransition, which is deliberately enter/exit-only
42093
+ * (exit ghosts / baseline enters must not fire on a plain reorder).
42094
+ * @param {number} realIndex
42095
+ */
42096
+ isLayoutShift(realIndex) {
42097
+ if (this.isLengthTransition(realIndex)) return true;
42098
+ if (!this._layoutShiftCache) this._layoutShiftCache = {};
42099
+ if (this._layoutShiftCache[realIndex] !== void 0) {
42100
+ return this._layoutShiftCache[realIndex];
42101
+ }
42102
+ const sj = seriesJoin(this.w, realIndex, true, true);
42103
+ const result = !!(sj && sj.join.changed);
42104
+ this._layoutShiftCache[realIndex] = result;
42105
+ return result;
42106
+ }
41489
42107
  /**
41490
42108
  * Resolve `pathFrom` for a bar on data update, joining old and new datums
41491
42109
  * by KEY (category label / x value) so survivors keep their identity across
@@ -43347,14 +43965,24 @@ class HeatMap {
43347
43965
  * @param {any[]} series
43348
43966
  */
43349
43967
  draw(series) {
43968
+ var _a, _b;
43350
43969
  const w = this.w;
43351
43970
  const graphics = new Graphics(this.w, this.ctx);
43971
+ const emit = seriesEmitter(this.ctx, graphics);
43972
+ const useCanvas = emit !== graphics && typeof emit.drawRectCell === "function";
43352
43973
  const ret = graphics.group({
43353
43974
  class: "apexcharts-heatmap"
43354
43975
  });
43355
43976
  ret.attr("clip-path", `url(#gridRectMask${w.globals.cuid})`);
43356
43977
  const xDivision = w.layout.gridWidth / w.globals.dataPoints;
43357
43978
  const yDivision = w.layout.gridHeight / w.seriesData.series.length;
43979
+ const isContinuousX = (w.config.xaxis.type === "numeric" || w.config.xaxis.type === "datetime") && w.axisFlags.isXNumeric && this.xRatio > 0;
43980
+ let binPx = xDivision;
43981
+ if (isContinuousX) {
43982
+ const diff = w.globals.minXDiff;
43983
+ binPx = Number.isFinite(diff) && diff > 0 ? diff / this.xRatio : xDivision;
43984
+ }
43985
+ const cellFillOpacity = Array.isArray(w.config.fill.opacity) ? (_a = w.config.fill.opacity[0]) != null ? _a : 1 : (_b = w.config.fill.opacity) != null ? _b : 1;
43358
43986
  let y1 = 0;
43359
43987
  let rev = false;
43360
43988
  this.negRange = this.helpers.checkColorRange();
@@ -43371,7 +43999,9 @@ class HeatMap {
43371
43999
  "data:realIndex": i
43372
44000
  });
43373
44001
  Series.addCollapsedClassToSeries(this.w, elSeries, i);
43374
- graphics.setupEventDelegation(elSeries, ".apexcharts-heatmap-rect");
44002
+ if (!useCanvas) {
44003
+ graphics.setupEventDelegation(elSeries, ".apexcharts-heatmap-rect");
44004
+ }
43375
44005
  if (w.config.chart.dropShadow.enabled) {
43376
44006
  const shadow = w.config.chart.dropShadow;
43377
44007
  const filters = new Filters(this.w);
@@ -43381,13 +44011,22 @@ class HeatMap {
43381
44011
  const shadeIntensity = w.config.plotOptions.heatmap.shadeIntensity;
43382
44012
  let j = 0;
43383
44013
  for (let dIndex = 0; dIndex < w.globals.dataPoints; dIndex++) {
43384
- if (w.seriesData.seriesX.length && !w.globals.allSeriesHasEqualX) {
44014
+ if (!isContinuousX && w.seriesData.seriesX.length && !w.globals.allSeriesHasEqualX) {
43385
44015
  if (w.globals.minX + w.globals.minXDiff * dIndex < w.seriesData.seriesX[i][j]) {
43386
44016
  x1 = x1 + xDivision;
43387
44017
  continue;
43388
44018
  }
43389
44019
  }
43390
44020
  if (j >= heatSeries[i].length) break;
44021
+ const cellW = isContinuousX ? binPx : xDivision;
44022
+ if (isContinuousX) {
44023
+ const xVal = w.seriesData.seriesX[i] ? w.seriesData.seriesX[i][j] : null;
44024
+ if (xVal == null || xVal !== xVal) {
44025
+ j++;
44026
+ continue;
44027
+ }
44028
+ x1 = (xVal - w.globals.minX) / this.xRatio - binPx / 2;
44029
+ }
43391
44030
  const heatColor = this.helpers.getShadeColor(
43392
44031
  w.config.chart.type,
43393
44032
  i,
@@ -43406,47 +44045,60 @@ class HeatMap {
43406
44045
  w.globals.hasNegs ? heatColorProps.percent < 0 ? 1 - (1 + heatColorProps.percent / 100) : shadeIntensity + heatColorProps.percent / 100 : heatColorProps.percent / 100
43407
44046
  ),
43408
44047
  patternID: Utils$1.randomId(),
43409
- width: w.config.fill.image.width ? w.config.fill.image.width : xDivision,
44048
+ width: w.config.fill.image.width ? w.config.fill.image.width : cellW,
43410
44049
  height: w.config.fill.image.height ? w.config.fill.image.height : yDivision
43411
44050
  });
43412
44051
  }
43413
44052
  const radius = this.rectRadius;
43414
- const rect = graphics.drawRect(x1, y1, xDivision, yDivision, radius);
43415
- rect.attr({
43416
- cx: x1,
43417
- cy: y1
43418
- });
43419
- rect.node.classList.add("apexcharts-heatmap-rect");
43420
- elSeries.add(rect);
43421
- rect.attr({
43422
- fill: color,
43423
- i,
43424
- index: i,
43425
- j,
43426
- val: series[i][j],
43427
- "stroke-width": this.strokeWidth,
43428
- stroke: w.config.plotOptions.heatmap.useFillColorAsStroke ? color : w.globals.stroke.colors[0],
43429
- color
43430
- });
43431
- if (w.config.chart.animations.enabled && !w.globals.dataChanged) {
43432
- let speed = 1;
43433
- if (!w.globals.resized) {
43434
- speed = w.config.chart.animations.speed;
43435
- }
43436
- this.animateHeatMap(rect, x1, y1, xDivision, yDivision, speed, i, j);
43437
- }
43438
- if (w.globals.dataChanged) {
43439
- let speed = 1;
43440
- if (this.dynamicAnim.enabled && w.globals.shouldAnimate) {
43441
- speed = this.dynamicAnim.speed;
43442
- let colorFrom = w.globals.previousPaths[i] && w.globals.previousPaths[i][j] && w.globals.previousPaths[i][j].color;
43443
- if (!colorFrom) colorFrom = "rgba(255, 255, 255, 0)";
43444
- this.animateHeatColor(
43445
- rect,
43446
- Utils$1.isColorHex(colorFrom) ? colorFrom : Utils$1.rgb2hex(colorFrom),
43447
- Utils$1.isColorHex(color) ? color : Utils$1.rgb2hex(color),
43448
- speed
43449
- );
44053
+ const stroke = w.config.plotOptions.heatmap.useFillColorAsStroke ? color : w.globals.stroke.colors[0];
44054
+ if (useCanvas) {
44055
+ emit.drawRectCell(x1, y1, cellW, yDivision, {
44056
+ fill: color,
44057
+ fillOpacity: cellFillOpacity,
44058
+ stroke,
44059
+ strokeWidth: this.strokeWidth,
44060
+ radius,
44061
+ seriesIndex: i,
44062
+ dataPointIndex: j
44063
+ });
44064
+ } else {
44065
+ const rect = graphics.drawRect(x1, y1, cellW, yDivision, radius);
44066
+ rect.attr({
44067
+ cx: x1,
44068
+ cy: y1
44069
+ });
44070
+ rect.node.classList.add("apexcharts-heatmap-rect");
44071
+ elSeries.add(rect);
44072
+ rect.attr({
44073
+ fill: color,
44074
+ i,
44075
+ index: i,
44076
+ j,
44077
+ val: series[i][j],
44078
+ "stroke-width": this.strokeWidth,
44079
+ stroke,
44080
+ color
44081
+ });
44082
+ if (w.config.chart.animations.enabled && !w.globals.dataChanged) {
44083
+ let speed = 1;
44084
+ if (!w.globals.resized) {
44085
+ speed = w.config.chart.animations.speed;
44086
+ }
44087
+ this.animateHeatMap(rect, x1, y1, cellW, yDivision, speed, i, j);
44088
+ }
44089
+ if (w.globals.dataChanged) {
44090
+ let speed = 1;
44091
+ if (this.dynamicAnim.enabled && w.globals.shouldAnimate) {
44092
+ speed = this.dynamicAnim.speed;
44093
+ let colorFrom = w.globals.previousPaths[i] && w.globals.previousPaths[i][j] && w.globals.previousPaths[i][j].color;
44094
+ if (!colorFrom) colorFrom = "rgba(255, 255, 255, 0)";
44095
+ this.animateHeatColor(
44096
+ rect,
44097
+ Utils$1.isColorHex(colorFrom) ? colorFrom : Utils$1.rgb2hex(colorFrom),
44098
+ Utils$1.isColorHex(color) ? color : Utils$1.rgb2hex(color),
44099
+ speed
44100
+ );
44101
+ }
43450
44102
  }
43451
44103
  }
43452
44104
  const formatter = w.config.dataLabels.formatter;
@@ -43458,7 +44110,7 @@ class HeatMap {
43458
44110
  });
43459
44111
  const dataLabels = this.helpers.calculateDataLabels({
43460
44112
  text: formattedText,
43461
- x: x1 + xDivision / 2,
44113
+ x: x1 + cellW / 2,
43462
44114
  y: y1 + yDivision / 2,
43463
44115
  i,
43464
44116
  j,
@@ -43468,7 +44120,7 @@ class HeatMap {
43468
44120
  if (dataLabels !== null) {
43469
44121
  elSeries.add(dataLabels);
43470
44122
  }
43471
- x1 = x1 + xDivision;
44123
+ if (!isContinuousX) x1 = x1 + xDivision;
43472
44124
  j++;
43473
44125
  }
43474
44126
  y1 = y1 + yDivision;