@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
@@ -4,16 +4,11 @@ import { area as areaGenerator, line as lineGenerator } from 'd3-shape';
4
4
  import get from 'lodash/get';
5
5
  import { block } from '../../../utils';
6
6
  import { filterOverlappingLabels } from '../../utils';
7
- import { renderAnnotations } from '../annotation';
8
7
  import { renderDataLabels } from '../data-labels';
9
- import { getMarkerHaloVisibility, getMarkerVisibility, renderMarker, selectMarkerHalo, selectMarkerSymbol, setMarker, } from '../marker';
10
8
  import { setActiveState } from '../utils';
11
9
  const b = block('area');
12
10
  export function renderArea(elements, preparedData, seriesOptions, allowOverlapDataLabels, dispatcher) {
13
11
  const plotSvgElement = select(elements.plot);
14
- const markersSvgElement = select(elements.markers);
15
- const hoverMarkersSvgElement = select(elements.hoverMarkers);
16
- const annotationsSvgElement = select(elements.annotations);
17
12
  const hoverOptions = get(seriesOptions, 'area.states.hover');
18
13
  const inactiveOptions = get(seriesOptions, 'area.states.inactive');
19
14
  const line = lineGenerator()
@@ -21,7 +16,6 @@ export function renderArea(elements, preparedData, seriesOptions, allowOverlapDa
21
16
  .defined((d) => d.y !== null && !d.hiddenInLine)
22
17
  .y((d) => d.y);
23
18
  plotSvgElement.selectAll('*').remove();
24
- markersSvgElement.selectAll('*').remove();
25
19
  const shapeSelection = plotSvgElement
26
20
  .selectAll('shape')
27
21
  .data(preparedData)
@@ -59,23 +53,10 @@ export function renderArea(elements, preparedData, seriesOptions, allowOverlapDa
59
53
  data: dataLabels,
60
54
  className: b('label'),
61
55
  });
62
- const markers = preparedData.reduce((acc, d) => acc.concat(d.markers), []);
63
- const markerSelection = markersSvgElement
64
- .selectAll('marker')
65
- .data(markers)
66
- .join('g')
67
- .call(renderMarker);
68
- renderAnnotations({
69
- anchors: preparedData.flatMap((d) => d.annotations),
70
- container: annotationsSvgElement,
71
- plotHeight: elements.boundsHeight,
72
- plotWidth: elements.boundsWidth,
73
- });
74
56
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
75
57
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
76
58
  function handleShapeHover(data) {
77
59
  const selected = (data === null || data === void 0 ? void 0 : data.filter((d) => d.series.type === 'area')) || [];
78
- const selectedDataItems = selected.map((d) => d.data);
79
60
  const selectedSeriesIds = selected.map((d) => { var _a; return (_a = d.series) === null || _a === void 0 ? void 0 : _a.id; });
80
61
  shapeSelection.datum((d, index, list) => {
81
62
  var _a;
@@ -111,62 +92,6 @@ export function renderArea(elements, preparedData, seriesOptions, allowOverlapDa
111
92
  datum: d,
112
93
  });
113
94
  });
114
- markerSelection.datum((d, index, list) => {
115
- const elementSelection = select(list[index]);
116
- const hovered = Boolean(hoverEnabled && selectedDataItems.includes(d.point.data));
117
- if (d.hovered !== hovered) {
118
- d.hovered = hovered;
119
- elementSelection.attr('visibility', getMarkerVisibility(d));
120
- selectMarkerHalo(elementSelection).attr('visibility', getMarkerHaloVisibility);
121
- selectMarkerSymbol(elementSelection).call(setMarker, hovered ? 'hover' : 'normal');
122
- }
123
- if (d.point.series.marker.states.normal.enabled) {
124
- const isActive = Boolean(!inactiveEnabled ||
125
- !selectedSeriesIds.length ||
126
- selectedSeriesIds.includes(d.point.series.id));
127
- setActiveState({
128
- element: list[index],
129
- state: inactiveOptions,
130
- active: isActive,
131
- datum: d,
132
- });
133
- }
134
- return d;
135
- });
136
- hoverMarkersSvgElement.selectAll('*').remove();
137
- if (hoverEnabled && selected.length > 0) {
138
- const hoverOnlyMarkers = [];
139
- for (const chunk of selected) {
140
- const seriesData = preparedData.find((pd) => pd.id === chunk.series.id);
141
- if (!seriesData) {
142
- continue;
143
- }
144
- const { series } = seriesData;
145
- if (series.marker.states.normal.enabled || !series.marker.states.hover.enabled) {
146
- continue;
147
- }
148
- const point = seriesData.points.find((p) => p.data === chunk.data);
149
- if (!point || point.y === null) {
150
- continue;
151
- }
152
- hoverOnlyMarkers.push({
153
- point: point,
154
- active: true,
155
- hovered: true,
156
- clipped: false,
157
- });
158
- }
159
- if (hoverOnlyMarkers.length > 0) {
160
- hoverMarkersSvgElement
161
- .selectAll('g')
162
- .data(hoverOnlyMarkers)
163
- .join('g')
164
- .call(renderMarker)
165
- .each((_d, i, nodes) => {
166
- selectMarkerSymbol(select(nodes[i])).call(setMarker, 'hover');
167
- });
168
- }
169
- }
170
95
  }
171
96
  dispatcher === null || dispatcher === void 0 ? void 0 : dispatcher.on('hover-shape.area', handleShapeHover);
172
97
  return () => {
@@ -1,6 +1,6 @@
1
1
  import type { AreaSeriesData, LabelData } from '../../../types';
2
2
  import type { AnnotationAnchor, PreparedAnnotation, PreparedAreaSeries } from '../../series/types';
3
- import type { SeriesShapeData } from '../types';
3
+ import type { MarkerItem, SeriesShapeData } from '../types';
4
4
  export type PointData = {
5
5
  annotation?: PreparedAnnotation;
6
6
  color?: string;
@@ -14,17 +14,11 @@ export type PointData = {
14
14
  export type MarkerPointData = PointData & {
15
15
  y: number;
16
16
  };
17
- export type MarkerData = {
18
- point: MarkerPointData;
19
- active: boolean;
20
- hovered: boolean;
21
- clipped: boolean;
22
- };
23
17
  export type PreparedAreaData = {
24
18
  annotations: AnnotationAnchor[];
25
19
  id: string;
26
20
  points: PointData[];
27
- markers: MarkerData[];
21
+ markers: MarkerItem[];
28
22
  color: string;
29
23
  opacity: number;
30
24
  width: number;
@@ -3,15 +3,12 @@ import get from 'lodash/get';
3
3
  import { prepareAnnotation } from '../../series/prepare-annotation';
4
4
  import { getSeriesStackId } from '../../series/utils';
5
5
  import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../../shapes/bar-constants';
6
- import { getDataCategoryValue, getLabelsSize, getTextSizeFn } from '../../utils';
6
+ import { getDataCategoryValue, getLabelsSize, getTextSizeFn, isPointDataLabelEnabled, } from '../../utils';
7
7
  import { getBandSize } from '../../utils/band-size';
8
8
  import { getFormattedValue } from '../../utils/format';
9
9
  const isSeriesDataValid = (d) => d.y !== null;
10
10
  async function getLabelData(d, xMax) {
11
11
  var _a;
12
- if (!d.series.dataLabels.enabled) {
13
- return {};
14
- }
15
12
  const text = getFormattedValue(Object.assign({ value: (_a = d.data.label) !== null && _a !== void 0 ? _a : d.data.y }, d.series.dataLabels));
16
13
  const style = d.series.dataLabels.style;
17
14
  if (d.series.dataLabels.html) {
@@ -209,6 +206,7 @@ export const prepareBarXData = async (args) => {
209
206
  optionsPopup: (_j = (_h = seriesOptions['bar-x']) === null || _h === void 0 ? void 0 : _h.annotation) === null || _j === void 0 ? void 0 : _j.popup,
210
207
  })
211
208
  : undefined,
209
+ annotations: [],
212
210
  x,
213
211
  y: barPositionY,
214
212
  width: rectWidth,
@@ -220,6 +218,8 @@ export const prepareBarXData = async (args) => {
220
218
  htmlLabels: [],
221
219
  svgLabels: [],
222
220
  isLastStackItem,
221
+ markers: [],
222
+ getHoverMarkers: () => [],
223
223
  };
224
224
  stackItems.push(barData);
225
225
  if (yDataValue > 0) {
@@ -243,6 +243,17 @@ export const prepareBarXData = async (args) => {
243
243
  }
244
244
  }
245
245
  }
246
+ for (const barData of result) {
247
+ if (barData.annotation) {
248
+ barData.annotations = [
249
+ {
250
+ annotation: barData.annotation,
251
+ x: barData.x + barData.width / 2,
252
+ y: barData.y,
253
+ },
254
+ ];
255
+ }
256
+ }
246
257
  const [_xMin, xRangeMax] = xScale.range();
247
258
  const xMax = xRangeMax;
248
259
  for (let i = 0; i < result.length; i++) {
@@ -252,9 +263,9 @@ export const prepareBarXData = async (args) => {
252
263
  barData.y + barData.height <= 0 ||
253
264
  barData.y >= plotHeight;
254
265
  const isZeroValue = ((_k = barData.data.y) !== null && _k !== void 0 ? _k : 0) === 0;
255
- if (barData.series.dataLabels.enabled &&
256
- !isRangeSlider &&
257
- (!isBarOutsideBounds || isZeroValue)) {
266
+ if (!isRangeSlider &&
267
+ (!isBarOutsideBounds || isZeroValue) &&
268
+ isPointDataLabelEnabled({ data: barData.data, series: barData.series })) {
258
269
  const { svgLabel, htmlLabel } = await getLabelData(barData, xMax);
259
270
  if (svgLabel) {
260
271
  barData.svgLabels.push(svgLabel);
@@ -3,7 +3,6 @@ import type { PreparedSeriesOptions } from '../../series/types';
3
3
  import type { PreparedBarXData } from './types';
4
4
  export declare function renderBarX(elements: {
5
5
  plot: SVGGElement;
6
- annotations: SVGGElement;
7
6
  boundsWidth: number;
8
7
  boundsHeight: number;
9
8
  }, preparedData: PreparedBarXData[], seriesOptions: PreparedSeriesOptions, allowOverlapDataLabels: boolean, dispatcher?: Dispatch<object>): () => void;
@@ -3,13 +3,11 @@ import { select } from 'd3-selection';
3
3
  import get from 'lodash/get';
4
4
  import { block } from '../../../utils';
5
5
  import { filterOverlappingLabels } from '../../utils';
6
- import { renderAnnotations } from '../annotation';
7
6
  import { renderDataLabels } from '../data-labels';
8
7
  import { getRectPath } from '../utils';
9
8
  const b = block('bar-x');
10
9
  export function renderBarX(elements, preparedData, seriesOptions, allowOverlapDataLabels, dispatcher) {
11
10
  const svgElement = select(elements.plot);
12
- const annotationsSvgElement = select(elements.annotations);
13
11
  const hoverOptions = get(seriesOptions, 'bar-x.states.hover');
14
12
  const inactiveOptions = get(seriesOptions, 'bar-x.states.inactive');
15
13
  svgElement.selectAll('*').remove();
@@ -43,22 +41,6 @@ export function renderBarX(elements, preparedData, seriesOptions, allowOverlapDa
43
41
  data: dataLabels,
44
42
  className: b('label'),
45
43
  });
46
- const annotationAnchors = [];
47
- for (const d of preparedData) {
48
- if (d.annotation) {
49
- annotationAnchors.push({
50
- annotation: d.annotation,
51
- x: d.x + d.width / 2,
52
- y: d.y,
53
- });
54
- }
55
- }
56
- renderAnnotations({
57
- anchors: annotationAnchors,
58
- container: annotationsSvgElement,
59
- plotHeight: elements.boundsHeight,
60
- plotWidth: elements.boundsWidth,
61
- });
62
44
  function handleShapeHover(data) {
63
45
  const hoverEnabled = hoverOptions === null || hoverOptions === void 0 ? void 0 : hoverOptions.enabled;
64
46
  const inactiveEnabled = inactiveOptions === null || inactiveOptions === void 0 ? void 0 : inactiveOptions.enabled;
@@ -1,8 +1,9 @@
1
1
  import type { LabelData, TooltipDataChunkBarX } from '../../../types';
2
- import type { PreparedAnnotation, PreparedBarXSeries } from '../../series/types';
2
+ import type { AnnotationAnchor, PreparedAnnotation, PreparedBarXSeries } from '../../series/types';
3
3
  import type { SeriesShapeData } from '../types';
4
4
  export type PreparedBarXData = Omit<TooltipDataChunkBarX, 'series'> & {
5
5
  annotation?: PreparedAnnotation;
6
+ annotations: AnnotationAnchor[];
6
7
  x: number;
7
8
  y: number;
8
9
  width: number;
@@ -1,15 +1,17 @@
1
1
  import { bisector, sort } from 'd3-array';
2
+ import { isPointTooltipEnabled } from '../../utils/tooltip-helpers';
2
3
  export function getTooltipData(args) {
3
4
  var _a, _b;
4
5
  const { data, position } = args;
5
6
  const [pointerX, pointerY] = position;
6
- const sorted = sort(data, (p) => p.y);
7
+ const visibleData = data.filter((p) => isPointTooltipEnabled({ data: p.data, series: p.series }));
8
+ const sorted = sort(visibleData, (p) => p.y);
7
9
  const closestYIndex = bisector((p) => p.y + p.height / 2).center(sorted, pointerY);
8
10
  const closestYPoint = sorted[closestYIndex];
9
11
  if (!closestYPoint) {
10
12
  return { chunks: [] };
11
13
  }
12
- const selectedPoints = data.filter((p) => p.data.y === closestYPoint.data.y);
14
+ const selectedPoints = visibleData.filter((p) => p.data.y === closestYPoint.data.y);
13
15
  const closestPoints = sort(selectedPoints.filter((p) => p.y === closestYPoint.y), (p) => p.x);
14
16
  let closestPointXValue;
15
17
  const lastPoint = closestPoints[closestPoints.length - 1];
@@ -1,6 +1,6 @@
1
1
  import { ascending, descending, sort } from 'd3-array';
2
2
  import get from 'lodash/get';
3
- import { filterOverlappingLabels, getHtmlLabelConstraintedPosition, getLabelsSize, getSvgLabelConstraintedPosition, getTextSizeFn, } from '../../utils';
3
+ import { filterOverlappingLabels, getHtmlLabelConstraintedPosition, getLabelsSize, getSvgLabelConstraintedPosition, getTextSizeFn, isPointDataLabelEnabled, } from '../../utils';
4
4
  import { getBarYLayout, groupBarYDataByYValue } from '../../utils/bar-y';
5
5
  import { getFormattedValue } from '../../utils/format';
6
6
  export async function prepareBarYData(args) {
@@ -14,6 +14,9 @@ export async function prepareBarYData(args) {
14
14
  shapes: [],
15
15
  labels: [],
16
16
  htmlLabels: [],
17
+ markers: [],
18
+ getHoverMarkers: () => [],
19
+ annotations: [],
17
20
  };
18
21
  }
19
22
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
@@ -139,7 +142,7 @@ export async function prepareBarYData(args) {
139
142
  for (let i = 0; i < result.length; i++) {
140
143
  const prepared = result[i];
141
144
  const dataLabels = prepared.series.dataLabels;
142
- if (dataLabels.enabled) {
145
+ if (isPointDataLabelEnabled({ data: prepared.data, series: prepared.series })) {
143
146
  const data = prepared.data;
144
147
  const content = getFormattedValue(Object.assign({ value: (_a = data.label) !== null && _a !== void 0 ? _a : data.x }, dataLabels));
145
148
  const y = prepared.y + prepared.height / 2;
@@ -209,5 +212,8 @@ export async function prepareBarYData(args) {
209
212
  shapes: result,
210
213
  labels,
211
214
  htmlLabels,
215
+ markers: [],
216
+ getHoverMarkers: () => [],
217
+ annotations: [],
212
218
  };
213
219
  }
@@ -1,5 +1,5 @@
1
1
  import { path } from 'd3-path';
2
- import { calculateNumericProperty, getFormattedValue, getLabelsSize, getTextSizeFn, } from '../../utils';
2
+ import { calculateNumericProperty, getFormattedValue, getLabelsSize, getTextSizeFn, isPointDataLabelEnabled, } from '../../utils';
3
3
  function getLineConnectorPaths(args) {
4
4
  const { points } = args;
5
5
  const leftPath = path();
@@ -19,7 +19,7 @@ function getAreaConnectorPath(args) {
19
19
  return p;
20
20
  }
21
21
  export async function prepareFunnelData(args) {
22
- var _a, _b, _c, _d, _e;
22
+ var _a, _b, _c, _d;
23
23
  const { series, boundsWidth, boundsHeight } = args;
24
24
  const items = [];
25
25
  const svgLabels = [];
@@ -33,75 +33,59 @@ export async function prepareFunnelData(args) {
33
33
  })) !== null && _b !== void 0 ? _b : 0;
34
34
  const itemHeight = (boundsHeight - connectorHeight * (series.length - 1)) / series.length;
35
35
  const getTextSize = getTextSizeFn({ style: series[0].dataLabels.style });
36
- const getSegmentY = (index) => {
37
- return index * (itemHeight + connectorHeight);
38
- };
39
- let segmentLeftOffset = 0;
40
- let segmentRightOffset = 0;
36
+ const getSegmentY = (index) => index * (itemHeight + connectorHeight);
37
+ // measure labels and accumulate max outside-label widths per side.
38
+ let rawLeftOffset = 0;
39
+ let rawRightOffset = 0;
40
+ const labelInfos = [];
41
41
  for (let index = 0; index < series.length; index++) {
42
42
  const s = series[index];
43
- if (s.dataLabels.enabled) {
44
- const d = s.data;
45
- const labelContent = (_c = d.label) !== null && _c !== void 0 ? _c : getFormattedValue({ value: d.value, format: s.dataLabels.format });
46
- const { width, height, hangingOffset } = s.dataLabels.html
47
- ? await getLabelsSize({
48
- labels: [labelContent],
49
- style: s.dataLabels.style,
50
- html: true,
51
- }).then((size) => ({
52
- width: size.maxWidth,
53
- height: size.maxHeight,
54
- hangingOffset: 0,
55
- }))
56
- : await getTextSize(labelContent);
57
- let x;
58
- switch (s.dataLabels.align) {
59
- case 'left': {
60
- x = 0;
61
- segmentLeftOffset = Math.max(segmentLeftOffset, width);
62
- break;
63
- }
64
- case 'right': {
65
- x = boundsWidth - width;
66
- segmentRightOffset = Math.max(segmentRightOffset, width);
67
- break;
68
- }
69
- case 'center': {
70
- x = boundsWidth / 2 - width / 2;
71
- break;
72
- }
73
- }
74
- const y = getSegmentY(index) + itemHeight / 2 - height / 2 + hangingOffset;
75
- if (s.dataLabels.html) {
76
- htmlLabels.push({
77
- x,
78
- y,
79
- content: labelContent,
80
- size: { width, height },
81
- style: s.dataLabels.style,
82
- });
43
+ if (!isPointDataLabelEnabled({ data: s.data, series: s })) {
44
+ labelInfos.push(null);
45
+ continue;
46
+ }
47
+ const d = s.data;
48
+ const labelContent = (_c = d.label) !== null && _c !== void 0 ? _c : getFormattedValue({ value: d.value, format: s.dataLabels.format });
49
+ const { width, height, hangingOffset } = s.dataLabels.html
50
+ ? await getLabelsSize({
51
+ labels: [labelContent],
52
+ style: s.dataLabels.style,
53
+ html: true,
54
+ }).then((size) => ({
55
+ width: size.maxWidth,
56
+ height: size.maxHeight,
57
+ hangingOffset: 0,
58
+ }))
59
+ : await getTextSize(labelContent);
60
+ labelInfos.push({ text: labelContent, width, height, hangingOffset, series: s });
61
+ const { inside, align, padding } = s.dataLabels;
62
+ if (!inside) {
63
+ // Minimum offset so this label stays within the plot boundary.
64
+ // Accounts for the fact that narrower segments are already indented from the edge.
65
+ const ratio = s.data.value / maxValue;
66
+ const minOffset = (2 * (width + padding) - boundsWidth * (1 - ratio)) / (1 + ratio);
67
+ if (align === 'left') {
68
+ rawLeftOffset = Math.max(rawLeftOffset, minOffset);
83
69
  }
84
- else {
85
- svgLabels.push({
86
- x,
87
- y,
88
- text: labelContent,
89
- style: s.dataLabels.style,
90
- size: { width, height, hangingOffset },
91
- textAnchor: 'start',
92
- series: s,
93
- });
70
+ else if (align === 'right') {
71
+ rawRightOffset = Math.max(rawRightOffset, minOffset);
94
72
  }
95
73
  }
96
74
  }
75
+ // reserveSpace=true → inset only the labelled side so labels don't overlap segments.
76
+ // reserveSpace=false → no inset; labels overlap segments.
77
+ const { reserveSpace } = series[0].dataLabels;
78
+ const segmentLeftOffset = reserveSpace ? rawLeftOffset : 0;
79
+ const segmentRightOffset = reserveSpace ? rawRightOffset : 0;
80
+ // compute shapes and label positions in a single pass.
81
+ // centerX is constant across all segments — hoist it out of the loop.
97
82
  const segmentMaxWidth = boundsWidth - segmentLeftOffset - segmentRightOffset;
98
- const isTrapezoid = ((_d = series[0]) === null || _d === void 0 ? void 0 : _d.shape) === 'trapezoid';
83
+ const isTrapezoid = series[0].shape === 'trapezoid';
84
+ const centerX = segmentLeftOffset + segmentMaxWidth / 2;
99
85
  const getItemWidth = (index) => (segmentMaxWidth * series[index].data.value) / maxValue;
100
86
  for (let index = 0; index < series.length; index++) {
101
87
  const s = series[index];
102
- const d = s.data;
103
88
  const itemWidth = getItemWidth(index);
104
- const centerX = segmentLeftOffset + segmentMaxWidth / 2;
105
89
  const segmentY = getSegmentY(index);
106
90
  const isLastSegment = index === series.length - 1;
107
91
  const bottomWidth = isTrapezoid && !isLastSegment ? getItemWidth(index + 1) : itemWidth;
@@ -111,7 +95,7 @@ export async function prepareFunnelData(args) {
111
95
  [centerX + bottomWidth / 2, segmentY + itemHeight],
112
96
  [centerX - bottomWidth / 2, segmentY + itemHeight],
113
97
  ];
114
- const funnelSegment = {
98
+ const item = {
115
99
  x: centerX - itemWidth / 2,
116
100
  y: segmentY,
117
101
  width: itemWidth,
@@ -119,22 +103,22 @@ export async function prepareFunnelData(args) {
119
103
  points,
120
104
  color: s.color,
121
105
  series: s,
122
- data: d,
106
+ data: s.data,
123
107
  borderColor: '',
124
108
  borderWidth: 0,
125
109
  cursor: s.cursor,
126
110
  };
127
- items.push(funnelSegment);
111
+ items.push(item);
128
112
  const prevSeries = series[index - 1];
129
113
  const prevItem = items[index - 1];
130
- if (prevSeries && prevItem && ((_e = prevSeries.connectors) === null || _e === void 0 ? void 0 : _e.enabled)) {
114
+ if (prevSeries && prevItem && ((_d = prevSeries.connectors) === null || _d === void 0 ? void 0 : _d.enabled)) {
131
115
  // Use the actual bottom corners of the previous segment (points[3]/[2]) so that
132
116
  // trapezoid segments (whose bottom edge differs from the top edge) are handled correctly.
133
117
  const connectorPoints = [
134
118
  prevItem.points[3],
135
119
  prevItem.points[2],
136
- funnelSegment.points[1],
137
- funnelSegment.points[0],
120
+ item.points[1],
121
+ item.points[0],
138
122
  ];
139
123
  connectors.push({
140
124
  linePath: getLineConnectorPaths({ points: connectorPoints }),
@@ -147,13 +131,82 @@ export async function prepareFunnelData(args) {
147
131
  dashStyle: prevSeries.connectors.lineDashStyle,
148
132
  });
149
133
  }
134
+ const info = labelInfos[index];
135
+ if (!info)
136
+ continue;
137
+ const { text, width, height, hangingOffset } = info;
138
+ const { anchor, inside, padding } = s.dataLabels;
139
+ const y = segmentY + itemHeight / 2 - height / 2 + hangingOffset;
140
+ let x;
141
+ if (inside) {
142
+ switch (s.dataLabels.align) {
143
+ case 'left':
144
+ x = item.x + padding;
145
+ break;
146
+ case 'right':
147
+ x = item.x + item.width - width - padding;
148
+ break;
149
+ default:
150
+ x = item.x + item.width / 2 - width / 2;
151
+ break;
152
+ }
153
+ }
154
+ else {
155
+ switch (s.dataLabels.align) {
156
+ case 'left': {
157
+ const edge = 0;
158
+ if (anchor === 'plot') {
159
+ x = edge;
160
+ }
161
+ else {
162
+ x = Math.max(edge, item.x - width - padding);
163
+ }
164
+ break;
165
+ }
166
+ case 'right': {
167
+ const edge = boundsWidth - width;
168
+ if (anchor === 'plot') {
169
+ x = edge;
170
+ }
171
+ else {
172
+ x = Math.min(edge, item.x + item.width + padding);
173
+ }
174
+ break;
175
+ }
176
+ default:
177
+ x = boundsWidth / 2 - width / 2;
178
+ break;
179
+ }
180
+ }
181
+ if (s.dataLabels.html) {
182
+ htmlLabels.push({
183
+ x,
184
+ y,
185
+ content: text,
186
+ size: { width, height },
187
+ style: s.dataLabels.style,
188
+ });
189
+ }
190
+ else {
191
+ svgLabels.push({
192
+ x,
193
+ y,
194
+ text,
195
+ style: s.dataLabels.style,
196
+ size: { width, height, hangingOffset },
197
+ textAnchor: 'start',
198
+ series: s,
199
+ });
200
+ }
150
201
  }
151
- const data = {
202
+ return {
152
203
  type: 'funnel',
153
204
  items,
154
205
  svgLabels,
155
206
  htmlLabels,
156
207
  connectors,
208
+ markers: [],
209
+ getHoverMarkers: () => [],
210
+ annotations: [],
157
211
  };
158
- return data;
159
212
  }
@@ -1,4 +1,4 @@
1
- import { getDomainDataXBySeries, getDomainDataYBySeries, getFormattedValue, getLabelsSize, getTextSizeFn, getTextWithElipsis, isBandScale, } from '../../utils';
1
+ import { getDomainDataXBySeries, getDomainDataYBySeries, getFormattedValue, getLabelsSize, getTextSizeFn, getTextWithElipsis, isBandScale, isPointDataLabelEnabled, shouldPrepareSeriesDataLabels, } from '../../utils';
2
2
  import { getBandSize } from '../../utils/band-size';
3
3
  export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale, }) {
4
4
  var _a, _b, _c, _d, _e;
@@ -44,10 +44,13 @@ export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale,
44
44
  }, []);
45
45
  const svgDataLabels = [];
46
46
  const htmlDataLabels = [];
47
- if (series.dataLabels.enabled) {
47
+ if (shouldPrepareSeriesDataLabels(series)) {
48
48
  if (series.dataLabels.html) {
49
49
  for (let i = 0; i < heatmapItems.length; i++) {
50
50
  const item = heatmapItems[i];
51
+ if (!isPointDataLabelEnabled({ data: item.data, series })) {
52
+ continue;
53
+ }
51
54
  const labelContent = (_c = item.data.label) !== null && _c !== void 0 ? _c : getFormattedValue({ value: item.data.value, format: series.dataLabels.format });
52
55
  if (labelContent) {
53
56
  const dataLabelsStyle = Object.assign(Object.assign({}, series.dataLabels.style), { maxWidth: `${item.width}px`, maxHeight: `${item.height}px`, overflow: 'hidden' });
@@ -71,6 +74,9 @@ export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale,
71
74
  const getTextSize = getTextSizeFn({ style: series.dataLabels.style });
72
75
  for (let i = 0; i < heatmapItems.length; i++) {
73
76
  const item = heatmapItems[i];
77
+ if (!isPointDataLabelEnabled({ data: item.data, series })) {
78
+ continue;
79
+ }
74
80
  const labelContent = (_e = item.data.label) !== null && _e !== void 0 ? _e : getFormattedValue({ value: item.data.value, format: series.dataLabels.format });
75
81
  if (labelContent) {
76
82
  const size = await getTextSize(labelContent);
@@ -97,6 +103,9 @@ export async function prepareHeatmapData({ series, xAxis, xScale, yAxis, yScale,
97
103
  htmlLabels: htmlDataLabels,
98
104
  items: heatmapItems,
99
105
  labels: svgDataLabels,
106
+ markers: [],
107
+ getHoverMarkers: () => [],
108
+ annotations: [],
100
109
  };
101
110
  return preparedData;
102
111
  }