apexcharts 7.7.0 → 7.8.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 (165) hide show
  1. package/dist/apexcharts.common.js +1 -1
  2. package/dist/apexcharts.core.js +412 -86
  3. package/dist/apexcharts.core.min.js +2 -2
  4. package/dist/apexcharts.esm.js +1 -1
  5. package/dist/apexcharts.js +411 -85
  6. package/dist/apexcharts.min.js +2 -2
  7. package/dist/apexcharts.ssr.common.js +2 -2
  8. package/dist/apexcharts.ssr.esm.js +411 -85
  9. package/dist/area.common.js +1 -1
  10. package/dist/area.esm.js +1 -1
  11. package/dist/bar.common.js +1 -1
  12. package/dist/bar.esm.js +1 -1
  13. package/dist/bar.js +1 -1
  14. package/dist/boxPlot.common.js +1 -1
  15. package/dist/boxPlot.esm.js +1 -1
  16. package/dist/bubble.common.js +1 -1
  17. package/dist/bubble.esm.js +1 -1
  18. package/dist/candlestick.common.js +1 -1
  19. package/dist/candlestick.esm.js +1 -1
  20. package/dist/candlestick.js +1 -1
  21. package/dist/column.common.js +1 -1
  22. package/dist/column.esm.js +1 -1
  23. package/dist/core.common.js +2 -2
  24. package/dist/core.esm.js +412 -86
  25. package/dist/donut.common.js +1 -1
  26. package/dist/donut.esm.js +1 -1
  27. package/dist/dumbbell.common.js +1 -1
  28. package/dist/dumbbell.esm.js +1 -1
  29. package/dist/features/all.common.js +1 -1
  30. package/dist/features/all.esm.js +1 -1
  31. package/dist/features/annotations.common.js +1 -1
  32. package/dist/features/annotations.esm.js +1 -1
  33. package/dist/features/annotations.js +1 -1
  34. package/dist/features/context-menu.common.js +1 -1
  35. package/dist/features/context-menu.esm.js +1 -1
  36. package/dist/features/context-menu.js +1 -1
  37. package/dist/features/drilldown.common.js +1 -1
  38. package/dist/features/drilldown.esm.js +1 -1
  39. package/dist/features/drilldown.js +1 -1
  40. package/dist/features/dumbbell.common.js +1 -1
  41. package/dist/features/dumbbell.esm.js +1 -1
  42. package/dist/features/dumbbell.js +1 -1
  43. package/dist/features/exports.common.js +1 -1
  44. package/dist/features/exports.esm.js +1 -1
  45. package/dist/features/exports.js +1 -1
  46. package/dist/features/facet.common.js +1 -1
  47. package/dist/features/facet.esm.js +1 -1
  48. package/dist/features/facet.js +1 -1
  49. package/dist/features/history.common.js +1 -1
  50. package/dist/features/history.esm.js +1 -1
  51. package/dist/features/history.js +1 -1
  52. package/dist/features/ink.common.js +1 -1
  53. package/dist/features/ink.esm.js +1 -1
  54. package/dist/features/ink.js +1 -1
  55. package/dist/features/keyboard.common.js +1 -1
  56. package/dist/features/keyboard.esm.js +1 -1
  57. package/dist/features/keyboard.js +1 -1
  58. package/dist/features/legend.common.js +1 -1
  59. package/dist/features/legend.esm.js +1 -1
  60. package/dist/features/legend.js +1 -1
  61. package/dist/features/link.common.js +1 -1
  62. package/dist/features/link.esm.js +1 -1
  63. package/dist/features/link.js +1 -1
  64. package/dist/features/marks.common.js +1 -1
  65. package/dist/features/marks.esm.js +1 -1
  66. package/dist/features/marks.js +1 -1
  67. package/dist/features/measure.common.js +1 -1
  68. package/dist/features/measure.esm.js +1 -1
  69. package/dist/features/measure.js +1 -1
  70. package/dist/features/morph.common.js +1 -1
  71. package/dist/features/morph.esm.js +1 -1
  72. package/dist/features/morph.js +1 -1
  73. package/dist/features/perspectives.common.js +1 -1
  74. package/dist/features/perspectives.esm.js +1 -1
  75. package/dist/features/perspectives.js +1 -1
  76. package/dist/features/raincloud.common.js +1 -1
  77. package/dist/features/raincloud.esm.js +1 -1
  78. package/dist/features/raincloud.js +1 -1
  79. package/dist/features/renderer-canvas.common.js +1 -1
  80. package/dist/features/renderer-canvas.esm.js +1 -1
  81. package/dist/features/renderer-canvas.js +1 -1
  82. package/dist/features/stats.common.js +1 -1
  83. package/dist/features/stats.esm.js +1 -1
  84. package/dist/features/stats.js +1 -1
  85. package/dist/features/storyboard.common.js +1 -1
  86. package/dist/features/storyboard.esm.js +1 -1
  87. package/dist/features/storyboard.js +1 -1
  88. package/dist/features/streamgraph.common.js +1 -1
  89. package/dist/features/streamgraph.esm.js +1 -1
  90. package/dist/features/streamgraph.js +1 -1
  91. package/dist/features/toolbar.common.js +1 -1
  92. package/dist/features/toolbar.esm.js +1 -1
  93. package/dist/features/toolbar.js +1 -1
  94. package/dist/features/trellis.common.js +1 -1
  95. package/dist/features/trellis.esm.js +1 -1
  96. package/dist/features/trellis.js +1 -1
  97. package/dist/features/waterfall.common.js +1 -1
  98. package/dist/features/waterfall.esm.js +1 -1
  99. package/dist/features/waterfall.js +1 -1
  100. package/dist/features/weave.common.js +1 -1
  101. package/dist/features/weave.esm.js +1 -1
  102. package/dist/features/weave.js +1 -1
  103. package/dist/heatmap.common.js +1 -1
  104. package/dist/heatmap.esm.js +1 -1
  105. package/dist/heatmap.js +1 -1
  106. package/dist/histogram.common.js +1 -1
  107. package/dist/histogram.esm.js +1 -1
  108. package/dist/icicle.common.js +1 -1
  109. package/dist/icicle.esm.js +1 -1
  110. package/dist/icicle.js +1 -1
  111. package/dist/line.common.js +1 -1
  112. package/dist/line.esm.js +1 -1
  113. package/dist/line.js +1 -1
  114. package/dist/pictograms.common.js +1 -1
  115. package/dist/pictograms.esm.js +1 -1
  116. package/dist/pictograms.js +1 -1
  117. package/dist/pie.common.js +1 -1
  118. package/dist/pie.esm.js +1 -1
  119. package/dist/pie.js +1 -1
  120. package/dist/polarArea.common.js +1 -1
  121. package/dist/polarArea.esm.js +1 -1
  122. package/dist/radar.common.js +1 -1
  123. package/dist/radar.esm.js +1 -1
  124. package/dist/radar.js +1 -1
  125. package/dist/radialBar.common.js +1 -1
  126. package/dist/radialBar.esm.js +1 -1
  127. package/dist/radialBar.js +1 -1
  128. package/dist/raincloud.common.js +1 -1
  129. package/dist/raincloud.esm.js +1 -1
  130. package/dist/rangeArea.common.js +1 -1
  131. package/dist/rangeArea.esm.js +1 -1
  132. package/dist/rangeBar.common.js +1 -1
  133. package/dist/rangeBar.esm.js +1 -1
  134. package/dist/scatter.common.js +1 -1
  135. package/dist/scatter.esm.js +1 -1
  136. package/dist/streamgraph.common.js +1 -1
  137. package/dist/streamgraph.esm.js +1 -1
  138. package/dist/sunburst.common.js +1 -1
  139. package/dist/sunburst.esm.js +1 -1
  140. package/dist/sunburst.js +1 -1
  141. package/dist/treemap.common.js +1 -1
  142. package/dist/treemap.esm.js +1 -1
  143. package/dist/treemap.js +1 -1
  144. package/dist/unit-shapes.common.js +1 -1
  145. package/dist/unit-shapes.esm.js +1 -1
  146. package/dist/unit-shapes.js +1 -1
  147. package/dist/unit.common.js +1 -1
  148. package/dist/unit.esm.js +1 -1
  149. package/dist/unit.js +1 -1
  150. package/dist/violin.common.js +1 -1
  151. package/dist/violin.esm.js +1 -1
  152. package/dist/violin.js +1 -1
  153. package/dist/waterfall.common.js +1 -1
  154. package/dist/waterfall.esm.js +1 -1
  155. package/package.json +2 -2
  156. package/src/apexcharts.js +2 -0
  157. package/src/modules/DataLabels.js +234 -23
  158. package/src/modules/helpers/DataLabelOverlap.js +222 -0
  159. package/src/modules/settings/Defaults.js +17 -10
  160. package/src/modules/settings/Options.js +18 -0
  161. package/src/modules/tooltip/Labels.js +57 -25
  162. package/src/modules/tooltip/Marker.js +62 -17
  163. package/src/modules/tooltip/Position.js +10 -1
  164. package/src/modules/tooltip/Tooltip.js +96 -21
  165. package/types/apexcharts.d.ts +41 -1
@@ -42,7 +42,7 @@ var __async = (__this, __arguments, generator) => {
42
42
  });
43
43
  };
44
44
  /*!
45
- * ApexCharts v7.7.0
45
+ * ApexCharts v7.8.0
46
46
  * (c) 2018-2026 ApexCharts
47
47
  */
48
48
 
@@ -4314,6 +4314,24 @@ var __async = (__this, __arguments, generator) => {
4314
4314
  },
4315
4315
  textAnchor: "middle",
4316
4316
  distributed: false,
4317
+ // Nudge data labels apart when they land on each other, across series
4318
+ // as well as within one. ON by default: a label sitting on top of
4319
+ // another one is never what the chart meant to say, and the pass is a
4320
+ // no-op on a chart whose labels already clear each other, so the cost
4321
+ // of leaving it on is one measuring pass. Set false for the old
4322
+ // behaviour, or an object to override:
4323
+ // gap clear space left between two separated labels (px)
4324
+ // maxShift how far a label may travel from its own mark; defaults
4325
+ // to about one label's own size along that axis
4326
+ // hide drop a label that still collides after both have spent
4327
+ // their budget, later-drawn first. Off by default: this
4328
+ // pass runs on every chart, and silently deleting a value
4329
+ // is worse than the overlap it set out to fix.
4330
+ // Labels separate along the VALUE axis, so a horizontal bar's move
4331
+ // left/right and everything else moves up/down. Rotated labels are
4332
+ // avoided but never moved, and radial types (pie, radar, ...) are left
4333
+ // to their own placement.
4334
+ avoidOverlap: true,
4317
4335
  offsetX: 0,
4318
4336
  offsetY: 0,
4319
4337
  style: {
@@ -5538,6 +5556,7 @@ var __async = (__this, __arguments, generator) => {
5538
5556
  });
5539
5557
  }
5540
5558
  waterfall() {
5559
+ var _a;
5541
5560
  const range = this.rangeBar();
5542
5561
  return __spreadProps(__spreadValues({}, range), {
5543
5562
  chart: {
@@ -5580,18 +5599,28 @@ var __async = (__this, __arguments, generator) => {
5580
5599
  // `end - start`, which is the delta for a step bar and the sum for a
5581
5600
  // subtotal / total bar.
5582
5601
  enabled: true,
5583
- // Small steps are normal in a waterfall, and a label wider or taller
5584
- // than its bar gets placed OUTSIDE it. The range column's white label
5585
- // is then white text on the chart background, so the two smallest steps
5586
- // of a P&L bridge simply vanished. A pale chip with dark ink reads
5587
- // wherever the label lands: over a green, red or blue bar, or off it.
5602
+ // No chip behind the label. A waterfall is usually a dense row of
5603
+ // steps, and a chip per label is a second rectangle competing with the
5604
+ // bar it names.
5588
5605
  background: {
5589
- enabled: true,
5590
- backgroundColor: "#fff",
5591
- foreColor: "#373d3f",
5592
- borderColor: "#e3e8ee",
5593
- opacity: 0.92
5594
- }
5606
+ enabled: false
5607
+ },
5608
+ style: __spreadProps(__spreadValues(
5609
+ {},
5610
+ /** @type {any} */
5611
+ (_a = range.dataLabels) == null ? void 0 : _a.style
5612
+ ), {
5613
+ // Small steps are normal in a waterfall, and a label wider or taller
5614
+ // than its bar gets placed OUTSIDE it. The range column's white ink
5615
+ // is then white text on the chart background, so the two smallest
5616
+ // steps of a P&L bridge simply vanished. Following `chart.foreColor`
5617
+ // instead keeps the label readable off the bar in either theme, and
5618
+ // legible enough over an increase/decrease/total bar.
5619
+ colors: [
5620
+ /** @param {any} opts */
5621
+ (opts) => opts.w.config.chart.foreColor
5622
+ ]
5623
+ })
5595
5624
  }),
5596
5625
  legend: {
5597
5626
  // A waterfall is one series, so the legend would show a single swatch
@@ -12937,6 +12966,98 @@ var __async = (__this, __arguments, generator) => {
12937
12966
  });
12938
12967
  return Number.isFinite(resolved) ? resolved : 0;
12939
12968
  };
12969
+ function overlapY(a2, aShift, b, bShift) {
12970
+ const aTop = a2.y + aShift;
12971
+ const bTop = b.y + bShift;
12972
+ return Math.min(aTop + a2.height, bTop + b.height) - Math.max(aTop, bTop);
12973
+ }
12974
+ function overlapX(a2, b) {
12975
+ return Math.min(a2.x + a2.width, b.x + b.width) - Math.max(a2.x, b.x);
12976
+ }
12977
+ function resolveLabelOverlaps(boxes, opts) {
12978
+ var _a;
12979
+ const n2 = boxes.length;
12980
+ const result = new Array(n2);
12981
+ for (let i2 = 0; i2 < n2; i2++) result[i2] = { dy: 0, hidden: false };
12982
+ if (n2 < 2) return result;
12983
+ const { gap, maxShift, minY, maxY } = opts;
12984
+ const iterations = (_a = opts.iterations) != null ? _a : 6;
12985
+ const idx = boxes.map((_, i2) => i2).sort((a2, b) => boxes[a2].x - boxes[b].x);
12986
+ const clampShift = (i2, d) => {
12987
+ const b = boxes[i2];
12988
+ if (b.fixed) return result[i2].dy;
12989
+ const out = Math.max(-maxShift, Math.min(maxShift, d));
12990
+ const canGoUp = Math.min(0, minY - b.y);
12991
+ const canGoDown = Math.max(0, maxY - (b.y + b.height));
12992
+ return Math.max(canGoUp, Math.min(canGoDown, out));
12993
+ };
12994
+ for (let pass = 0; pass < iterations; pass++) {
12995
+ let moved = false;
12996
+ for (let p = 0; p < idx.length; p++) {
12997
+ const i2 = idx[p];
12998
+ const a2 = boxes[i2];
12999
+ if (result[i2].hidden) continue;
13000
+ for (let q = p + 1; q < idx.length; q++) {
13001
+ const j2 = idx[q];
13002
+ const b = boxes[j2];
13003
+ if (result[j2].hidden) continue;
13004
+ if (b.x >= a2.x + a2.width) break;
13005
+ if (overlapX(a2, b) <= 0) continue;
13006
+ const oy = overlapY(a2, result[i2].dy, b, result[j2].dy);
13007
+ if (oy <= -gap) continue;
13008
+ const need = oy + gap;
13009
+ const aCy = a2.y + result[i2].dy + a2.height / 2;
13010
+ const bCy = b.y + result[j2].dy + b.height / 2;
13011
+ const aUp = aCy === bCy ? a2.order <= b.order : aCy < bCy;
13012
+ const upIdx = aUp ? i2 : j2;
13013
+ const downIdx = aUp ? j2 : i2;
13014
+ const wantUp = clampShift(upIdx, result[upIdx].dy - need / 2);
13015
+ const wantDown = clampShift(downIdx, result[downIdx].dy + need / 2);
13016
+ const gotUp = result[upIdx].dy - wantUp;
13017
+ const gotDown = wantDown - result[downIdx].dy;
13018
+ const shortfall = need - (gotUp + gotDown);
13019
+ let finalUp = wantUp;
13020
+ let finalDown = wantDown;
13021
+ if (shortfall > 0.01) {
13022
+ finalDown = clampShift(downIdx, wantDown + shortfall);
13023
+ const stillShort = need - (gotUp + (finalDown - result[downIdx].dy));
13024
+ if (stillShort > 0.01) {
13025
+ finalUp = clampShift(upIdx, wantUp - stillShort);
13026
+ }
13027
+ }
13028
+ if (finalUp !== result[upIdx].dy || finalDown !== result[downIdx].dy) {
13029
+ result[upIdx].dy = finalUp;
13030
+ result[downIdx].dy = finalDown;
13031
+ moved = true;
13032
+ }
13033
+ }
13034
+ }
13035
+ if (!moved) break;
13036
+ }
13037
+ if (!opts.hide) return result;
13038
+ for (let p = 0; p < idx.length; p++) {
13039
+ const i2 = idx[p];
13040
+ if (result[i2].hidden) continue;
13041
+ const a2 = boxes[i2];
13042
+ for (let q = p + 1; q < idx.length; q++) {
13043
+ const j2 = idx[q];
13044
+ if (result[j2].hidden) continue;
13045
+ const b = boxes[j2];
13046
+ if (b.x >= a2.x + a2.width) break;
13047
+ if (overlapX(a2, b) <= 0) continue;
13048
+ if (overlapY(a2, result[i2].dy, b, result[j2].dy) > 0) {
13049
+ const first = a2.order <= b.order ? j2 : i2;
13050
+ const second = first === i2 ? j2 : i2;
13051
+ const loser = !boxes[first].fixed ? first : !boxes[second].fixed ? second : -1;
13052
+ if (loser === -1) continue;
13053
+ result[loser].hidden = true;
13054
+ if (loser === i2) break;
13055
+ }
13056
+ }
13057
+ }
13058
+ return result;
13059
+ }
13060
+ const RADIAL_TYPES = ["radar", "pie", "donut", "polarArea", "radialBar"];
12940
13061
  class DataLabels {
12941
13062
  /**
12942
13063
  * @param {import('../types/internal').ChartStateW} w
@@ -13259,33 +13380,164 @@ var __async = (__this, __arguments, generator) => {
13259
13380
  }
13260
13381
  return elRect;
13261
13382
  }
13383
+ /**
13384
+ * Separate data labels that landed on top of each other, across series.
13385
+ *
13386
+ * Runs after every series has drawn and before `dataLabelsBackground()`, for
13387
+ * two reasons: the shift has to be applied to the text before a pill is cut
13388
+ * around it, and only at this point does every label exist to be compared.
13389
+ * `dataLabelsCorrection` cannot do this job - it runs while a single series
13390
+ * is being plotted, so the labels it would collide with have not been drawn.
13391
+ *
13392
+ * On by default; `dataLabels.avoidOverlap: false` restores strict placement.
13393
+ * The pass is a no-op on a chart whose labels already clear each other, so
13394
+ * what it costs such a chart is the one measuring loop below.
13395
+ */
13396
+ avoidOverlaps() {
13397
+ var _a, _b, _c, _d;
13398
+ const w = this.w;
13399
+ const cfg = w.config.dataLabels.avoidOverlap;
13400
+ if (!cfg) return;
13401
+ if (RADIAL_TYPES.indexOf(w.config.chart.type) !== -1) return;
13402
+ const opts = typeof cfg === "object" ? cfg : {};
13403
+ const bCnf = w.config.dataLabels.background;
13404
+ const nodes = w.dom.baseEl.querySelectorAll(
13405
+ ".apexcharts-datalabels text.apexcharts-datalabel"
13406
+ );
13407
+ if (nodes.length < 2) return;
13408
+ const measured = [];
13409
+ for (let i2 = 0; i2 < nodes.length; i2++) {
13410
+ const el = (
13411
+ /** @type {SVGGraphicsElement} */
13412
+ nodes[i2]
13413
+ );
13414
+ const rect = el.getBoundingClientRect();
13415
+ const ctm = (_a = el.getScreenCTM) == null ? void 0 : _a.call(el);
13416
+ const screen2 = rect.width > 0 && rect.height > 0;
13417
+ const box = screen2 ? rect : el.getBBox();
13418
+ if (!box.width || !box.height) continue;
13419
+ const rotated = !!ctm && (Math.abs(ctm.b) > 1e-6 || Math.abs(ctm.c) > 1e-6);
13420
+ const scaleY = screen2 && ctm && ctm.d ? Math.abs(ctm.d) : 1;
13421
+ const scaleX = screen2 && ctm && ctm.a ? Math.abs(ctm.a) : 1;
13422
+ const padH = (bCnf.enabled ? bCnf.padding : 0) * scaleX;
13423
+ const padV = (bCnf.enabled ? bCnf.padding / 2 : 0) * scaleY;
13424
+ measured.push({
13425
+ el,
13426
+ scaleY,
13427
+ box: {
13428
+ x: (screen2 ? rect.left : box.x) - padH,
13429
+ y: (screen2 ? rect.top : box.y) - padV / 2,
13430
+ width: box.width + padH * 2,
13431
+ height: box.height + padV,
13432
+ order: measured.length,
13433
+ fixed: rotated
13434
+ }
13435
+ });
13436
+ }
13437
+ if (measured.length < 2) return;
13438
+ const horizontal = !!((_c = (_b = w.config.plotOptions) == null ? void 0 : _b.bar) == null ? void 0 : _c.horizontal);
13439
+ const boxes = measured.map(
13440
+ ({ box }) => horizontal ? {
13441
+ x: box.y,
13442
+ y: box.x,
13443
+ width: box.height,
13444
+ height: box.width,
13445
+ order: box.order,
13446
+ fixed: box.fixed
13447
+ } : box
13448
+ );
13449
+ const gridEl = w.dom.baseEl.querySelector(".apexcharts-grid");
13450
+ const gridRect = gridEl == null ? void 0 : gridEl.getBoundingClientRect();
13451
+ const useScreen = !!gridRect && gridRect.height > 0;
13452
+ const extent = boxes[0].height;
13453
+ const unit = measured[0].scaleY;
13454
+ const lo = useScreen ? horizontal ? gridRect.left : gridRect.top : 0;
13455
+ const hi = useScreen ? horizontal ? gridRect.right : gridRect.bottom : horizontal ? w.layout.gridWidth : w.layout.gridHeight;
13456
+ const resolved = resolveLabelOverlaps(boxes, {
13457
+ gap: ((_d = opts.gap) != null ? _d : 2) * unit,
13458
+ // Default budget is roughly one label's own extent in each direction:
13459
+ // far enough to clear a coincident twin, near enough that the label is
13460
+ // still unmistakably its mark's.
13461
+ maxShift: opts.maxShift ? opts.maxShift * unit : Math.max(extent, 14),
13462
+ // The plot itself, with no slack: past this edge the label is clipped,
13463
+ // so pushing one out there trades an overlap for a truncated value. A
13464
+ // label that already starts outside (the one above a bar that reaches
13465
+ // the top of the grid) keeps its place - resolveLabelOverlaps treats
13466
+ // these as a restriction on movement, never as a push.
13467
+ minY: lo,
13468
+ maxY: hi,
13469
+ // Dropping a label is opt-in. This pass is on by default, and a default
13470
+ // that silently deletes a value is worse than the overlap it set out to
13471
+ // fix: on a crowded horizontal bar it removed eight of eighteen labels.
13472
+ // Off, a pair that cannot be separated is simply left as it is today.
13473
+ hide: opts.hide === true
13474
+ });
13475
+ const attr = horizontal ? "x" : "y";
13476
+ const centreAttr = horizontal ? "cx" : "cy";
13477
+ for (let i2 = 0; i2 < measured.length; i2++) {
13478
+ const { el, scaleY } = measured[i2];
13479
+ const { dy, hidden } = resolved[i2];
13480
+ if (hidden) {
13481
+ el.style.display = "none";
13482
+ el.classList.add("apexcharts-datalabel-hidden");
13483
+ continue;
13484
+ }
13485
+ if (!dy) continue;
13486
+ const delta = dy / scaleY;
13487
+ const v = parseFloat(el.getAttribute(attr) || "0");
13488
+ el.setAttribute(attr, (v + delta).toString());
13489
+ const c = el.getAttribute(centreAttr);
13490
+ if (c !== null) {
13491
+ el.setAttribute(centreAttr, (parseFloat(c) + delta).toString());
13492
+ }
13493
+ }
13494
+ }
13262
13495
  dataLabelsBackground() {
13263
- var _a;
13496
+ var _a, _b;
13264
13497
  const w = this.w;
13265
13498
  if (w.config.chart.type === "bubble") return;
13266
13499
  const elDataLabels = w.dom.baseEl.querySelectorAll(
13267
13500
  ".apexcharts-datalabels text"
13268
13501
  );
13502
+ const measured = [];
13269
13503
  for (let i2 = 0; i2 < elDataLabels.length; i2++) {
13270
13504
  const el = elDataLabels[i2];
13271
- const coords = (
13505
+ const bbox = (
13272
13506
  /** @type {SVGGraphicsElement} */
13273
13507
  el.getBBox()
13274
13508
  );
13275
- let elRect = null;
13276
- if (coords.width && coords.height) {
13277
- elRect = this.addBackgroundToDataLabel(el, coords);
13278
- }
13279
- if (elRect) {
13280
- (_a = el.parentNode) == null ? void 0 : _a.insertBefore(elRect.node, el);
13281
- const background = w.config.dataLabels.background.backgroundColor || el.getAttribute("fill");
13282
- const shouldAnim = w.config.chart.animations.enabled && !w.globals.resized && !w.globals.dataChanged;
13283
- if (shouldAnim) {
13284
- elRect.animate().attr({ fill: background });
13285
- } else {
13286
- elRect.attr({ fill: background });
13287
- }
13288
- el.setAttribute("fill", w.config.dataLabels.background.foreColor);
13509
+ if (bbox.width && bbox.height) {
13510
+ measured.push({
13511
+ el,
13512
+ // copied out of the live SVGRect so nothing below can disturb it
13513
+ coords: {
13514
+ x: bbox.x,
13515
+ y: bbox.y,
13516
+ width: bbox.width,
13517
+ height: bbox.height
13518
+ },
13519
+ // captured before the write pass overwrites the text's own fill
13520
+ fill: el.getAttribute("fill")
13521
+ });
13522
+ }
13523
+ }
13524
+ const bCnf = w.config.dataLabels.background;
13525
+ const largeThreshold = (_a = w.config.chart.animations.largeDatasetThreshold) != null ? _a : 0;
13526
+ const bulkReveal = largeThreshold > 0 && measured.length > largeThreshold;
13527
+ const shouldAnim = w.config.chart.animations.enabled && !w.globals.resized && !w.globals.dataChanged && !bulkReveal;
13528
+ for (let i2 = 0; i2 < measured.length; i2++) {
13529
+ const { el, coords, fill } = measured[i2];
13530
+ const elRect = this.addBackgroundToDataLabel(el, coords);
13531
+ if (!elRect) continue;
13532
+ (_b = el.parentNode) == null ? void 0 : _b.insertBefore(elRect.node, el);
13533
+ const background = bCnf.backgroundColor || fill;
13534
+ if (shouldAnim) {
13535
+ elRect.animate().attr({ fill: background });
13536
+ } else {
13537
+ elRect.attr({ fill: background });
13538
+ }
13539
+ el.setAttribute("fill", bCnf.foreColor);
13540
+ if (!bulkReveal) {
13289
13541
  const cxAttr = el.getAttribute("cx");
13290
13542
  if (cxAttr !== null) {
13291
13543
  applyProgressiveReveal(elRect, parseFloat(cxAttr), w);
@@ -24147,8 +24399,9 @@ var __async = (__this, __arguments, generator) => {
24147
24399
  });
24148
24400
  const tooltipEl = this.ttCtx.getElTooltip();
24149
24401
  if (tooltipEl) {
24150
- this.ttCtx.tooltipRect.ttWidth = tooltipEl.getBoundingClientRect().width;
24151
- this.ttCtx.tooltipRect.ttHeight = tooltipEl.getBoundingClientRect().height;
24402
+ const rect = tooltipEl.getBoundingClientRect();
24403
+ this.ttCtx.tooltipRect.ttWidth = rect.width;
24404
+ this.ttCtx.tooltipRect.ttHeight = rect.height;
24152
24405
  }
24153
24406
  }
24154
24407
  /** @param {{i: any, j: any, values: any, ttItems: any, shared: any, e: any}} opts */
@@ -24157,8 +24410,10 @@ var __async = (__this, __arguments, generator) => {
24157
24410
  const { xVal, zVal, xAxisTTVal } = values;
24158
24411
  const seriesLen = w.seriesData.series.length;
24159
24412
  const basePColor = j2 !== null && w.config.plotOptions.bar.distributed ? w.globals.colors[j2] : w.globals.colors[i2];
24160
- for (let t2 = 0; t2 < seriesLen; t2++) {
24161
- const tIndex = w.config.tooltip.inverseOrder ? seriesLen - 1 - t2 : t2;
24413
+ const singleRow = (ttItems == null ? void 0 : ttItems.length) === 1;
24414
+ const iterations = singleRow ? 1 : seriesLen;
24415
+ for (let t2 = 0; t2 < iterations; t2++) {
24416
+ const tIndex = singleRow ? 0 : w.config.tooltip.inverseOrder ? seriesLen - 1 - t2 : t2;
24162
24417
  const row = this.computeSeriesRow({
24163
24418
  i: i2,
24164
24419
  j: j2,
@@ -24380,12 +24635,35 @@ var __async = (__this, __arguments, generator) => {
24380
24635
  w
24381
24636
  });
24382
24637
  }
24638
+ /**
24639
+ * The nodes a hover writes into, captured when the row was built in
24640
+ * Tooltip.createTTElements. Rows that did not come from there (or from an
24641
+ * older build) are queried once and then cached the same way, so no hover
24642
+ * repeats the lookups.
24643
+ * @param {any} row
24644
+ */
24645
+ rowRefs(row) {
24646
+ if (!row.ttRefs) {
24647
+ row.ttRefs = {
24648
+ marker: row.querySelector(".apexcharts-tooltip-marker"),
24649
+ text: row.querySelector(".apexcharts-tooltip-text"),
24650
+ yLabel: row.querySelector(".apexcharts-tooltip-text-y-label"),
24651
+ yValue: row.querySelector(".apexcharts-tooltip-text-y-value"),
24652
+ goalsLabel: row.querySelector(".apexcharts-tooltip-text-goals-label"),
24653
+ goalsValue: row.querySelector(".apexcharts-tooltip-text-goals-value"),
24654
+ zLabel: row.querySelector(".apexcharts-tooltip-text-z-label"),
24655
+ zValue: row.querySelector(".apexcharts-tooltip-text-z-value")
24656
+ };
24657
+ }
24658
+ return row.ttRefs;
24659
+ }
24383
24660
  /** @param {{ t?: any, j?: any, i?: any, ttItems?: any, values?: any, seriesName?: any, shared?: any, pColor?: any }} opts */
24384
24661
  DOMHandling({ t: t2, j: j2, ttItems, values, seriesName, shared, pColor }) {
24385
24662
  const w = this.w;
24386
24663
  const ttCtx = this.ttCtx;
24387
24664
  const { val, goalVals, xVal, xAxisTTVal, zVal } = values;
24388
24665
  if (!ttItems || !ttItems[t2]) return;
24666
+ const refs = this.rowRefs(ttItems[t2]);
24389
24667
  let ttItemsChildren = null;
24390
24668
  ttItemsChildren = ttItems[t2].children;
24391
24669
  if (w.config.tooltip.fillSeriesColor) {
@@ -24407,13 +24685,11 @@ var __async = (__this, __arguments, generator) => {
24407
24685
  ttCtx.xaxisTooltipText.innerHTML = xAxisTTVal !== "" ? xAxisTTVal : xVal;
24408
24686
  }
24409
24687
  }
24410
- const ttYLabel = ttItems[t2].querySelector(
24411
- ".apexcharts-tooltip-text-y-label"
24412
- );
24688
+ const ttYLabel = refs.yLabel;
24413
24689
  if (ttYLabel) {
24414
24690
  ttYLabel.innerHTML = seriesName ? seriesName : "";
24415
24691
  }
24416
- const ttYVal = ttItems[t2].querySelector(".apexcharts-tooltip-text-y-value");
24692
+ const ttYVal = refs.yValue;
24417
24693
  if (ttYVal) {
24418
24694
  ttYVal.innerHTML = typeof val !== "undefined" ? val : "";
24419
24695
  }
@@ -24430,12 +24706,8 @@ var __async = (__this, __arguments, generator) => {
24430
24706
  if (!w.config.tooltip.marker.show) {
24431
24707
  ttItemsChildren[0].style.display = "none";
24432
24708
  }
24433
- const ttGLabel = ttItems[t2].querySelector(
24434
- ".apexcharts-tooltip-text-goals-label"
24435
- );
24436
- const ttGVal = ttItems[t2].querySelector(
24437
- ".apexcharts-tooltip-text-goals-value"
24438
- );
24709
+ const ttGLabel = refs.goalsLabel;
24710
+ const ttGVal = refs.goalsValue;
24439
24711
  if (goalVals.length && w.seriesData.seriesGoals[t2]) {
24440
24712
  const createGoalsHtml = () => {
24441
24713
  let gLabels = "<div>";
@@ -24462,21 +24734,15 @@ var __async = (__this, __arguments, generator) => {
24462
24734
  ttGVal.innerHTML = "";
24463
24735
  }
24464
24736
  if (zVal !== null) {
24465
- const ttZLabel = ttItems[t2].querySelector(
24466
- ".apexcharts-tooltip-text-z-label"
24467
- );
24737
+ const ttZLabel = refs.zLabel;
24468
24738
  ttZLabel.innerHTML = w.config.tooltip.z.title;
24469
- const ttZVal = ttItems[t2].querySelector(
24470
- ".apexcharts-tooltip-text-z-value"
24471
- );
24739
+ const ttZVal = refs.zValue;
24472
24740
  ttZVal.innerHTML = typeof zVal !== "undefined" ? zVal : "";
24473
24741
  }
24474
24742
  if (shared && ttItemsChildren[0]) {
24475
24743
  if (w.config.tooltip.hideEmptySeries) {
24476
- const ttItemMarker = ttItems[t2].querySelector(
24477
- ".apexcharts-tooltip-marker"
24478
- );
24479
- const ttItemText = ttItems[t2].querySelector(".apexcharts-tooltip-text");
24744
+ const ttItemMarker = refs.marker;
24745
+ const ttItemText = refs.text;
24480
24746
  if (parseFloat(val) == 0) {
24481
24747
  ttItemMarker.style.display = "none";
24482
24748
  ttItemText.style.display = "none";
@@ -24501,13 +24767,15 @@ var __async = (__this, __arguments, generator) => {
24501
24767
  * @param {number} i
24502
24768
  */
24503
24769
  toggleActiveInactiveSeries(shared, i2) {
24770
+ var _a;
24504
24771
  const w = this.w;
24505
24772
  if (shared) {
24506
24773
  this.tooltipUtil.toggleAllTooltipSeriesGroups("enable");
24507
24774
  } else {
24508
24775
  this.tooltipUtil.toggleAllTooltipSeriesGroups("disable");
24776
+ const rowIndex = ((_a = this.ttCtx.ttItems) == null ? void 0 : _a.length) === 1 ? 0 : i2;
24509
24777
  const firstTooltipSeriesGroup = w.dom.baseEl.querySelector(
24510
- `.apexcharts-tooltip-series-group-${i2}`
24778
+ `.apexcharts-tooltip-series-group-${rowIndex}`
24511
24779
  );
24512
24780
  if (firstTooltipSeriesGroup) {
24513
24781
  const ftsGroup = (
@@ -24940,8 +25208,9 @@ var __async = (__this, __arguments, generator) => {
24940
25208
  );
24941
25209
  for (let p = 0; p < allPoints.length; p++) {
24942
25210
  if (parseInt((_a = allPoints[p].getAttribute("rel")) != null ? _a : "0", 10) === j2) {
24943
- ttCtx.marker.resetPointsSize();
25211
+ ttCtx.marker.resetEnlargedPoints();
24944
25212
  ttCtx.marker.enlargeCurrentPoint(j2, allPoints[p]);
25213
+ break;
24945
25214
  }
24946
25215
  }
24947
25216
  } else {
@@ -25299,6 +25568,7 @@ var __async = (__this, __arguments, generator) => {
25299
25568
  this.ttCtx = tooltipContext;
25300
25569
  this.ctx = tooltipContext.ctx;
25301
25570
  this.tooltipPosition = new Position(tooltipContext);
25571
+ this.enlargedPoints = /* @__PURE__ */ new Set();
25302
25572
  }
25303
25573
  drawDynamicPoints() {
25304
25574
  const w = this.w;
@@ -25376,12 +25646,14 @@ var __async = (__this, __arguments, generator) => {
25376
25646
  const me = this;
25377
25647
  const ttCtx = this.ttCtx;
25378
25648
  const col = j2;
25649
+ this.resetEnlargedPoints();
25379
25650
  const points = w.dom.baseEl.querySelectorAll(
25380
- ".apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker"
25651
+ `.apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker[rel="${col}"]`
25381
25652
  );
25382
25653
  let newSize = w.config.markers.hover.size;
25654
+ let lastCx = null;
25655
+ let lastCy = null;
25383
25656
  for (let p = 0; p < points.length; p++) {
25384
- const rel = points[p].getAttribute("rel");
25385
25657
  const index = points[p].getAttribute("index");
25386
25658
  if (newSize === void 0) {
25387
25659
  newSize = w.globals.markers.size[
@@ -25389,22 +25661,35 @@ var __async = (__this, __arguments, generator) => {
25389
25661
  index
25390
25662
  ] + w.config.markers.hover.sizeOffset;
25391
25663
  }
25392
- if (col === parseInt(rel != null ? rel : "0", 10)) {
25393
- me.newPointSize(col, points[p]);
25394
- const cx = (_a = points[p].getAttribute("cx")) != null ? _a : "0";
25395
- const cy = (_b = points[p].getAttribute("cy")) != null ? _b : "0";
25396
- me.tooltipPosition.moveXCrosshairs(parseFloat(cx));
25397
- if (!ttCtx.fixedTooltip) {
25398
- me.tooltipPosition.moveTooltip(
25399
- parseFloat(cx),
25400
- parseFloat(cy),
25401
- newSize
25402
- );
25403
- }
25404
- } else {
25405
- me.oldPointSize(points[p]);
25406
- }
25664
+ me.newPointSize(col, points[p]);
25665
+ lastCx = (_a = points[p].getAttribute("cx")) != null ? _a : "0";
25666
+ lastCy = (_b = points[p].getAttribute("cy")) != null ? _b : "0";
25667
+ }
25668
+ if (lastCx === null) return;
25669
+ me.tooltipPosition.moveXCrosshairs(parseFloat(lastCx));
25670
+ if (!ttCtx.fixedTooltip) {
25671
+ me.tooltipPosition.moveTooltip(
25672
+ parseFloat(lastCx),
25673
+ parseFloat(
25674
+ /** @type {string} */
25675
+ lastCy
25676
+ ),
25677
+ newSize
25678
+ );
25679
+ }
25680
+ }
25681
+ /**
25682
+ * Restore every marker this module grew back to its default size. Cheap
25683
+ * because it only visits the handful of nodes actually enlarged, where the
25684
+ * old code re-pathed every marker in the chart.
25685
+ */
25686
+ resetEnlargedPoints() {
25687
+ if (this.enlargedPoints.size === 0) return;
25688
+ const points = Array.from(this.enlargedPoints);
25689
+ for (let i2 = 0; i2 < points.length; i2++) {
25690
+ this.oldPointSize(points[i2]);
25407
25691
  }
25692
+ this.enlargedPoints.clear();
25408
25693
  }
25409
25694
  /**
25410
25695
  * Resizes the hovered marker to its hover size and returns the size applied,
@@ -25428,6 +25713,7 @@ var __async = (__this, __arguments, generator) => {
25428
25713
  }
25429
25714
  const path = this.ttCtx.tooltipUtil.getPathFromPoint(point, newSize);
25430
25715
  point.setAttribute("d", path);
25716
+ this.enlargedPoints.add(point);
25431
25717
  return newSize;
25432
25718
  }
25433
25719
  return void 0;
@@ -25439,10 +25725,12 @@ var __async = (__this, __arguments, generator) => {
25439
25725
  const size = parseFloat(point.getAttribute("default-marker-size"));
25440
25726
  const path = this.ttCtx.tooltipUtil.getPathFromPoint(point, size);
25441
25727
  point.setAttribute("d", path);
25728
+ this.enlargedPoints.delete(point);
25442
25729
  }
25443
25730
  resetPointsSize() {
25444
25731
  var _a;
25445
25732
  const w = this.w;
25733
+ this.enlargedPoints.clear();
25446
25734
  const points = w.dom.baseEl.querySelectorAll(
25447
25735
  ".apexcharts-series:not(.apexcharts-series-collapsed) .apexcharts-marker"
25448
25736
  );
@@ -26114,9 +26402,11 @@ var __async = (__this, __arguments, generator) => {
26114
26402
  this.dataPointsDividedHeight = 0;
26115
26403
  this.dataPointsDividedWidth = 0;
26116
26404
  this.tooltipTitle = null;
26405
+ this._elTooltipCache = null;
26406
+ this._elXCrosshairsCache = null;
26407
+ this._elGridCache = null;
26117
26408
  this.legendLabels = null;
26118
26409
  this.ttItems = null;
26119
- this.seriesBound = null;
26120
26410
  this.seriesHoverTimeout = void 0;
26121
26411
  this.interactiveHideTimeout = void 0;
26122
26412
  this.clientX = 0;
@@ -26144,7 +26434,6 @@ var __async = (__this, __arguments, generator) => {
26144
26434
  const w = this.w;
26145
26435
  const tooltipEl = this.getElTooltip();
26146
26436
  if (!tooltipEl) return;
26147
- this.updateDimensionCache();
26148
26437
  if (typeof ResizeObserver !== "undefined" && !w.globals.resizeObserver) {
26149
26438
  w.globals.resizeObserver = new ResizeObserver(() => {
26150
26439
  if (!this.dimensionUpdateScheduled) {
@@ -26199,21 +26488,59 @@ var __async = (__this, __arguments, generator) => {
26199
26488
  * @param {{ w: import('../../types/internal').ChartStateW }} [ctx]
26200
26489
  * @returns {HTMLElement | null}
26201
26490
  */
26491
+ /**
26492
+ * Resolve a chart-level element, keeping the node between calls.
26493
+ *
26494
+ * Hover paths ask for these several times per frame and every lookup is a
26495
+ * `querySelector` across the entire chart DOM, which a CPU profile of a
26496
+ * 700-series chart showed dominating hover time. Validity is checked with
26497
+ * `baseEl.contains()` — a short walk up the ancestors, not a tree scan.
26498
+ *
26499
+ * That check is what respects `fastUpdate`: `drawTooltip` DETACHES the
26500
+ * existing tooltip before building a replacement (see its comment on the
26501
+ * fastUpdate path), so a rebuilt element leaves the cached node outside
26502
+ * `baseEl`, the check fails, and the selector runs again. A full re-render
26503
+ * replaces `baseEl`'s subtree with the same consequence.
26504
+ *
26505
+ * @param {any} ctx owner of the cache slot (a Tooltip, or another chart)
26506
+ * @param {string} key cache property on that owner
26507
+ * @param {string} selector
26508
+ * @returns {any}
26509
+ */
26510
+ _resolveEl(ctx, key, selector) {
26511
+ var _a, _b;
26512
+ const baseEl = (_b = (_a = ctx.w) == null ? void 0 : _a.dom) == null ? void 0 : _b.baseEl;
26513
+ if (!baseEl) return null;
26514
+ const cached = ctx[key];
26515
+ if (cached && baseEl.contains(cached)) return cached;
26516
+ const el = baseEl.querySelector(selector);
26517
+ ctx[key] = el;
26518
+ return el;
26519
+ }
26520
+ /**
26521
+ * @param {any} [ctx] another chart's context, for grouped tooltips
26522
+ * @returns {HTMLElement | null}
26523
+ */
26202
26524
  getElTooltip(ctx) {
26203
26525
  if (!ctx) ctx = this;
26204
- if (!ctx.w.dom.baseEl) return null;
26205
26526
  return (
26206
26527
  /** @type {HTMLElement | null} */
26207
- ctx.w.dom.baseEl.querySelector(
26528
+ this._resolveEl(
26529
+ ctx,
26530
+ "_elTooltipCache",
26208
26531
  ".apexcharts-tooltip:not(.apexcharts-annotation-tooltip)"
26209
26532
  )
26210
26533
  );
26211
26534
  }
26212
26535
  getElXCrosshairs() {
26213
- return this.w.dom.baseEl.querySelector(".apexcharts-xcrosshairs");
26536
+ return this._resolveEl(
26537
+ this,
26538
+ "_elXCrosshairsCache",
26539
+ ".apexcharts-xcrosshairs"
26540
+ );
26214
26541
  }
26215
26542
  getElGrid() {
26216
- return this.w.dom.baseEl.querySelector(".apexcharts-grid");
26543
+ return this._resolveEl(this, "_elGridCache", ".apexcharts-grid");
26217
26544
  }
26218
26545
  /**
26219
26546
  * @param {import('../../types/internal').XYRatios} xyRatios
@@ -26330,12 +26657,8 @@ var __async = (__this, __arguments, generator) => {
26330
26657
  tooltipEl.appendChild(this.tooltipTitle);
26331
26658
  }
26332
26659
  let ttItemsCnt = w.seriesData.series.length;
26333
- if ((w.globals.xyCharts || w.globals.comboCharts) && this.tConfig.shared) {
26334
- if (!this.showOnIntersect) {
26335
- ttItemsCnt = w.seriesData.series.length;
26336
- } else {
26337
- ttItemsCnt = 1;
26338
- }
26660
+ if (w.globals.xyCharts || w.globals.comboCharts) {
26661
+ ttItemsCnt = this.tConfig.shared && !this.showOnIntersect ? w.seriesData.series.length : 1;
26339
26662
  }
26340
26663
  this.legendLabels = w.dom.baseEl.querySelectorAll(".apexcharts-legend-text");
26341
26664
  this.ttItems = this.createTTElements(ttItemsCnt);
@@ -26387,6 +26710,7 @@ var __async = (__this, __arguments, generator) => {
26387
26710
  gYZ.classList.add("apexcharts-tooltip-text");
26388
26711
  gYZ.style.fontFamily = this.tConfig.style.fontFamily || w.config.chart.fontFamily;
26389
26712
  gYZ.style.fontSize = this.tConfig.style.fontSize;
26713
+ const refs = { marker: point, text: gYZ };
26390
26714
  ["y", "goals", "z"].forEach((g) => {
26391
26715
  const gValText = BrowserAPIs.createElementNS(
26392
26716
  "http://www.w3.org/1999/xhtml",
@@ -26405,9 +26729,12 @@ var __async = (__this, __arguments, generator) => {
26405
26729
  );
26406
26730
  txtValue.classList.add(`apexcharts-tooltip-text-${g}-value`);
26407
26731
  gValText.appendChild(txtValue);
26732
+ refs[`${g}Label`] = txtLabel;
26733
+ refs[`${g}Value`] = txtValue;
26408
26734
  gYZ.appendChild(gValText);
26409
26735
  });
26410
26736
  gTxt.appendChild(gYZ);
26737
+ gTxt.ttRefs = refs;
26411
26738
  tooltipEl.appendChild(gTxt);
26412
26739
  ttItems.push(gTxt);
26413
26740
  }
@@ -26423,9 +26750,6 @@ var __async = (__this, __arguments, generator) => {
26423
26750
  const isPolarMarkerChart = chartWithmarkers && !w.globals.xyCharts;
26424
26751
  const hoverArea = w.dom.Paper.node;
26425
26752
  const elGrid = this.getElGrid();
26426
- if (elGrid) {
26427
- this.seriesBound = elGrid.getBoundingClientRect();
26428
- }
26429
26753
  const tooltipY = [];
26430
26754
  const tooltipX = [];
26431
26755
  const seriesHoverParams = {
@@ -29696,6 +30020,7 @@ var __async = (__this, __arguments, generator) => {
29696
30020
  const elGraph = this.core.plotChartType(series, xyRatios);
29697
30021
  const dataLabels = new DataLabels(this.w, this);
29698
30022
  dataLabels.bringForward();
30023
+ dataLabels.avoidOverlaps();
29699
30024
  if (w.config.dataLabels.background.enabled) {
29700
30025
  dataLabels.dataLabelsBackground();
29701
30026
  }
@@ -30365,6 +30690,7 @@ var __async = (__this, __arguments, generator) => {
30365
30690
  }
30366
30691
  const dataLabels = new DataLabels(w, this);
30367
30692
  dataLabels.bringForward();
30693
+ dataLabels.avoidOverlaps();
30368
30694
  if (w.config.dataLabels.background.enabled) {
30369
30695
  dataLabels.dataLabelsBackground();
30370
30696
  }