apexcharts 8.2.0 → 8.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (222) hide show
  1. package/README.md +7 -7
  2. package/dist/apexcharts.common.js +2 -2
  3. package/dist/apexcharts.core.js +271 -173
  4. package/dist/apexcharts.core.min.js +2 -2
  5. package/dist/apexcharts.css +35 -0
  6. package/dist/apexcharts.esm.js +1722 -1527
  7. package/dist/apexcharts.full.js +1459 -1075
  8. package/dist/apexcharts.full.min.js +2 -2
  9. package/dist/apexcharts.js +994 -715
  10. package/dist/apexcharts.min.js +2 -2
  11. package/dist/apexcharts.ssr.common.js +2 -2
  12. package/dist/apexcharts.ssr.esm.js +994 -715
  13. package/dist/area.common.js +2 -2
  14. package/dist/area.esm.js +91 -40
  15. package/dist/bar.common.js +2 -2
  16. package/dist/bar.esm.js +433 -394
  17. package/dist/bar.js +2 -2
  18. package/dist/boxPlot.common.js +2 -2
  19. package/dist/boxPlot.esm.js +364 -322
  20. package/dist/bubble.common.js +2 -2
  21. package/dist/bubble.esm.js +91 -40
  22. package/dist/candlestick.common.js +2 -2
  23. package/dist/candlestick.esm.js +364 -322
  24. package/dist/candlestick.js +2 -2
  25. package/dist/column.common.js +2 -2
  26. package/dist/column.esm.js +433 -394
  27. package/dist/core.common.js +2 -2
  28. package/dist/core.esm.js +271 -173
  29. package/dist/donut.common.js +1 -1
  30. package/dist/donut.esm.js +1 -1
  31. package/dist/dumbbell.common.js +2 -2
  32. package/dist/dumbbell.esm.js +433 -394
  33. package/dist/features/all.common.js +2 -2
  34. package/dist/features/all.esm.js +250 -187
  35. package/dist/features/annotations.common.js +1 -1
  36. package/dist/features/annotations.esm.js +1 -1
  37. package/dist/features/annotations.js +1 -1
  38. package/dist/features/context-menu.common.js +1 -1
  39. package/dist/features/context-menu.esm.js +1 -1
  40. package/dist/features/context-menu.js +1 -1
  41. package/dist/features/drilldown.common.js +2 -2
  42. package/dist/features/drilldown.esm.js +4 -2
  43. package/dist/features/drilldown.js +2 -2
  44. package/dist/features/dumbbell.common.js +1 -1
  45. package/dist/features/dumbbell.esm.js +1 -1
  46. package/dist/features/dumbbell.js +1 -1
  47. package/dist/features/exports.common.js +1 -1
  48. package/dist/features/exports.esm.js +1 -1
  49. package/dist/features/exports.js +1 -1
  50. package/dist/features/facet.common.js +1 -1
  51. package/dist/features/facet.esm.js +1 -1
  52. package/dist/features/facet.js +1 -1
  53. package/dist/features/highlight-filter.common.js +2 -2
  54. package/dist/features/highlight-filter.esm.js +14 -9
  55. package/dist/features/highlight-filter.js +2 -2
  56. package/dist/features/history.common.js +1 -1
  57. package/dist/features/history.esm.js +1 -1
  58. package/dist/features/history.js +1 -1
  59. package/dist/features/ink.common.js +1 -1
  60. package/dist/features/ink.esm.js +1 -1
  61. package/dist/features/ink.js +1 -1
  62. package/dist/features/keyboard.common.js +2 -2
  63. package/dist/features/keyboard.esm.js +97 -145
  64. package/dist/features/keyboard.js +2 -2
  65. package/dist/features/legend.common.js +2 -2
  66. package/dist/features/legend.esm.js +63 -43
  67. package/dist/features/legend.js +2 -2
  68. package/dist/features/link.common.js +1 -1
  69. package/dist/features/link.esm.js +1 -1
  70. package/dist/features/link.js +1 -1
  71. package/dist/features/marks.common.js +1 -1
  72. package/dist/features/marks.esm.js +1 -1
  73. package/dist/features/marks.js +1 -1
  74. package/dist/features/measure.common.js +1 -1
  75. package/dist/features/measure.esm.js +1 -1
  76. package/dist/features/measure.js +1 -1
  77. package/dist/features/morph.common.js +1 -1
  78. package/dist/features/morph.esm.js +1 -1
  79. package/dist/features/morph.js +1 -1
  80. package/dist/features/perspectives.common.js +1 -1
  81. package/dist/features/perspectives.esm.js +1 -1
  82. package/dist/features/perspectives.js +1 -1
  83. package/dist/features/raincloud.common.js +1 -1
  84. package/dist/features/raincloud.esm.js +1 -1
  85. package/dist/features/raincloud.js +1 -1
  86. package/dist/features/renderer-canvas.common.js +2 -2
  87. package/dist/features/renderer-canvas.esm.js +2 -1
  88. package/dist/features/renderer-canvas.js +2 -2
  89. package/dist/features/stats.common.js +1 -1
  90. package/dist/features/stats.esm.js +1 -1
  91. package/dist/features/stats.js +1 -1
  92. package/dist/features/storyboard.common.js +1 -1
  93. package/dist/features/storyboard.esm.js +1 -1
  94. package/dist/features/storyboard.js +1 -1
  95. package/dist/features/streamgraph.common.js +2 -2
  96. package/dist/features/streamgraph.esm.js +3 -2
  97. package/dist/features/streamgraph.js +2 -2
  98. package/dist/features/toolbar.common.js +2 -2
  99. package/dist/features/toolbar.esm.js +92 -2
  100. package/dist/features/toolbar.js +2 -2
  101. package/dist/features/trellis.common.js +2 -2
  102. package/dist/features/trellis.esm.js +83 -47
  103. package/dist/features/trellis.js +2 -2
  104. package/dist/features/waterfall.common.js +1 -1
  105. package/dist/features/waterfall.esm.js +1 -1
  106. package/dist/features/waterfall.js +1 -1
  107. package/dist/features/weave.common.js +1 -1
  108. package/dist/features/weave.esm.js +1 -1
  109. package/dist/features/weave.js +1 -1
  110. package/dist/full.common.js +2 -2
  111. package/dist/full.esm.js +950 -795
  112. package/dist/heatmap.common.js +2 -2
  113. package/dist/heatmap.esm.js +3 -17
  114. package/dist/heatmap.js +2 -2
  115. package/dist/histogram.common.js +2 -2
  116. package/dist/histogram.esm.js +433 -394
  117. package/dist/icicle.common.js +2 -2
  118. package/dist/icicle.esm.js +54 -38
  119. package/dist/icicle.js +2 -2
  120. package/dist/line.common.js +2 -2
  121. package/dist/line.esm.js +91 -40
  122. package/dist/line.js +2 -2
  123. package/dist/locales/en.json +2 -1
  124. package/dist/locales/ro.json +3 -2
  125. package/dist/pictograms.common.js +1 -1
  126. package/dist/pictograms.esm.js +1 -1
  127. package/dist/pictograms.js +1 -1
  128. package/dist/pie.common.js +1 -1
  129. package/dist/pie.esm.js +1 -1
  130. package/dist/pie.js +1 -1
  131. package/dist/polarArea.common.js +1 -1
  132. package/dist/polarArea.esm.js +1 -1
  133. package/dist/radar.common.js +2 -2
  134. package/dist/radar.esm.js +5 -4
  135. package/dist/radar.js +2 -2
  136. package/dist/radialBar.common.js +1 -1
  137. package/dist/radialBar.esm.js +1 -1
  138. package/dist/radialBar.js +1 -1
  139. package/dist/raincloud.common.js +2 -2
  140. package/dist/raincloud.esm.js +72 -26
  141. package/dist/rangeArea.common.js +2 -2
  142. package/dist/rangeArea.esm.js +91 -40
  143. package/dist/rangeBar.common.js +2 -2
  144. package/dist/rangeBar.esm.js +433 -394
  145. package/dist/scatter.common.js +2 -2
  146. package/dist/scatter.esm.js +91 -40
  147. package/dist/streamgraph.common.js +2 -2
  148. package/dist/streamgraph.esm.js +93 -41
  149. package/dist/sunburst.common.js +2 -2
  150. package/dist/sunburst.esm.js +103 -93
  151. package/dist/sunburst.js +2 -2
  152. package/dist/treemap.common.js +2 -2
  153. package/dist/treemap.esm.js +105 -86
  154. package/dist/treemap.js +2 -2
  155. package/dist/unit-shapes.common.js +1 -1
  156. package/dist/unit-shapes.esm.js +1 -1
  157. package/dist/unit-shapes.js +1 -1
  158. package/dist/unit.common.js +2 -2
  159. package/dist/unit.esm.js +280 -202
  160. package/dist/unit.js +2 -2
  161. package/dist/violin.common.js +2 -2
  162. package/dist/violin.esm.js +72 -26
  163. package/dist/violin.js +2 -2
  164. package/dist/waterfall.common.js +2 -2
  165. package/dist/waterfall.esm.js +432 -393
  166. package/package.json +1 -1
  167. package/src/apexcharts.js +13 -6
  168. package/src/assets/apexcharts.css +35 -0
  169. package/src/charts/Bar.js +62 -55
  170. package/src/charts/BarStacked.js +80 -88
  171. package/src/charts/BoxCandleStick.js +28 -31
  172. package/src/charts/Icicle.js +37 -37
  173. package/src/charts/Line.js +118 -42
  174. package/src/charts/Radar.js +5 -7
  175. package/src/charts/RangeBar.js +47 -43
  176. package/src/charts/Sunburst.js +101 -98
  177. package/src/charts/Treemap.js +108 -66
  178. package/src/charts/Unit.js +368 -250
  179. package/src/charts/Violin.js +48 -30
  180. package/src/charts/common/Breadcrumb.js +2 -2
  181. package/src/charts/common/Hierarchy.js +32 -11
  182. package/src/charts/common/Jitter.js +32 -7
  183. package/src/charts/common/bar/DataLabels.js +76 -81
  184. package/src/charts/common/bar/Helpers.js +43 -7
  185. package/src/charts/common/line/Helpers.js +12 -15
  186. package/src/charts/common/partition/NodeTooltip.js +8 -1
  187. package/src/charts/common/partition/Partition.js +33 -1
  188. package/src/charts/common/treemap/Helpers.js +3 -11
  189. package/src/locales/en.json +2 -1
  190. package/src/locales/ro.json +3 -2
  191. package/src/modules/Core.js +4 -0
  192. package/src/modules/CoreUtils.js +18 -42
  193. package/src/modules/Data.js +23 -24
  194. package/src/modules/DataLabels.js +6 -6
  195. package/src/modules/Graphics.js +62 -49
  196. package/src/modules/Markers.js +3 -1
  197. package/src/modules/Range.js +44 -29
  198. package/src/modules/RendererController.js +17 -3
  199. package/src/modules/Scales.js +32 -9
  200. package/src/modules/Series.js +39 -18
  201. package/src/modules/Theme.js +1 -1
  202. package/src/modules/ZoomPanSelection.js +119 -2
  203. package/src/modules/accessibility/KeyboardNavigation.js +114 -186
  204. package/src/modules/animations/LengthTransition.js +22 -2
  205. package/src/modules/drilldown/Breadcrumb.js +5 -2
  206. package/src/modules/helpers/Destroy.js +1 -1
  207. package/src/modules/highlightFilter/HighlightFilter.js +8 -9
  208. package/src/modules/highlightFilter/TreemapPart.js +2 -2
  209. package/src/modules/legend/HeatmapGradientLegend.js +76 -45
  210. package/src/modules/legend/Helpers.js +2 -0
  211. package/src/modules/legend/Legend.js +11 -12
  212. package/src/modules/settings/Options.js +7 -0
  213. package/src/modules/streamgraph/StreamLabels.js +1 -0
  214. package/src/modules/tooltip/Tooltip.js +20 -4
  215. package/src/modules/tooltip/Utils.js +8 -0
  216. package/src/modules/trellis/Trellis.js +6 -0
  217. package/src/modules/trellis/TrellisChrome.js +18 -7
  218. package/src/modules/trellis/TrellisSync.js +2 -0
  219. package/src/renderers/canvas/CanvasGraphics.js +1 -0
  220. package/src/ssr/DOMShim.js +10 -0
  221. package/src/types/internal.d.ts +9 -3
  222. package/types/apexcharts.d.ts +31 -12
@@ -325,28 +325,6 @@ class CoreUtils {
325
325
  // for multi axis charts.
326
326
  gl.seriesYAxisMap = axisSeriesMap.map((x) => x)
327
327
  gl.seriesYAxisReverseMap = seriesYAxisReverseMap.map((x) => x)
328
- // Set default series group names
329
- /**
330
- * @param {Record<string, any>} axisSeries
331
- * @param {number} ai
332
- */
333
- gl.seriesYAxisMap.forEach((axisSeries, ai) => {
334
- /**
335
- * @param {number} si
336
- */
337
- axisSeries.forEach((si) => {
338
- // series may be bare until loaded in realtime
339
- if (
340
- /** @type {any} */ (cnf.series[si]) &&
341
- /** @type {any} */ (cnf.series[si]).group === undefined
342
- ) {
343
- // A series with no group defined will be named after the axis that
344
- // referenced it and thus form a group automatically.
345
- const _series = /** @type {any} */ (cnf.series[si])
346
- _series.group = 'apexcharts-axis-'.concat(ai.toString())
347
- }
348
- })
349
- })
350
328
  }
351
329
 
352
330
  /**
@@ -552,18 +530,20 @@ class CoreUtils {
552
530
  const stackedTotals = excluded.length
553
531
  ? this.getStackedSeriesTotals(excluded)
554
532
  : w.seriesData.stackedSeriesTotals
555
- // Columns and areas on a numeric axis stack by x, so each point takes its
556
- // share of the stack at its own x (horizontal bars stack by index).
557
- const sx =
558
- w.axisFlags.isXNumeric &&
559
- !w.config.plotOptions.bar.horizontal &&
560
- w.seriesData.seriesX
561
- /** @type {Map<number, number>} */
533
+ // Bars and areas on a numeric axis stack by x, so each point takes its
534
+ // share of the stack at its own x.
535
+ const sx = w.axisFlags.isXNumeric && w.seriesData.seriesX
536
+ // Each series group is its own stack, so it normalises to its own total.
537
+ const gi = w.labelData.seriesGroupIndex
538
+ const byKey = sx || w.labelData.seriesGroups.length > 1
539
+ /** @param {number} i @param {number} j */
540
+ const key = (i, j) => gi[i] + ' ' + (sx ? sx[i][j] : j)
541
+ /** @type {Map<string, number>} */
562
542
  const byX = new Map()
563
- if (sx) {
543
+ if (byKey) {
564
544
  w.seriesData.series.forEach((s, i) => {
565
545
  if (excluded.indexOf(i) < 0) {
566
- s.forEach((v, j) => byX.set(sx[i][j], (byX.get(sx[i][j]) || 0) + v))
546
+ s.forEach((v, j) => byX.set(key(i, j), (byX.get(key(i, j)) || 0) + v))
567
547
  }
568
548
  })
569
549
  }
@@ -576,7 +556,7 @@ class CoreUtils {
576
556
  const seriesPercent = []
577
557
  if (Array.isArray(ser)) {
578
558
  for (let j = 0; j < ser.length; j++) {
579
- const total = sx ? byX.get(sx[i][j]) : stackedTotals[j]
559
+ const total = byKey ? byX.get(key(i, j)) : stackedTotals[j]
580
560
  let percent = 0
581
561
  if (total) {
582
562
  percent = (100 * ser[j]) / total
@@ -638,11 +618,9 @@ class CoreUtils {
638
618
  zRatio = 1
639
619
  }
640
620
 
641
- if (gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0) {
642
- // Negative numbers present in series
643
- const _hasNegsGl = /** @type {any} */ (gl)
644
- _hasNegsGl.hasNegs = true
645
- }
621
+ // Negative numbers present in series; reassigned so an update clears it
622
+ const _hasNegsGl = /** @type {any} */ (gl)
623
+ _hasNegsGl.hasNegs = gl.minY !== Number.MIN_VALUE && Math.abs(gl.minY) !== 0
646
624
 
647
625
  // Check we have a map as series may still to be added/updated.
648
626
  if (w.globals.seriesYAxisReverseMap.length > 0) {
@@ -860,7 +838,7 @@ class CoreUtils {
860
838
  // other series of the same type on the same axis.
861
839
  /**
862
840
  * @param {Record<string, any>} typeSeries
863
- * @param {string[]} typeGroups
841
+ * @param {number[]} typeGroups
864
842
  * @param {string} type
865
843
  * @param {string} chartClass
866
844
  */
@@ -871,7 +849,7 @@ class CoreUtils {
871
849
  if (typeSeries.series.length > 0) {
872
850
  // draw each group separately
873
851
  /**
874
- * @param {string} gn
852
+ * @param {number} gn
875
853
  */
876
854
  typeGroups.forEach((/** @type {any} */ gn) => {
877
855
  /** @type {any[]} */
@@ -883,9 +861,7 @@ class CoreUtils {
883
861
  * @param {number} ii
884
862
  */
885
863
  typeSeries.i.forEach((/** @type {any} */ i, /** @type {any} */ ii) => {
886
- if (
887
- /** @type {Record<string,any>} */ (w.config.series[i]).group === gn
888
- ) {
864
+ if (w.labelData.seriesGroupIndex[i] === gn) {
889
865
  gs.push(typeSeries.series[ii])
890
866
  gi.push(i)
891
867
  }
@@ -97,7 +97,7 @@ function isRawSample(d, name, flatY) {
97
97
  function subtreeTotal(d) {
98
98
  if (!d || typeof d !== 'object') return Utils.parseNumber(d) || 0
99
99
  const v = d.y ?? d.value
100
- if (v != null) return Utils.parseNumber(v) || 0
100
+ if (v != null && v !== '') return Utils.parseNumber(v) || 0
101
101
  if (!Array.isArray(d.children)) return 0
102
102
  return d.children.reduce(
103
103
  (/** @type {number} */ s, /** @type {any} */ c) =>
@@ -1038,22 +1038,21 @@ export default class Data {
1038
1038
  })
1039
1039
 
1040
1040
  this.coreUtils.setSeriesYAxisMappings()
1041
- // At this point, every series that didn't have a user defined group name
1042
- // has been given a name according to the yaxis the series is referenced by.
1043
- // This fits the existing behaviour where all series associated with an axis
1044
- // are defacto presented as a single group. It is now formalised.
1041
+ // A series with no user defined group is grouped by the yaxis that
1042
+ // references it, so all series of an axis form one group. The name is
1043
+ // derived here, never written back onto the caller's series objects.
1044
+ const rev = this.w.globals.seriesYAxisReverseMap
1045
+ const keys = cnf.series.map(
1046
+ (/** @type {any} */ s, /** @type {number} */ i) =>
1047
+ s.group ?? 'apexcharts-axis-' + rev[i],
1048
+ )
1045
1049
  /** @type {any[]} */
1046
1050
  const buckets = []
1047
- /**
1048
- * @param {Record<string, any>} s
1049
- */
1050
- const groups = [
1051
- ...new Set(cnf.series.map((/** @type {any} */ s) => s.group)),
1052
- ]
1051
+ const groups = [...new Set(keys)]
1053
1052
  // Membership is recorded by index: groups may reuse series names.
1054
- this.w.labelData.seriesGroupIndex = cnf.series.map(
1055
- (/** @type {any} */ s, /** @type {number} */ i) => {
1056
- const index = groups.indexOf(s.group)
1053
+ this.w.labelData.seriesGroupIndex = keys.map(
1054
+ (/** @type {any} */ k, /** @type {number} */ i) => {
1055
+ const index = groups.indexOf(k)
1057
1056
  if (!buckets[index]) buckets[index] = []
1058
1057
 
1059
1058
  buckets[index].push(this.w.seriesData.seriesNames[i])
@@ -1477,19 +1476,19 @@ export default class Data {
1477
1476
  if (rootColors && x !== undefined) {
1478
1477
  rootColors[labels.length] = dataPoint.color
1479
1478
  }
1480
- if (x !== undefined && y !== undefined) {
1481
- labels.push(String(x))
1482
- values.push(Utils.parseNumber(y))
1483
- } else if (x !== undefined && Array.isArray(dataPoint.children)) {
1479
+ if (x !== undefined && Array.isArray(dataPoint.children)) {
1484
1480
  // A partition chart (sunburst, icicle) may leave a branch's own
1485
- // value out and let it be the sum of its children. The hierarchy
1486
- // resolver does exactly that in `fillValues`, but that runs long
1487
- // after this parse, and dropping the datum here left the chart with
1488
- // an EMPTY series, which makes the renderer bail before it ever
1489
- // builds the tree: a blank chart and a warning about pie data.
1490
- // So roll the subtree up now, which is the same number.
1481
+ // value out (or null / '') and let it be the sum of its children.
1482
+ // The hierarchy resolver does exactly that in `fillValues`, but
1483
+ // that runs long after this parse, and dropping the datum here left
1484
+ // the chart with an EMPTY series, which makes the renderer bail
1485
+ // before it ever builds the tree: a blank chart and a warning about
1486
+ // pie data. So roll the subtree up now, which is the same number.
1491
1487
  labels.push(String(x))
1492
1488
  values.push(subtreeTotal(dataPoint))
1489
+ } else if (x !== undefined && y !== undefined) {
1490
+ labels.push(String(x))
1491
+ values.push(Utils.parseNumber(y))
1493
1492
  } else {
1494
1493
  console.warn(
1495
1494
  'ApexCharts: Invalid data point format for pie chart. Expected {x, y} format:',
@@ -118,6 +118,12 @@ class DataLabels {
118
118
  drawnextLabel = true
119
119
  }
120
120
 
121
+ // Record the drawn RECT's index, not the point's: a rangeArea series
122
+ // records two rects per point (its start labels, then its end labels).
123
+ if (drawnextLabel) {
124
+ ;(w.globals.lastDrawnDataLabelsIndexes[i] ||= []).push(len + 1)
125
+ }
126
+
121
127
  return {
122
128
  x,
123
129
  y,
@@ -474,12 +480,6 @@ class DataLabels {
474
480
  // Progressive reveal: data labels fade in alongside their markers as the
475
481
  // line's pen-stroke reaches them. Uses the corrected x (post-offset).
476
482
  if (penDrawn(w, i)) applyProgressiveReveal(dataLabelText, x, w)
477
-
478
- if (typeof w.globals.lastDrawnDataLabelsIndexes[i] === 'undefined') {
479
- w.globals.lastDrawnDataLabelsIndexes[i] = []
480
- }
481
-
482
- w.globals.lastDrawnDataLabelsIndexes[i].push(j)
483
483
  }
484
484
 
485
485
  return dataLabelText
@@ -457,6 +457,23 @@ class Graphics {
457
457
  return arc
458
458
  }
459
459
 
460
+ /**
461
+ * stroke.dashArray of a series, shared with the canvas renderer. A plugin
462
+ * may have claimed it: resolved here rather than written into the config,
463
+ * so the caller's own dashing is untouched and there is nothing to restore
464
+ * when the claim goes. See weave/Claims.
465
+ * @param {number} realIndex
466
+ */
467
+ seriesDash(realIndex) {
468
+ const d = this.w.config.stroke.dashArray
469
+ return resolveClaimed(
470
+ this.w,
471
+ 'stroke.dashArray',
472
+ realIndex,
473
+ Array.isArray(d) ? d[realIndex] : d,
474
+ )
475
+ }
476
+
460
477
  /**
461
478
  * @memberof Graphics
462
479
  * @param {Record<string, any>} opts
@@ -610,23 +627,6 @@ class Graphics {
610
627
  }
611
628
  }
612
629
 
613
- const strokeDashArrayOpt = w.config.stroke.dashArray
614
- let strokeDashArray = 0
615
- if (Array.isArray(strokeDashArrayOpt)) {
616
- strokeDashArray = strokeDashArrayOpt[realIndex]
617
- } else {
618
- strokeDashArray = w.config.stroke.dashArray
619
- }
620
- // A plugin may have claimed this series' dash. Resolved here rather than
621
- // written into the config above, so the caller's own dashing is untouched
622
- // and there is nothing to restore when the claim goes. See weave/Claims.
623
- strokeDashArray = resolveClaimed(
624
- w,
625
- 'stroke.dashArray',
626
- realIndex,
627
- strokeDashArray,
628
- )
629
-
630
630
  const el = this.drawPath({
631
631
  d,
632
632
  stroke,
@@ -635,7 +635,7 @@ class Graphics {
635
635
  fillOpacity: 1,
636
636
  classes: className,
637
637
  strokeLinecap,
638
- strokeDashArray,
638
+ strokeDashArray: this.seriesDash(realIndex),
639
639
  })
640
640
 
641
641
  el.attr('index', realIndex)
@@ -935,13 +935,21 @@ class Graphics {
935
935
  return g
936
936
  }
937
937
 
938
- /** @param {{ text: any, maxWidth: any, fontSize: any, fontFamily?: any }} opts */
939
- getTextBasedOnMaxWidth({ text, maxWidth, fontSize, fontFamily }) {
940
- const tRects = this.getTextRects(text, fontSize, fontFamily, '')
941
- const wordWidth = tRects.width / text.length
942
- const wordsBasedOnWidth = Math.floor(maxWidth / wordWidth)
938
+ /** @param {{ text: any, maxWidth: any, fontSize: any, fontFamily?: any, fontWeight?: any }} opts */
939
+ getTextBasedOnMaxWidth({ text, maxWidth, fontSize, fontFamily, fontWeight }) {
940
+ const tRects = this.getTextRects(
941
+ text,
942
+ fontSize,
943
+ fontFamily,
944
+ '',
945
+ true,
946
+ fontWeight,
947
+ )
948
+ // Characters that fit, less the ellipsis. Below zero not even '...'
949
+ // fits (and a negative slice end would keep nearly the whole text).
950
+ const n = Math.floor(maxWidth / (tRects.width / text.length)) - 3
943
951
  if (maxWidth < tRects.width) {
944
- return text.slice(0, wordsBasedOnWidth - 3) + '...'
952
+ return n < 0 ? '' : text.slice(0, n) + '...'
945
953
  }
946
954
  return text
947
955
  }
@@ -984,6 +992,7 @@ class Graphics {
984
992
  maxWidth,
985
993
  fontSize,
986
994
  fontFamily,
995
+ fontWeight,
987
996
  }
988
997
  let elText
989
998
  if (Array.isArray(text)) {
@@ -1226,7 +1235,12 @@ class Graphics {
1226
1235
  if (w.config.states.hover.filter.type !== 'none') {
1227
1236
  if (!w.interact.isTouchDevice) {
1228
1237
  const hoverFilter = w.config.states.hover.filter
1229
- filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value)
1238
+ filters.applyFilter(
1239
+ path,
1240
+ Filters.isSliceChart(w) ? j : i,
1241
+ hoverFilter.type,
1242
+ hoverFilter.value,
1243
+ )
1230
1244
  }
1231
1245
  }
1232
1246
  }
@@ -1267,35 +1281,29 @@ class Graphics {
1267
1281
  if (Filters.hoverOutlineOwnsHoverState(w)) return
1268
1282
 
1269
1283
  if (w.config.states.hover.filter.type !== 'none') {
1270
- filters.getDefaultFilter(path, i)
1284
+ filters.getDefaultFilter(path, Filters.isSliceChart(w) ? j : i)
1271
1285
  }
1272
1286
  }
1273
1287
 
1274
1288
  /**
1275
1289
  * Clear every selected data point (single-select mode): reset the selection
1276
- * array and restore the default filter on all series path/circle/rect nodes.
1277
- * NOTE: preserves the original behavior of passing the clicked series index
1278
- * `i` to getDefaultFilter for every element (not each element's own index).
1279
- * @param {any} filters @param {number} i
1290
+ * array and restore the default filter on each selected node, with its own
1291
+ * series index (dropShadow.enabledOnSeries is per series; a pie slice's
1292
+ * shadow is per slice, j).
1293
+ * @param {any} filters
1280
1294
  */
1281
- _clearAllDataPointSelections(filters, i) {
1295
+ _clearAllDataPointSelections(filters) {
1282
1296
  const w = this.w
1283
1297
  w.interact.selectedDataPoints = []
1284
- const elPaths = w.dom.Paper.find(
1285
- '.apexcharts-series path:not(.apexcharts-decoration-element)',
1286
- )
1287
- const elCircles = w.dom.Paper.find(
1288
- '.apexcharts-series circle:not(.apexcharts-decoration-element), .apexcharts-series rect:not(.apexcharts-decoration-element)',
1289
- )
1290
- /** @param {any[]} els */
1291
- const deSelect = (els) => {
1292
- Array.prototype.forEach.call(els, (/** @type {any} */ el) => {
1298
+ w.dom.Paper.find('.apexcharts-series [selected="true"]').forEach(
1299
+ (/** @type {any} */ el) => {
1293
1300
  el.node.setAttribute('selected', 'false')
1294
- filters.getDefaultFilter(el, i)
1295
- })
1296
- }
1297
- deSelect(elPaths)
1298
- deSelect(elCircles)
1301
+ filters.getDefaultFilter(
1302
+ el,
1303
+ +el.node.getAttribute(Filters.isSliceChart(w) ? 'j' : 'index'),
1304
+ )
1305
+ },
1306
+ )
1299
1307
  }
1300
1308
 
1301
1309
  /**
@@ -1321,7 +1329,7 @@ class Graphics {
1321
1329
  !w.config.states.active.allowMultipleDataPointsSelection &&
1322
1330
  w.interact.selectedDataPoints.length > 0
1323
1331
  ) {
1324
- this._clearAllDataPointSelections(filters, i)
1332
+ this._clearAllDataPointSelections(filters)
1325
1333
  }
1326
1334
 
1327
1335
  path.node.setAttribute('selected', 'true')
@@ -1350,11 +1358,11 @@ class Graphics {
1350
1358
 
1351
1359
  if (selected === 'true') {
1352
1360
  const activeFilter = w.config.states.active.filter
1353
- if (activeFilter !== 'none') {
1361
+ if (activeFilter.type !== 'none') {
1354
1362
  filters.applyFilter(path, i, activeFilter.type, activeFilter.value)
1355
1363
  } else {
1356
1364
  // Reapply the hover filter in case it was removed by `deselect`when there is no active filter and it is not a touch device
1357
- if (w.config.states.hover.filter !== 'none') {
1365
+ if (w.config.states.hover.filter.type !== 'none') {
1358
1366
  if (!w.interact.isTouchDevice) {
1359
1367
  const hoverFilter = w.config.states.hover.filter
1360
1368
  filters.applyFilter(path, i, hoverFilter.type, hoverFilter.value)
@@ -1404,7 +1412,12 @@ class Graphics {
1404
1412
 
1405
1413
  if (!crossfilterClick) {
1406
1414
  const selected = this._togglePointSelection(path, filters, i, j)
1407
- this._applyPointSelectionFilter(path, filters, i, selected)
1415
+ this._applyPointSelectionFilter(
1416
+ path,
1417
+ filters,
1418
+ Filters.isSliceChart(w) ? j : i,
1419
+ selected,
1420
+ )
1408
1421
  }
1409
1422
 
1410
1423
  if (typeof w.config.chart.events.dataPointSelection === 'function') {
@@ -143,8 +143,10 @@ export default class Markers {
143
143
  setGlobalMarkerSize() {
144
144
  const w = this.w
145
145
 
146
+ // A copy: the padding below must not grow (or throw on a frozen) caller
147
+ // array.
146
148
  w.globals.markers.size = Array.isArray(w.config.markers.size)
147
- ? w.config.markers.size
149
+ ? w.config.markers.size.slice()
148
150
  : [w.config.markers.size]
149
151
 
150
152
  if (w.globals.markers.size.length > 0) {
@@ -634,42 +634,38 @@ class Range {
634
634
  gl.barGroups = []
635
635
  gl.lineGroups = []
636
636
  gl.areaGroups = []
637
- /**
638
- * @param {Record<string, any>} s
639
- */
640
- cnf.series.forEach((s) => {
641
- const _s = /** @type {any} */ (s)
642
- const type = _s.type || cnf.chart.type
643
- switch (type) {
637
+ cnf.series.forEach((s, i) => {
638
+ const g = this.w.labelData.seriesGroupIndex[i]
639
+ switch (/** @type {any} */ (s).type || cnf.chart.type) {
644
640
  case 'bar':
645
641
  case 'column':
646
- gl.barGroups.push(_s.group)
642
+ gl.barGroups.push(g)
647
643
  break
648
644
  case 'line':
649
- gl.lineGroups.push(_s.group)
645
+ gl.lineGroups.push(g)
650
646
  break
651
647
  case 'area':
652
- gl.areaGroups.push(_s.group)
648
+ gl.areaGroups.push(g)
653
649
  break
654
650
  }
655
651
  })
656
652
  // Uniquify the group names in each stackable chart type.
657
653
  /**
658
- * @param {string} v
654
+ * @param {number} v
659
655
  * @param {number} i
660
- * @param {string[]} a
656
+ * @param {number[]} a
661
657
  */
662
658
  gl.barGroups = gl.barGroups.filter((v, i, a) => a.indexOf(v) === i)
663
659
  /**
664
- * @param {string} v
660
+ * @param {number} v
665
661
  * @param {number} i
666
- * @param {string[]} a
662
+ * @param {number[]} a
667
663
  */
668
664
  gl.lineGroups = gl.lineGroups.filter((v, i, a) => a.indexOf(v) === i)
669
665
  /**
670
- * @param {string} v
666
+ * @param {number} v
671
667
  * @param {number} i
672
- * @param {string[]} a
668
+ * @param {number[]} a
673
669
  */
674
670
  gl.areaGroups = gl.areaGroups.filter((v, i, a) => a.indexOf(v) === i)
675
671
 
@@ -796,9 +792,10 @@ class Range {
796
792
  ticks = gl.dataPoints - 1
797
793
  }
798
794
  } else if (cnf.xaxis.tickAmount === 'dataPoints') {
799
- if (this.w.seriesData.series.length > 1) {
800
- ticks = this.w.seriesData.series[gl.maxValsInArrayIndex].length - 1
801
- }
795
+ ticks = Math.max(
796
+ 1,
797
+ (this.w.seriesData.series[gl.maxValsInArrayIndex] || []).length - 1,
798
+ )
802
799
  if (this.w.axisFlags.isXNumeric) {
803
800
  const diff = Math.round(gl.maxX - gl.minX)
804
801
  if (diff < 30) {
@@ -877,9 +874,30 @@ class Range {
877
874
  // On its side the chart draws one band per row and one label per
878
875
  // band, so each band is labelled with its own row's x. The evenly
879
876
  // spaced ticks put "Jan 03" against the row that holds Jan 04.
880
- this.w.labelData.labels = /** @type {any} */ (
881
- (this.w.seriesData.seriesX[gl.maxValsInArrayIndex] || []).slice()
882
- )
877
+ // Series that do not share their x values get a band for every x any
878
+ // of them has, in the longest series' direction, and each bar sits in
879
+ // its own x's band (bar/Helpers barRow).
880
+ const rows = (
881
+ this.w.seriesData.seriesX[gl.maxValsInArrayIndex] || []
882
+ ).slice()
883
+ const seen = new Set(rows)
884
+ const n = rows.length
885
+ if (cnf.chart.type === 'bar') {
886
+ this.w.seriesData.seriesX.forEach((s) =>
887
+ s?.forEach((x) => {
888
+ if (x != null && !seen.has(x)) {
889
+ seen.add(x)
890
+ rows.push(x)
891
+ }
892
+ }),
893
+ )
894
+ }
895
+ if (rows.length > n) {
896
+ const dir = rows[0] > rows[n - 1] ? -1 : 1
897
+ rows.sort((a, b) => (a - b) * dir)
898
+ gl.dataPoints = rows.length
899
+ }
900
+ this.w.labelData.labels = /** @type {any} */ (rows)
883
901
  } else if (isXNumeric) {
884
902
  this.w.labelData.labels = /** @type {any} */ (
885
903
  gl.xAxisScale.result.slice()
@@ -1073,10 +1091,9 @@ class Range {
1073
1091
  if (!this.w.seriesData.series.length) return
1074
1092
  const gIdx = this.w.labelData.seriesGroupIndex
1075
1093
  // [positive, negative] sums per stack: the series group (by index, groups
1076
- // may reuse names), then the x value on a numeric axis as stacked columns
1077
- // and lines draw (#4886), else the ordinal (horizontal bars stack by it).
1078
- const byX =
1079
- this.w.axisFlags.isXNumeric && !this.w.config.plotOptions.bar.horizontal
1094
+ // may reuse names), then the x value on a numeric axis as stacked bars and
1095
+ // lines draw (#4886), else the ordinal.
1096
+ const byX = this.w.axisFlags.isXNumeric
1080
1097
  /** @type {Map<string, number[]>} */
1081
1098
  const stacks = new Map()
1082
1099
 
@@ -1108,9 +1125,7 @@ class Range {
1108
1125
 
1109
1126
  const v = this.w.seriesData.series[i][j]
1110
1127
  if (stackSeries && v !== null && Utils.isNumber(v)) {
1111
- v > 0
1112
- ? (st[0] += parseFloat(String(v)) + 0.0001)
1113
- : (st[1] += parseFloat(String(v)))
1128
+ v > 0 ? (st[0] += v * 1.000001) : (st[1] += +v)
1114
1129
  }
1115
1130
  }
1116
1131
  },
@@ -143,7 +143,9 @@ export default class RendererController {
143
143
  return this._activeKind
144
144
  }
145
145
  // The backend was requested/auto-selected but its feature isn't bundled.
146
- if (mode === desired) {
146
+ // resolve() runs every render, so say it once per chart.
147
+ if (mode === desired && !this._warned) {
148
+ this._warned = 1
147
149
  warnMissingFeature(
148
150
  `\`chart.renderer: '${desired}'\``,
149
151
  `renderer-${desired}`,
@@ -152,10 +154,15 @@ export default class RendererController {
152
154
  },
153
155
  )
154
156
  }
155
- } else if (mode === 'canvas' && hasCanvasUnsupportedFeature(this.w)) {
157
+ } else if (
158
+ mode === 'canvas' &&
159
+ !this._warned &&
160
+ hasCanvasUnsupportedFeature(this.w)
161
+ ) {
156
162
  // Explicit canvas, but a configured feature (gradient/pattern/image fill,
157
163
  // or a state color-matrix filter) can't render on canvas yet: 'auto'
158
- // declines silently, explicit 'canvas' says why.
164
+ // declines silently, explicit 'canvas' says why (once).
165
+ this._warned = 1
159
166
  console.warn(
160
167
  `[apexcharts] renderer:"canvas" requested but this chart uses a feature the ` +
161
168
  `canvas renderer does not render yet (gradient/pattern/image fill or a ` +
@@ -163,6 +170,13 @@ export default class RendererController {
163
170
  )
164
171
  }
165
172
 
173
+ // Leaving a non-SVG backend frees it (display list, bitmap); the factory
174
+ // builds a fresh one if the chart crosses back.
175
+ const prev = this._instances[this._activeKind]
176
+ if (prev) {
177
+ prev.destroy()
178
+ delete this._instances[this._activeKind]
179
+ }
166
180
  this._activate('svg', this.svg)
167
181
  return this._activeKind
168
182
  }
@@ -655,6 +655,19 @@ export default class Scales {
655
655
  ;/** @type {any} */ (gl).yAxisScale[index] = []
656
656
  }
657
657
 
658
+ // Zero, a negative or the MIN_VALUE sentinel has no logarithm. The floor
659
+ // was the base, clipping smaller values: drop it to the power of the base
660
+ // at or below the smallest positive value this axis plots.
661
+ if (y.logarithmic && minY <= Number.MIN_VALUE) {
662
+ const s = this.w.seriesData.series
663
+ const map = gl.isMultipleYAxis && gl.seriesYAxisMap[index]
664
+ const b = y.logBase || 10
665
+ const m = (map ? map.map((i) => s[i]) : s)
666
+ .flat()
667
+ .reduce((a, v) => (v > 0 && (!a || v < a) ? v : a), 0)
668
+ minY = m && Math.min(b, b ** Math.floor(Math.log(m) / Math.log(b)))
669
+ }
670
+
658
671
  const range = Math.abs(maxY - minY)
659
672
 
660
673
  // A log scale is degenerate when the domain spans less than one full
@@ -719,15 +732,25 @@ export default class Scales {
719
732
  // no data in the chart. Either all series collapsed or user passed a blank array
720
733
  gl.xAxisScale = this.linearScale(0, 10, 10)
721
734
  } else {
722
- const ticks = gl.xTickAmount
723
-
724
- gl.xAxisScale = this.linearScale(
725
- minX,
726
- maxX,
727
- ticks,
728
- 0,
729
- w.config.xaxis.max === undefined ? w.config.xaxis.stepSize : undefined,
730
- )
735
+ const x = w.config.xaxis
736
+ // a fixed max or a streaming range window wins over the step
737
+ let step = (x.max ?? x.range) === undefined ? x.stepSize : undefined
738
+ // A step fixes the tick count and the axis ends on the last step. One
739
+ // too fine to draw keeps the default count instead.
740
+ const fit = step > 0 && !gl.isBarHorizontal && x.type !== 'datetime'
741
+ if (fit) {
742
+ const n = Math.ceil((maxX - minX) / step - 1e-9)
743
+ n > 1e3 ? (step = undefined) : (gl.xTickAmount = n)
744
+ }
745
+
746
+ let s = this.linearScale(minX, maxX, gl.xTickAmount, 0, step)
747
+ if (fit && step) {
748
+ // linearScale rounds the step, so it can fall short of the data
749
+ while (s.niceMax < maxX)
750
+ s = this.linearScale(minX, maxX, ++gl.xTickAmount, 0, step)
751
+ gl.maxX = s.niceMax
752
+ }
753
+ gl.xAxisScale = s
731
754
  }
732
755
  return gl.xAxisScale
733
756
  }