@gravity-ui/charts 1.51.7 → 1.52.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 (199) hide show
  1. package/dist/cjs/components/ChartInner/useChartInnerHandlers.d.ts +3 -2
  2. package/dist/cjs/components/ChartInner/useChartInnerHandlers.js +1 -3
  3. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +3 -2
  4. package/dist/cjs/components/ChartInner/useDefaultState.d.ts +3 -2
  5. package/dist/cjs/components/index.d.ts +1 -0
  6. package/dist/cjs/components/index.js +1 -0
  7. package/dist/cjs/core/series/plugin.d.ts +47 -2
  8. package/dist/cjs/core/series/types.d.ts +4 -0
  9. package/dist/cjs/core/shapes/area/prepare-data.js +29 -19
  10. package/dist/cjs/core/shapes/area/renderer.d.ts +0 -5
  11. package/dist/cjs/core/shapes/area/renderer.js +0 -75
  12. package/dist/cjs/core/shapes/area/types.d.ts +2 -8
  13. package/dist/cjs/core/shapes/bar-x/prepare-data.js +18 -7
  14. package/dist/cjs/core/shapes/bar-x/renderer.d.ts +0 -1
  15. package/dist/cjs/core/shapes/bar-x/renderer.js +0 -18
  16. package/dist/cjs/core/shapes/bar-x/types.d.ts +2 -1
  17. package/dist/cjs/core/shapes/bar-y/get-tooltip-data.js +4 -2
  18. package/dist/cjs/core/shapes/bar-y/prepare-data.js +8 -2
  19. package/dist/cjs/core/shapes/funnel/prepare-data.js +121 -68
  20. package/dist/cjs/core/shapes/heatmap/prepare-data.js +11 -2
  21. package/dist/cjs/core/shapes/line/prepare-data.js +27 -17
  22. package/dist/cjs/core/shapes/line/renderer.d.ts +0 -5
  23. package/dist/cjs/core/shapes/line/renderer.js +0 -75
  24. package/dist/cjs/core/shapes/line/types.d.ts +2 -8
  25. package/dist/cjs/core/shapes/marker.d.ts +30 -0
  26. package/dist/cjs/core/shapes/marker.js +68 -0
  27. package/dist/cjs/core/shapes/pie/prepare-data.js +24 -9
  28. package/dist/cjs/core/shapes/radar/prepare-data.js +3 -0
  29. package/dist/cjs/core/shapes/sankey/prepare-data.js +10 -1
  30. package/dist/cjs/core/shapes/scatter/prepare-data.js +8 -1
  31. package/dist/cjs/core/shapes/scatter/renderer.js +3 -2
  32. package/dist/cjs/core/shapes/scatter/types.d.ts +1 -1
  33. package/dist/cjs/core/shapes/treemap/prepare-data.js +9 -1
  34. package/dist/cjs/core/shapes/types.d.ts +35 -0
  35. package/dist/cjs/core/shapes/waterfall/prepare-data.js +5 -2
  36. package/dist/cjs/core/shapes/x-range/prepare-data.js +7 -2
  37. package/dist/cjs/core/types/chart/base.d.ts +22 -2
  38. package/dist/cjs/core/types/chart/funnel.d.ts +25 -1
  39. package/dist/cjs/core/types/chart/tooltip.d.ts +6 -1
  40. package/dist/cjs/core/utils/data-labels.d.ts +34 -0
  41. package/dist/cjs/core/utils/data-labels.js +26 -0
  42. package/dist/cjs/core/utils/get-closest-data.d.ts +2 -2
  43. package/dist/cjs/core/utils/get-closest-data.js +14 -34
  44. package/dist/cjs/core/utils/tooltip-helpers.d.ts +16 -0
  45. package/dist/cjs/core/utils/tooltip-helpers.js +12 -0
  46. package/dist/cjs/hooks/useShapes/AnnotationLayer.d.ts +9 -0
  47. package/dist/cjs/hooks/useShapes/AnnotationLayer.js +17 -0
  48. package/dist/cjs/hooks/useShapes/HoverMarkerLayer.d.ts +10 -0
  49. package/dist/cjs/hooks/useShapes/HoverMarkerLayer.js +22 -0
  50. package/dist/cjs/hooks/useShapes/MarkerLayer.d.ts +7 -0
  51. package/dist/cjs/hooks/useShapes/MarkerLayer.js +12 -0
  52. package/dist/cjs/hooks/useShapes/SeriesShapes.d.ts +18 -0
  53. package/dist/cjs/hooks/useShapes/SeriesShapes.js +32 -0
  54. package/dist/cjs/hooks/useShapes/index.d.ts +5 -18
  55. package/dist/cjs/hooks/useShapes/index.js +39 -229
  56. package/dist/cjs/index.d.ts +0 -1
  57. package/dist/cjs/index.js +0 -1
  58. package/dist/cjs/plugins/area/index.js +42 -0
  59. package/dist/cjs/plugins/bar-x/index.js +42 -0
  60. package/dist/cjs/plugins/bar-y/index.js +26 -0
  61. package/dist/cjs/plugins/funnel/index.js +18 -0
  62. package/dist/cjs/plugins/funnel/prepare.js +17 -12
  63. package/dist/cjs/plugins/heatmap/index.js +23 -0
  64. package/dist/cjs/plugins/line/index.js +28 -0
  65. package/dist/cjs/plugins/pie/index.js +18 -0
  66. package/dist/cjs/plugins/radar/index.js +18 -0
  67. package/dist/cjs/plugins/sankey/index.js +18 -0
  68. package/dist/cjs/plugins/scatter/index.js +26 -0
  69. package/dist/cjs/plugins/treemap/index.js +18 -0
  70. package/dist/cjs/plugins/waterfall/index.js +39 -0
  71. package/dist/cjs/plugins/x-range/index.js +25 -0
  72. package/dist/cjs/setup-jsdom.d.ts +0 -1
  73. package/dist/cjs/setup-jsdom.js +1 -1
  74. package/dist/esm/components/ChartInner/useChartInnerHandlers.d.ts +3 -2
  75. package/dist/esm/components/ChartInner/useChartInnerHandlers.js +1 -3
  76. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +3 -2
  77. package/dist/esm/components/ChartInner/useDefaultState.d.ts +3 -2
  78. package/dist/esm/components/index.d.ts +1 -0
  79. package/dist/esm/components/index.js +1 -0
  80. package/dist/esm/core/series/plugin.d.ts +47 -2
  81. package/dist/esm/core/series/types.d.ts +4 -0
  82. package/dist/esm/core/shapes/area/prepare-data.js +29 -19
  83. package/dist/esm/core/shapes/area/renderer.d.ts +0 -5
  84. package/dist/esm/core/shapes/area/renderer.js +0 -75
  85. package/dist/esm/core/shapes/area/types.d.ts +2 -8
  86. package/dist/esm/core/shapes/bar-x/prepare-data.js +18 -7
  87. package/dist/esm/core/shapes/bar-x/renderer.d.ts +0 -1
  88. package/dist/esm/core/shapes/bar-x/renderer.js +0 -18
  89. package/dist/esm/core/shapes/bar-x/types.d.ts +2 -1
  90. package/dist/esm/core/shapes/bar-y/get-tooltip-data.js +4 -2
  91. package/dist/esm/core/shapes/bar-y/prepare-data.js +8 -2
  92. package/dist/esm/core/shapes/funnel/prepare-data.js +121 -68
  93. package/dist/esm/core/shapes/heatmap/prepare-data.js +11 -2
  94. package/dist/esm/core/shapes/line/prepare-data.js +27 -17
  95. package/dist/esm/core/shapes/line/renderer.d.ts +0 -5
  96. package/dist/esm/core/shapes/line/renderer.js +0 -75
  97. package/dist/esm/core/shapes/line/types.d.ts +2 -8
  98. package/dist/esm/core/shapes/marker.d.ts +30 -0
  99. package/dist/esm/core/shapes/marker.js +68 -0
  100. package/dist/esm/core/shapes/pie/prepare-data.js +24 -9
  101. package/dist/esm/core/shapes/radar/prepare-data.js +3 -0
  102. package/dist/esm/core/shapes/sankey/prepare-data.js +10 -1
  103. package/dist/esm/core/shapes/scatter/prepare-data.js +8 -1
  104. package/dist/esm/core/shapes/scatter/renderer.js +3 -2
  105. package/dist/esm/core/shapes/scatter/types.d.ts +1 -1
  106. package/dist/esm/core/shapes/treemap/prepare-data.js +9 -1
  107. package/dist/esm/core/shapes/types.d.ts +35 -0
  108. package/dist/esm/core/shapes/waterfall/prepare-data.js +5 -2
  109. package/dist/esm/core/shapes/x-range/prepare-data.js +7 -2
  110. package/dist/esm/core/types/chart/base.d.ts +22 -2
  111. package/dist/esm/core/types/chart/funnel.d.ts +25 -1
  112. package/dist/esm/core/types/chart/tooltip.d.ts +6 -1
  113. package/dist/esm/core/utils/data-labels.d.ts +34 -0
  114. package/dist/esm/core/utils/data-labels.js +26 -0
  115. package/dist/esm/core/utils/get-closest-data.d.ts +2 -2
  116. package/dist/esm/core/utils/get-closest-data.js +14 -34
  117. package/dist/esm/core/utils/tooltip-helpers.d.ts +16 -0
  118. package/dist/esm/core/utils/tooltip-helpers.js +12 -0
  119. package/dist/esm/hooks/useShapes/AnnotationLayer.d.ts +9 -0
  120. package/dist/esm/hooks/useShapes/AnnotationLayer.js +17 -0
  121. package/dist/esm/hooks/useShapes/HoverMarkerLayer.d.ts +10 -0
  122. package/dist/esm/hooks/useShapes/HoverMarkerLayer.js +22 -0
  123. package/dist/esm/hooks/useShapes/MarkerLayer.d.ts +7 -0
  124. package/dist/esm/hooks/useShapes/MarkerLayer.js +12 -0
  125. package/dist/esm/hooks/useShapes/SeriesShapes.d.ts +18 -0
  126. package/dist/esm/hooks/useShapes/SeriesShapes.js +32 -0
  127. package/dist/esm/hooks/useShapes/index.d.ts +5 -18
  128. package/dist/esm/hooks/useShapes/index.js +39 -229
  129. package/dist/esm/index.d.ts +0 -1
  130. package/dist/esm/index.js +0 -1
  131. package/dist/esm/plugins/area/index.js +42 -0
  132. package/dist/esm/plugins/bar-x/index.js +42 -0
  133. package/dist/esm/plugins/bar-y/index.js +26 -0
  134. package/dist/esm/plugins/funnel/index.js +18 -0
  135. package/dist/esm/plugins/funnel/prepare.js +17 -12
  136. package/dist/esm/plugins/heatmap/index.js +23 -0
  137. package/dist/esm/plugins/line/index.js +28 -0
  138. package/dist/esm/plugins/pie/index.js +18 -0
  139. package/dist/esm/plugins/radar/index.js +18 -0
  140. package/dist/esm/plugins/sankey/index.js +18 -0
  141. package/dist/esm/plugins/scatter/index.js +26 -0
  142. package/dist/esm/plugins/treemap/index.js +18 -0
  143. package/dist/esm/plugins/waterfall/index.js +39 -0
  144. package/dist/esm/plugins/x-range/index.js +25 -0
  145. package/dist/esm/setup-jsdom.d.ts +0 -1
  146. package/dist/esm/setup-jsdom.js +1 -1
  147. package/package.json +2 -3
  148. package/dist/cjs/hooks/useShapes/area/index.d.ts +0 -15
  149. package/dist/cjs/hooks/useShapes/area/index.js +0 -52
  150. package/dist/cjs/hooks/useShapes/bar-x/index.d.ts +0 -16
  151. package/dist/cjs/hooks/useShapes/bar-x/index.js +0 -45
  152. package/dist/cjs/hooks/useShapes/bar-y/index.d.ts +0 -13
  153. package/dist/cjs/hooks/useShapes/bar-y/index.js +0 -19
  154. package/dist/cjs/hooks/useShapes/funnel/index.d.ts +0 -13
  155. package/dist/cjs/hooks/useShapes/funnel/index.js +0 -21
  156. package/dist/cjs/hooks/useShapes/heatmap/index.d.ts +0 -13
  157. package/dist/cjs/hooks/useShapes/heatmap/index.js +0 -20
  158. package/dist/cjs/hooks/useShapes/line/index.d.ts +0 -15
  159. package/dist/cjs/hooks/useShapes/line/index.js +0 -38
  160. package/dist/cjs/hooks/useShapes/pie/index.d.ts +0 -12
  161. package/dist/cjs/hooks/useShapes/pie/index.js +0 -20
  162. package/dist/cjs/hooks/useShapes/radar/index.d.ts +0 -12
  163. package/dist/cjs/hooks/useShapes/radar/index.js +0 -19
  164. package/dist/cjs/hooks/useShapes/sankey/index.d.ts +0 -12
  165. package/dist/cjs/hooks/useShapes/sankey/index.js +0 -18
  166. package/dist/cjs/hooks/useShapes/scatter/index.d.ts +0 -13
  167. package/dist/cjs/hooks/useShapes/scatter/index.js +0 -22
  168. package/dist/cjs/hooks/useShapes/treemap/index.d.ts +0 -12
  169. package/dist/cjs/hooks/useShapes/treemap/index.js +0 -18
  170. package/dist/cjs/hooks/useShapes/waterfall/index.d.ts +0 -14
  171. package/dist/cjs/hooks/useShapes/waterfall/index.js +0 -31
  172. package/dist/cjs/hooks/useShapes/x-range/index.d.ts +0 -14
  173. package/dist/cjs/hooks/useShapes/x-range/index.js +0 -20
  174. package/dist/esm/hooks/useShapes/area/index.d.ts +0 -15
  175. package/dist/esm/hooks/useShapes/area/index.js +0 -52
  176. package/dist/esm/hooks/useShapes/bar-x/index.d.ts +0 -16
  177. package/dist/esm/hooks/useShapes/bar-x/index.js +0 -45
  178. package/dist/esm/hooks/useShapes/bar-y/index.d.ts +0 -13
  179. package/dist/esm/hooks/useShapes/bar-y/index.js +0 -19
  180. package/dist/esm/hooks/useShapes/funnel/index.d.ts +0 -13
  181. package/dist/esm/hooks/useShapes/funnel/index.js +0 -21
  182. package/dist/esm/hooks/useShapes/heatmap/index.d.ts +0 -13
  183. package/dist/esm/hooks/useShapes/heatmap/index.js +0 -20
  184. package/dist/esm/hooks/useShapes/line/index.d.ts +0 -15
  185. package/dist/esm/hooks/useShapes/line/index.js +0 -38
  186. package/dist/esm/hooks/useShapes/pie/index.d.ts +0 -12
  187. package/dist/esm/hooks/useShapes/pie/index.js +0 -20
  188. package/dist/esm/hooks/useShapes/radar/index.d.ts +0 -12
  189. package/dist/esm/hooks/useShapes/radar/index.js +0 -19
  190. package/dist/esm/hooks/useShapes/sankey/index.d.ts +0 -12
  191. package/dist/esm/hooks/useShapes/sankey/index.js +0 -18
  192. package/dist/esm/hooks/useShapes/scatter/index.d.ts +0 -13
  193. package/dist/esm/hooks/useShapes/scatter/index.js +0 -22
  194. package/dist/esm/hooks/useShapes/treemap/index.d.ts +0 -12
  195. package/dist/esm/hooks/useShapes/treemap/index.js +0 -18
  196. package/dist/esm/hooks/useShapes/waterfall/index.d.ts +0 -14
  197. package/dist/esm/hooks/useShapes/waterfall/index.js +0 -31
  198. package/dist/esm/hooks/useShapes/x-range/index.d.ts +0 -14
  199. package/dist/esm/hooks/useShapes/x-range/index.js +0 -20
@@ -2,7 +2,7 @@ import { group, max } from 'd3-array';
2
2
  import { arc, line as lineGenerator } from 'd3-shape';
3
3
  import merge from 'lodash/merge';
4
4
  import { DEFAULT_DATALABELS_STYLE } from '../../constants';
5
- import { calculateNumericProperty, getLabelsSize, getLeftPosition, getTextSizeFn, isLabelsOverlapping, } from '../../utils';
5
+ import { calculateNumericProperty, getLabelsSize, getLeftPosition, getTextSizeFn, isLabelsOverlapping, isPointDataLabelEnabled, shouldPrepareSeriesDataLabels, } from '../../utils';
6
6
  import { getFormattedValue } from '../../utils/format';
7
7
  import { getCurveFactory, getInscribedAngle, pieGenerator } from './utils';
8
8
  const FULL_CIRCLE = Math.PI * 2;
@@ -32,7 +32,7 @@ export function preparePieData(args) {
32
32
  const minRadius = typeof propsMinRadius === 'number' ? propsMinRadius : maxRadius * 0.3;
33
33
  const groupedPieSeries = group(preparedSeries, (pieSeries) => pieSeries.stackId);
34
34
  const dataLabelsStyle = merge({}, DEFAULT_DATALABELS_STYLE, (_b = (_a = preparedSeries[0]) === null || _a === void 0 ? void 0 : _a.dataLabels) === null || _b === void 0 ? void 0 : _b.style);
35
- const prepareItem = ({ stackId, items, labels, }) => {
35
+ const prepareItem = ({ stackId, items, labels, hasDataLabels, }) => {
36
36
  var _a;
37
37
  const series = items[0];
38
38
  const { center, borderWidth, borderColor, borderRadius, dataLabels } = series;
@@ -54,6 +54,9 @@ export function preparePieData(args) {
54
54
  opacity: series.states.hover.halo.opacity,
55
55
  size: series.states.hover.halo.size,
56
56
  },
57
+ markers: [],
58
+ getHoverMarkers: () => [],
59
+ annotations: [],
57
60
  };
58
61
  const labelMaxHeight = (_a = max(Object.values(labels).map((l) => { var _a, _b; return (_b = (_a = l.size) === null || _a === void 0 ? void 0 : _a.height) !== null && _b !== void 0 ? _b : 0; }))) !== null && _a !== void 0 ? _a : 0;
59
62
  const segments = items.reduce((acc, item) => {
@@ -62,7 +65,7 @@ export function preparePieData(args) {
62
65
  return acc;
63
66
  }
64
67
  let maxSegmentRadius = maxRadius;
65
- if (dataLabels.enabled) {
68
+ if (hasDataLabels) {
66
69
  maxSegmentRadius -=
67
70
  dataLabels.distance + dataLabels.connectorPadding + labelMaxHeight;
68
71
  }
@@ -82,16 +85,19 @@ export function preparePieData(args) {
82
85
  data.segments = pieGenerator(segments);
83
86
  return data;
84
87
  };
85
- const getLabels = async ({ series }) => {
88
+ const getLabels = async ({ series, hasDataLabels, }) => {
86
89
  var _a;
87
90
  const { dataLabels } = series[0];
88
- if (!dataLabels.enabled) {
91
+ if (!hasDataLabels) {
89
92
  return {};
90
93
  }
91
94
  const getTextSize = getTextSizeFn({ style: dataLabelsStyle });
92
95
  const acc = {};
93
96
  for (let i = 0; i < series.length; i++) {
94
97
  const d = series[i];
98
+ if (!isPointDataLabelEnabled({ data: d.data, series: d })) {
99
+ continue;
100
+ }
95
101
  const text = getFormattedValue(Object.assign({ value: (_a = d.data.label) !== null && _a !== void 0 ? _a : d.data.value }, d.dataLabels));
96
102
  let labelWidth = 0;
97
103
  let labelHeight = 0;
@@ -120,12 +126,12 @@ export function preparePieData(args) {
120
126
  return acc;
121
127
  };
122
128
  const prepareLabels = (prepareLabelsArgs) => {
123
- const { data, series, labels: labelsData, allowOverlow = true } = prepareLabelsArgs;
129
+ const { data, series, labels: labelsData, hasDataLabels, allowOverlow = true, } = prepareLabelsArgs;
124
130
  const { dataLabels } = series[0];
125
131
  const labels = [];
126
132
  const htmlLabels = [];
127
133
  const connectors = [];
128
- if (!dataLabels.enabled) {
134
+ if (!hasDataLabels) {
129
135
  return { labels, htmlLabels, connectors };
130
136
  }
131
137
  const shouldUseHtml = dataLabels.html;
@@ -150,6 +156,9 @@ export function preparePieData(args) {
150
156
  let shouldStopLabelPlacement = false;
151
157
  series.forEach((d, index) => {
152
158
  var _a, _b;
159
+ if (!isPointDataLabelEnabled({ data: d.data, series: d })) {
160
+ return;
161
+ }
153
162
  const prevLabel = labels[labels.length - 1];
154
163
  const { text = '', size: labelSize } = labelsData[d.id];
155
164
  const labelWidth = (_a = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _a !== void 0 ? _a : 0;
@@ -287,12 +296,17 @@ export function preparePieData(args) {
287
296
  };
288
297
  return Promise.all(Array.from(groupedPieSeries).map(async ([stackId, items]) => {
289
298
  var _a;
290
- const seriesLabels = await getLabels({ series: items });
291
- const data = prepareItem({ stackId, items, labels: seriesLabels });
299
+ const hasDataLabels = shouldPrepareSeriesDataLabels({
300
+ dataLabels: items[0].dataLabels,
301
+ data: items.map((it) => it.data),
302
+ });
303
+ const seriesLabels = await getLabels({ series: items, hasDataLabels });
304
+ const data = prepareItem({ stackId, items, labels: seriesLabels, hasDataLabels });
292
305
  const preparedLabels = prepareLabels({
293
306
  data,
294
307
  labels: seriesLabels,
295
308
  series: items,
309
+ hasDataLabels,
296
310
  });
297
311
  let maxLeftRightFreeSpace = Infinity;
298
312
  let labelsOverflow = 0;
@@ -370,6 +384,7 @@ export function preparePieData(args) {
370
384
  data,
371
385
  series: items,
372
386
  labels: seriesLabels,
387
+ hasDataLabels,
373
388
  allowOverlow: false,
374
389
  });
375
390
  if (typeof ((_a = items[0]) === null || _a === void 0 ? void 0 : _a.innerRadius) !== 'undefined') {
@@ -26,6 +26,9 @@ export async function prepareRadarData(args) {
26
26
  htmlLabels: [],
27
27
  grid: [],
28
28
  cursor: preparedSeries[0].cursor,
29
+ markers: [],
30
+ getHoverMarkers: () => [],
31
+ annotations: [],
29
32
  };
30
33
  const categories = preparedSeries[0].categories;
31
34
  const axisStrokeColor = 'var(--g-color-line-generic)';
@@ -70,5 +70,14 @@ export function prepareSankeyData(args) {
70
70
  });
71
71
  dataLabels.push(...labels);
72
72
  }
73
- return { series, nodes: sankeyNodes, links: sankeyLinks, htmlLabels, labels: dataLabels };
73
+ return {
74
+ series,
75
+ nodes: sankeyNodes,
76
+ links: sankeyLinks,
77
+ htmlLabels,
78
+ labels: dataLabels,
79
+ markers: [],
80
+ getHoverMarkers: () => [],
81
+ annotations: [],
82
+ };
74
83
  }
@@ -112,5 +112,12 @@ export async function prepareScatterData(args) {
112
112
  }
113
113
  }
114
114
  }
115
- return { markers, svgLabels: allSvgLabels, htmlLabels: allHtmlLabels };
115
+ return {
116
+ scatterData: markers,
117
+ svgLabels: allSvgLabels,
118
+ htmlLabels: allHtmlLabels,
119
+ markers: [],
120
+ getHoverMarkers: () => [],
121
+ annotations: [],
122
+ };
116
123
  }
@@ -6,20 +6,21 @@ import { setActiveState, shapeKey } from '../../shapes/utils';
6
6
  import { renderDataLabels } from '../data-labels';
7
7
  const b = block('scatter');
8
8
  export function renderScatter(elements, preparedData, seriesOptions, dispatcher) {
9
+ var _a;
9
10
  const svgElement = select(elements.plot);
10
11
  const hoverOptions = get(seriesOptions, 'scatter.states.hover');
11
12
  const inactiveOptions = get(seriesOptions, 'scatter.states.inactive');
12
13
  svgElement.selectAll('*').remove();
13
14
  const selection = svgElement
14
15
  .selectAll('path')
15
- .data(preparedData.markers, shapeKey)
16
+ .data(preparedData.scatterData, shapeKey)
16
17
  .join('g')
17
18
  .call(renderMarker)
18
19
  .attr('opacity', (d) => d.point.opacity)
19
20
  .attr('cursor', (d) => d.point.series.cursor);
20
21
  renderDataLabels({
21
22
  container: svgElement,
22
- data: preparedData.svgLabels,
23
+ data: (_a = preparedData.svgLabels) !== null && _a !== void 0 ? _a : [],
23
24
  className: b('label'),
24
25
  });
25
26
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
@@ -18,7 +18,7 @@ export type MarkerData = {
18
18
  };
19
19
  export type PreparedScatterData = MarkerData;
20
20
  export type PreparedScatterShapeData = {
21
- markers: PreparedScatterData[];
21
+ scatterData: PreparedScatterData[];
22
22
  svgLabels: LabelData[];
23
23
  } & SeriesShapeData;
24
24
  export {};
@@ -160,5 +160,13 @@ export async function prepareTreemapData(args) {
160
160
  labelData = labels;
161
161
  }
162
162
  }
163
- return { labelData, leaves, series, htmlLabels };
163
+ return {
164
+ labelData,
165
+ leaves,
166
+ series,
167
+ htmlLabels,
168
+ markers: [],
169
+ getHoverMarkers: () => [],
170
+ annotations: [],
171
+ };
164
172
  }
@@ -1,4 +1,39 @@
1
1
  import type { HtmlItem } from '../../types';
2
+ import type { SymbolType } from '../constants';
3
+ import type { AnnotationAnchor } from '../series/types';
4
+ export interface MarkerItem {
5
+ cx: number;
6
+ cy: number;
7
+ radius: number;
8
+ symbolType: `${SymbolType}`;
9
+ fill: string;
10
+ stroke: string;
11
+ strokeWidth: number;
12
+ opacity: number;
13
+ active: boolean;
14
+ clipped: boolean;
15
+ series: {
16
+ id: string;
17
+ };
18
+ data: unknown;
19
+ }
2
20
  export interface SeriesShapeData {
3
21
  htmlLabels: HtmlItem[];
22
+ markers: MarkerItem[];
23
+ annotations: AnnotationAnchor[];
24
+ getHoverMarkers(hoveredData: unknown[]): MarkerItem[];
25
+ }
26
+ export interface TooltipItemData {
27
+ type?: string;
28
+ series?: {
29
+ type?: string;
30
+ tooltip?: {
31
+ enabled?: boolean;
32
+ };
33
+ };
34
+ point?: {
35
+ series?: {
36
+ type?: string;
37
+ };
38
+ };
4
39
  }
@@ -2,11 +2,11 @@ import get from 'lodash/get';
2
2
  import sortBy from 'lodash/sortBy';
3
3
  import { MIN_BAR_GAP, MIN_BAR_WIDTH } from '../../shapes/bar-constants';
4
4
  import { getXValue, getYValue } from '../../shapes/utils';
5
- import { getLabelsSize } from '../../utils';
5
+ import { getLabelsSize, isPointDataLabelEnabled } from '../../utils';
6
6
  import { getFormattedValue } from '../../utils/format';
7
7
  async function getLabelData(d, plotHeight) {
8
8
  var _a, _b;
9
- if (!d.series.dataLabels.enabled) {
9
+ if (!isPointDataLabelEnabled({ data: d.data, series: d.series })) {
10
10
  return undefined;
11
11
  }
12
12
  const labelValue = (_b = (_a = d.data.label) !== null && _a !== void 0 ? _a : d.data.y) !== null && _b !== void 0 ? _b : d.subTotal;
@@ -145,6 +145,9 @@ export const prepareWaterfallData = async (args) => {
145
145
  series: item.series,
146
146
  subTotal: totalValue,
147
147
  htmlLabels: [],
148
+ markers: [],
149
+ getHoverMarkers: () => [],
150
+ annotations: [],
148
151
  };
149
152
  preparedData.label = await getLabelData(preparedData, plotHeight);
150
153
  result.push(preparedData);
@@ -1,6 +1,6 @@
1
1
  import get from 'lodash/get';
2
2
  import { MIN_BAR_WIDTH } from '../../shapes/bar-constants';
3
- import { getDataCategoryValue, getLabelsSize, getTextSizeFn, getTextWithElipsis } from '../../utils';
3
+ import { getDataCategoryValue, getLabelsSize, getTextSizeFn, getTextWithElipsis, isPointDataLabelEnabled, } from '../../utils';
4
4
  import { getBandSize } from '../../utils/band-size';
5
5
  import { getFormattedValue } from '../../utils/format';
6
6
  const DEFAULT_BAR_PADDING = 0.2;
@@ -84,6 +84,9 @@ export async function prepareXRangeData(args) {
84
84
  series: s,
85
85
  htmlLabels: [],
86
86
  svgLabels: [],
87
+ markers: [],
88
+ getHoverMarkers: () => [],
89
+ annotations: [],
87
90
  });
88
91
  });
89
92
  });
@@ -91,7 +94,9 @@ export async function prepareXRangeData(args) {
91
94
  for (let i = 0; i < result.length; i++) {
92
95
  const item = result[i];
93
96
  const { dataLabels } = item.series;
94
- if (!dataLabels.enabled || item.data.label === null || isRangeSlider) {
97
+ if (isRangeSlider ||
98
+ item.data.label === null ||
99
+ !isPointDataLabelEnabled({ data: item.data, series: item.series })) {
95
100
  continue;
96
101
  }
97
102
  const content = getFormattedValue(Object.assign({ value: item.data.label }, dataLabels));
@@ -93,14 +93,34 @@ export interface BaseSeries {
93
93
  };
94
94
  }
95
95
  export interface BaseSeriesData<T = MeaningfulAny> {
96
+ /** Individual color for the data chunk (point in scatter, segment in pie, bar etc) */
97
+ color?: string;
96
98
  /**
97
99
  * A reserved subspace to store options and values for customized functionality
98
100
  *
99
101
  * Here you can add additional data for your own event callbacks and formatter callbacks
100
102
  */
101
103
  custom?: T;
102
- /** Individual color for the data chunk (point in scatter, segment in pie, bar etc) */
103
- color?: string;
104
+ /** Per-point overrides for the series data label. */
105
+ dataLabels?: {
106
+ /**
107
+ * Per-point override of `series.dataLabels.enabled`. The point-level value takes precedence:
108
+ * `true` shows the label even when series-level labels are disabled,
109
+ * `false` hides the label even when series-level labels are enabled.
110
+ * @default series.dataLabels.enabled
111
+ */
112
+ enabled?: boolean;
113
+ };
114
+ /** Per-point overrides for the tooltip behavior. */
115
+ tooltip?: {
116
+ /**
117
+ * Per-point override of `series.tooltip.enabled`. The point-level value takes precedence:
118
+ * `true` shows the point in the tooltip even when the series is hidden from the tooltip,
119
+ * `false` hides the point even when the series is shown.
120
+ * @default series.tooltip.enabled
121
+ */
122
+ enabled?: boolean;
123
+ };
104
124
  }
105
125
  export interface BaseSeriesLegend extends ChartLegendItem {
106
126
  /**
@@ -62,8 +62,32 @@ export interface FunnelSeries<T = MeaningfulAny> extends Omit<BaseSeries, 'dataL
62
62
  areaOpacity?: number;
63
63
  };
64
64
  dataLabels?: Omit<BaseDataLabels, 'allowOverlap'> & {
65
- /** Horizontal alignment of the data labels. */
65
+ /**
66
+ * Horizontal alignment of the data labels.
67
+ * @default 'center'
68
+ */
66
69
  align?: 'left' | 'center' | 'right';
70
+ /**
71
+ * Whether to align the data label inside or outside the shape.
72
+ * @default false
73
+ */
74
+ inside?: boolean;
75
+ /**
76
+ * Whether to shrink the funnel shapes to reserve space for outside labels.
77
+ * When true, the plot area is inset on the labelled side so labels do not overlap segments.
78
+ * When false, no space is reserved and labels are clamped to the plot area boundary if they overflow.
79
+ * Only relevant when `inside` is false.
80
+ * @default true
81
+ */
82
+ reserveSpace?: boolean;
83
+ /**
84
+ * The reference area for label alignment. Only relevant when `inside` is false.
85
+ *
86
+ * - `'shape'` - aligns relative to the data shape (e.g., funnel section).
87
+ * - `'plot'` - aligns relative to the chart plot area boundaries.
88
+ * @default 'plot'
89
+ */
90
+ anchor?: 'plot' | 'shape';
67
91
  };
68
92
  /** Individual series legend options. Has higher priority than legend options in widget data */
69
93
  legend?: ChartLegendItem & {
@@ -6,7 +6,7 @@ import type { AreaSeries, AreaSeriesData } from './area';
6
6
  import type { AxisPlotBand, AxisPlotLine, AxisPlotShape, ChartXAxis, ChartYAxis } from './axis';
7
7
  import type { BarXSeries, BarXSeriesData } from './bar-x';
8
8
  import type { BarYSeries, BarYSeriesData } from './bar-y';
9
- import type { ValueFormat } from './base';
9
+ import type { BaseSeries, ValueFormat } from './base';
10
10
  import type { FunnelSeries, FunnelSeriesData } from './funnel';
11
11
  import type { HeatmapSeries, HeatmapSeriesData } from './heatmap';
12
12
  import type { LineSeries, LineSeriesData } from './line';
@@ -31,6 +31,7 @@ export interface TooltipDataChunkPie<T = MeaningfulAny> {
31
31
  type: PieSeries['type'];
32
32
  id: string;
33
33
  name: string;
34
+ tooltip?: BaseSeries['tooltip'];
34
35
  };
35
36
  }
36
37
  export interface TooltipDataChunkScatter<T = MeaningfulAny> {
@@ -39,6 +40,7 @@ export interface TooltipDataChunkScatter<T = MeaningfulAny> {
39
40
  type: ScatterSeries['type'];
40
41
  id: string;
41
42
  name: string;
43
+ tooltip?: BaseSeries['tooltip'];
42
44
  };
43
45
  }
44
46
  export interface TooltipDataChunkLine<T = MeaningfulAny> {
@@ -47,6 +49,7 @@ export interface TooltipDataChunkLine<T = MeaningfulAny> {
47
49
  type: LineSeries['type'];
48
50
  id: string;
49
51
  name: string;
52
+ tooltip?: BaseSeries['tooltip'];
50
53
  };
51
54
  closest?: boolean;
52
55
  }
@@ -56,6 +59,7 @@ export interface TooltipDataChunkArea<T = MeaningfulAny> {
56
59
  type: AreaSeries['type'];
57
60
  id: string;
58
61
  name: string;
62
+ tooltip?: BaseSeries['tooltip'];
59
63
  };
60
64
  }
61
65
  export interface TooltipDataChunkTreemap<T = MeaningfulAny> {
@@ -88,6 +92,7 @@ export interface TooltipDataChunkFunnel<T = MeaningfulAny> {
88
92
  type: FunnelSeries['type'];
89
93
  id: string;
90
94
  name: string;
95
+ tooltip?: BaseSeries['tooltip'];
91
96
  };
92
97
  }
93
98
  export interface TooltipDataChunkXRange<T = MeaningfulAny> {
@@ -7,12 +7,46 @@ type PointLabelSeries = {
7
7
  html: boolean;
8
8
  padding: number;
9
9
  format?: ValueFormat;
10
+ enabled?: boolean;
10
11
  };
11
12
  };
13
+ /**
14
+ * Resolves the effective dataLabels visibility for a point: point-level setting wins
15
+ * over series-level. Both default to `true` when unset.
16
+ */
17
+ export declare function isPointDataLabelEnabled(args: {
18
+ data?: {
19
+ dataLabels?: {
20
+ enabled?: boolean;
21
+ };
22
+ } | null;
23
+ series?: {
24
+ dataLabels?: {
25
+ enabled?: boolean;
26
+ };
27
+ } | null;
28
+ }): boolean;
29
+ /**
30
+ * Returns `true` if the series should run its dataLabels prep pipeline:
31
+ * either series-level is enabled, or at least one point opts in via override.
32
+ */
33
+ export declare function shouldPrepareSeriesDataLabels(series: {
34
+ dataLabels?: {
35
+ enabled?: boolean;
36
+ };
37
+ data?: ReadonlyArray<{
38
+ dataLabels?: {
39
+ enabled?: boolean;
40
+ };
41
+ }>;
42
+ }): boolean;
12
43
  type LabelPoint = {
13
44
  x: number | null;
14
45
  y: number | null;
15
46
  data: {
47
+ dataLabels?: {
48
+ enabled?: boolean;
49
+ };
16
50
  label?: string | number | null;
17
51
  y?: string | number | null;
18
52
  };
@@ -1,5 +1,28 @@
1
1
  import { getFormattedValue } from './format';
2
2
  import { getLabelsSize, getTextSizeFn } from './text';
3
+ /**
4
+ * Resolves the effective dataLabels visibility for a point: point-level setting wins
5
+ * over series-level. Both default to `true` when unset.
6
+ */
7
+ export function isPointDataLabelEnabled(args) {
8
+ var _a, _b, _c, _d, _e;
9
+ const pointEnabled = (_b = (_a = args.data) === null || _a === void 0 ? void 0 : _a.dataLabels) === null || _b === void 0 ? void 0 : _b.enabled;
10
+ if (pointEnabled !== undefined) {
11
+ return pointEnabled;
12
+ }
13
+ return (_e = (_d = (_c = args.series) === null || _c === void 0 ? void 0 : _c.dataLabels) === null || _d === void 0 ? void 0 : _d.enabled) !== null && _e !== void 0 ? _e : true;
14
+ }
15
+ /**
16
+ * Returns `true` if the series should run its dataLabels prep pipeline:
17
+ * either series-level is enabled, or at least one point opts in via override.
18
+ */
19
+ export function shouldPrepareSeriesDataLabels(series) {
20
+ var _a, _b;
21
+ if ((_a = series.dataLabels) === null || _a === void 0 ? void 0 : _a.enabled) {
22
+ return true;
23
+ }
24
+ return Boolean((_b = series.data) === null || _b === void 0 ? void 0 : _b.some((d) => { var _a; return ((_a = d.dataLabels) === null || _a === void 0 ? void 0 : _a.enabled) === true; }));
25
+ }
3
26
  /**
4
27
  * Shared "above-point" dataLabels algorithm used by line, area, and scatter series.
5
28
  *
@@ -25,6 +48,9 @@ export async function preparePointDataLabels({ series, points, xMax, yAxisTop, i
25
48
  if (point.y === null || point.x === null || isOutsideBounds(point.x, point.y)) {
26
49
  continue;
27
50
  }
51
+ if (!isPointDataLabelEnabled({ data: point.data, series })) {
52
+ continue;
53
+ }
28
54
  const text = getFormattedValue(Object.assign({ value: (_a = point.data.label) !== null && _a !== void 0 ? _a : point.data.y }, series.dataLabels));
29
55
  const anchorY = point.y - anchorYOffset;
30
56
  if (series.dataLabels.html) {
@@ -1,8 +1,8 @@
1
- import type { ShapeData } from '../../hooks/useShapes';
2
1
  import type { TooltipDataChunk } from '../../types';
2
+ import type { TooltipItemData } from '../shapes/types';
3
3
  type GetClosestPointsArgs = {
4
4
  position: [number, number];
5
- shapesData: ShapeData[];
5
+ shapesData: TooltipItemData[];
6
6
  boundsHeight: number;
7
7
  boundsWidth: number;
8
8
  };
@@ -1,34 +1,7 @@
1
1
  import get from 'lodash/get';
2
2
  import groupBy from 'lodash/groupBy';
3
- import { getTooltipData as areaGetTooltipData } from '../shapes/area/get-tooltip-data';
4
- import { getTooltipData as barXGetTooltipData } from '../shapes/bar-x/get-tooltip-data';
5
- import { getTooltipData as barYGetTooltipData } from '../shapes/bar-y/get-tooltip-data';
6
- import { getTooltipData as funnelGetTooltipData } from '../shapes/funnel/get-tooltip-data';
7
- import { getTooltipData as heatmapGetTooltipData } from '../shapes/heatmap/get-tooltip-data';
8
- import { getTooltipData as lineGetTooltipData } from '../shapes/line/get-tooltip-data';
9
- import { getTooltipData as pieGetTooltipData } from '../shapes/pie/get-tooltip-data';
10
- import { getTooltipData as radarGetTooltipData } from '../shapes/radar/get-tooltip-data';
11
- import { getTooltipData as sankeyGetTooltipData } from '../shapes/sankey/get-tooltip-data';
12
- import { getTooltipData as scatterGetTooltipData } from '../shapes/scatter/get-tooltip-data';
13
- import { getTooltipData as treemapGetTooltipData } from '../shapes/treemap/get-tooltip-data';
14
- import { getTooltipData as waterfallGetTooltipData } from '../shapes/waterfall/get-tooltip-data';
15
- import { getTooltipData as xRangeGetTooltipData } from '../shapes/x-range/get-tooltip-data';
16
- import { getClosestPointsByXValue } from './tooltip-helpers';
17
- const tooltipFnByType = {
18
- line: lineGetTooltipData,
19
- area: areaGetTooltipData,
20
- 'bar-x': barXGetTooltipData,
21
- 'bar-y': barYGetTooltipData,
22
- waterfall: waterfallGetTooltipData,
23
- scatter: scatterGetTooltipData,
24
- pie: pieGetTooltipData,
25
- treemap: treemapGetTooltipData,
26
- heatmap: heatmapGetTooltipData,
27
- sankey: sankeyGetTooltipData,
28
- radar: radarGetTooltipData,
29
- funnel: funnelGetTooltipData,
30
- 'x-range': xRangeGetTooltipData,
31
- };
3
+ import { getSeriesPlugin } from '../series/seriesRegistry';
4
+ import { getClosestPointsByXValue, isPointTooltipEnabled } from './tooltip-helpers';
32
5
  function getSeriesType(shapeData) {
33
6
  return (get(shapeData, 'series.type') ||
34
7
  get(shapeData, 'point.series.type') ||
@@ -41,19 +14,26 @@ export function getClosestPoints(args) {
41
14
  const xLookupPoints = [];
42
15
  const groups = groupBy(shapesData, getSeriesType);
43
16
  for (const [seriesType, list] of Object.entries(groups)) {
44
- const fn = tooltipFnByType[seriesType];
45
- if (!fn) {
17
+ let plugin;
18
+ try {
19
+ plugin = getSeriesPlugin(seriesType);
20
+ }
21
+ catch (_a) {
46
22
  continue;
47
23
  }
48
- const { chunks, xLookupPoints: seriesXLookupPoints } = fn({
24
+ const { chunks, xLookupPoints: seriesXLookupPoints } = plugin.getTooltipData({
49
25
  data: list,
50
26
  position,
51
27
  boundsWidth,
52
28
  boundsHeight,
53
29
  });
54
- result.push(...chunks);
30
+ result.push(...chunks.filter((c) => isPointTooltipEnabled(c)));
55
31
  if (seriesXLookupPoints) {
56
- xLookupPoints.push(...seriesXLookupPoints);
32
+ for (const p of seriesXLookupPoints) {
33
+ if (isPointTooltipEnabled(p)) {
34
+ xLookupPoints.push(p);
35
+ }
36
+ }
57
37
  }
58
38
  }
59
39
  if (xLookupPoints.length) {
@@ -30,6 +30,22 @@ export declare function getClosestPointsByXValue(x: number, y: number, points: S
30
30
  subTotal?: number;
31
31
  sourceX?: number;
32
32
  }[];
33
+ /**
34
+ * Resolves the effective tooltip visibility for a point: point-level setting wins
35
+ * over series-level. Both default to `true` when unset.
36
+ */
37
+ export declare function isPointTooltipEnabled(args: {
38
+ data?: {
39
+ tooltip?: {
40
+ enabled?: boolean;
41
+ };
42
+ } | null;
43
+ series?: {
44
+ tooltip?: {
45
+ enabled?: boolean;
46
+ };
47
+ } | null;
48
+ }): boolean;
33
49
  export declare function isInsidePath(args: {
34
50
  path: string;
35
51
  point: [number, number];
@@ -50,6 +50,18 @@ export function getClosestPointsByXValue(x, y, points) {
50
50
  const closestYIndex = getClosestYIndex(closestPoints, y);
51
51
  return closestPoints.map((p, i) => (Object.assign(Object.assign({}, p), { closest: i === closestYIndex })));
52
52
  }
53
+ /**
54
+ * Resolves the effective tooltip visibility for a point: point-level setting wins
55
+ * over series-level. Both default to `true` when unset.
56
+ */
57
+ export function isPointTooltipEnabled(args) {
58
+ var _a, _b, _c, _d, _e;
59
+ const pointEnabled = (_b = (_a = args.data) === null || _a === void 0 ? void 0 : _a.tooltip) === null || _b === void 0 ? void 0 : _b.enabled;
60
+ if (pointEnabled !== undefined) {
61
+ return pointEnabled;
62
+ }
63
+ return (_e = (_d = (_c = args.series) === null || _c === void 0 ? void 0 : _c.tooltip) === null || _d === void 0 ? void 0 : _d.enabled) !== null && _e !== void 0 ? _e : true;
64
+ }
53
65
  export function isInsidePath(args) {
54
66
  const { path, point, width, height, strokeWidth } = args;
55
67
  const canvas = document.createElement('canvas');
@@ -0,0 +1,9 @@
1
+ import React from 'react';
2
+ import type { AnnotationAnchor } from '../../core/series/types';
3
+ interface Props {
4
+ annotations: AnnotationAnchor[];
5
+ boundsWidth: number;
6
+ boundsHeight: number;
7
+ }
8
+ export declare const AnnotationLayer: ({ annotations, boundsWidth, boundsHeight }: Props) => React.JSX.Element;
9
+ export {};
@@ -0,0 +1,17 @@
1
+ import React from 'react';
2
+ import { select } from 'd3-selection';
3
+ import { renderAnnotations } from '../../core/shapes/annotation';
4
+ export const AnnotationLayer = ({ annotations, boundsWidth, boundsHeight }) => {
5
+ const ref = React.useRef(null);
6
+ React.useEffect(() => {
7
+ if (!ref.current)
8
+ return;
9
+ renderAnnotations({
10
+ anchors: annotations,
11
+ container: select(ref.current),
12
+ plotWidth: boundsWidth,
13
+ plotHeight: boundsHeight,
14
+ });
15
+ }, [annotations, boundsWidth, boundsHeight]);
16
+ return React.createElement("g", { ref: ref });
17
+ };