@gravity-ui/charts 1.34.0 → 1.34.2

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 (55) hide show
  1. package/dist/cjs/components/AxisX/prepare-axis-data.d.ts +6 -5
  2. package/dist/cjs/components/AxisX/prepare-axis-data.js +2 -2
  3. package/dist/cjs/components/AxisY/utils.js +3 -3
  4. package/dist/cjs/components/ChartInner/index.js +23 -10
  5. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -0
  6. package/dist/cjs/components/ChartInner/useChartInnerProps.js +3 -1
  7. package/dist/cjs/components/RangeSlider/index.js +1 -0
  8. package/dist/cjs/hooks/useAxis/x-axis.js +1 -1
  9. package/dist/cjs/hooks/useBrush/index.js +24 -5
  10. package/dist/cjs/hooks/useBrush/types.d.ts +1 -0
  11. package/dist/cjs/hooks/useBrush/utils.d.ts +4 -0
  12. package/dist/cjs/hooks/useBrush/utils.js +4 -0
  13. package/dist/cjs/hooks/useShapes/area/prepare-data.js +85 -25
  14. package/dist/cjs/hooks/useShapes/index.d.ts +3 -0
  15. package/dist/cjs/hooks/useShapes/index.js +40 -27
  16. package/dist/cjs/hooks/useShapes/utils.d.ts +10 -0
  17. package/dist/cjs/hooks/useShapes/utils.js +15 -0
  18. package/dist/cjs/setup-jsdom.d.ts +0 -0
  19. package/dist/cjs/setup-jsdom.js +19 -0
  20. package/dist/cjs/utils/chart/axis/common.d.ts +2 -2
  21. package/dist/cjs/utils/chart/axis/common.js +2 -2
  22. package/dist/cjs/utils/chart/axis/x-axis.d.ts +11 -10
  23. package/dist/cjs/utils/chart/axis/x-axis.js +24 -3
  24. package/dist/cjs/utils/chart/index.d.ts +2 -29
  25. package/dist/cjs/utils/chart/index.js +2 -19
  26. package/dist/cjs/utils/chart/series-type-guards.d.ts +30 -0
  27. package/dist/cjs/utils/chart/series-type-guards.js +19 -0
  28. package/dist/esm/components/AxisX/prepare-axis-data.d.ts +6 -5
  29. package/dist/esm/components/AxisX/prepare-axis-data.js +2 -2
  30. package/dist/esm/components/AxisY/utils.js +3 -3
  31. package/dist/esm/components/ChartInner/index.js +23 -10
  32. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -0
  33. package/dist/esm/components/ChartInner/useChartInnerProps.js +3 -1
  34. package/dist/esm/components/RangeSlider/index.js +1 -0
  35. package/dist/esm/hooks/useAxis/x-axis.js +1 -1
  36. package/dist/esm/hooks/useBrush/index.js +24 -5
  37. package/dist/esm/hooks/useBrush/types.d.ts +1 -0
  38. package/dist/esm/hooks/useBrush/utils.d.ts +4 -0
  39. package/dist/esm/hooks/useBrush/utils.js +4 -0
  40. package/dist/esm/hooks/useShapes/area/prepare-data.js +85 -25
  41. package/dist/esm/hooks/useShapes/index.d.ts +3 -0
  42. package/dist/esm/hooks/useShapes/index.js +40 -27
  43. package/dist/esm/hooks/useShapes/utils.d.ts +10 -0
  44. package/dist/esm/hooks/useShapes/utils.js +15 -0
  45. package/dist/esm/setup-jsdom.d.ts +0 -0
  46. package/dist/esm/setup-jsdom.js +19 -0
  47. package/dist/esm/utils/chart/axis/common.d.ts +2 -2
  48. package/dist/esm/utils/chart/axis/common.js +2 -2
  49. package/dist/esm/utils/chart/axis/x-axis.d.ts +11 -10
  50. package/dist/esm/utils/chart/axis/x-axis.js +24 -3
  51. package/dist/esm/utils/chart/index.d.ts +2 -29
  52. package/dist/esm/utils/chart/index.js +2 -19
  53. package/dist/esm/utils/chart/series-type-guards.d.ts +30 -0
  54. package/dist/esm/utils/chart/series-type-guards.js +19 -0
  55. package/package.json +1 -1
@@ -94,11 +94,13 @@ export const prepareAreaData = async (args) => {
94
94
  const positiveStackValues = new Map();
95
95
  const negativeStackValues = new Map();
96
96
  xValues.forEach(([key]) => {
97
- positiveStackValues.set(key, 0);
98
- negativeStackValues.set(key, 0);
97
+ positiveStackValues.set(key, { prev: 0, next: 0 });
98
+ negativeStackValues.set(key, { prev: 0, next: 0 });
99
99
  });
100
100
  const seriesStackData = [];
101
- for (let j = 0; j < seriesStack.length; j++) {
101
+ // Process series in reverse order so that the first series in input
102
+ // appears at the top of the stack (furthest from baseline)
103
+ for (let j = seriesStack.length - 1; j >= 0; j--) {
102
104
  const s = seriesStack[j];
103
105
  const yAxisIndex = s.yAxis;
104
106
  const seriesYAxis = yAxis[yAxisIndex];
@@ -123,40 +125,97 @@ export const prepareAreaData = async (args) => {
123
125
  : d.x);
124
126
  return m.set(key, d);
125
127
  }, new Map());
126
- const points = xValues.reduce((pointsAcc, [x, xValue]) => {
127
- var _a, _b;
128
+ const points = xValues.reduce((pointsAcc, [x, xValue], index) => {
129
+ var _a, _b, _c, _d, _e, _f, _g, _h;
128
130
  const d = (_a = seriesData.get(x)) !== null && _a !== void 0 ? _a : {
129
131
  x,
130
132
  y: 0,
131
133
  };
132
134
  const yDataValue = (_b = d.y) !== null && _b !== void 0 ? _b : null;
135
+ if (s.nullMode === 'connect' && yDataValue === null) {
136
+ return pointsAcc;
137
+ }
133
138
  const yValue = getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale });
134
- let y = null;
135
- let y0 = yAxisTop + yMin;
136
139
  if (typeof yDataValue === 'number' && yValue !== null) {
140
+ const prevPoint = seriesData.get((_c = xValues[index - 1]) === null || _c === void 0 ? void 0 : _c[0]);
141
+ const nextPoint = seriesData.get((_d = xValues[index + 1]) === null || _d === void 0 ? void 0 : _d[0]);
142
+ const currentPointStackHeight = Math.abs(yMin - yValue);
137
143
  if (yDataValue >= 0) {
138
- const positiveStackHeight = positiveStackValues.get(x) || 0;
139
- y = yAxisTop + yValue - positiveStackHeight;
140
- y0 -= positiveStackHeight;
141
- positiveStackValues.set(x, positiveStackHeight + (yMin - yValue));
144
+ const positiveStackHeights = positiveStackValues.get(x);
145
+ let prevSectionStackHeight = (_e = positiveStackHeights === null || positiveStackHeights === void 0 ? void 0 : positiveStackHeights.prev) !== null && _e !== void 0 ? _e : 0;
146
+ let nextSectionStackHeight = (_f = positiveStackHeights === null || positiveStackHeights === void 0 ? void 0 : positiveStackHeights.next) !== null && _f !== void 0 ? _f : 0;
147
+ pointsAcc.push({
148
+ y0: yAxisTop + yMin - prevSectionStackHeight,
149
+ x: xValue,
150
+ y: yAxisTop + yValue - prevSectionStackHeight,
151
+ data: d,
152
+ series: s,
153
+ });
154
+ if (prevSectionStackHeight !== nextSectionStackHeight) {
155
+ pointsAcc.push({
156
+ y0: yAxisTop + yMin - nextSectionStackHeight,
157
+ x: xValue,
158
+ y: yAxisTop + yValue - nextSectionStackHeight,
159
+ data: d,
160
+ series: s,
161
+ });
162
+ }
163
+ if ((prevPoint === null || prevPoint === void 0 ? void 0 : prevPoint.y) !== null) {
164
+ prevSectionStackHeight =
165
+ prevSectionStackHeight + currentPointStackHeight;
166
+ }
167
+ if ((nextPoint === null || nextPoint === void 0 ? void 0 : nextPoint.y) !== null) {
168
+ nextSectionStackHeight =
169
+ nextSectionStackHeight + currentPointStackHeight;
170
+ }
171
+ positiveStackValues.set(x, {
172
+ prev: prevSectionStackHeight,
173
+ next: nextSectionStackHeight,
174
+ });
142
175
  }
143
176
  else {
144
- const negativeStackHeight = negativeStackValues.get(x) || 0;
145
- y = yAxisTop + yValue + negativeStackHeight;
146
- y0 += negativeStackHeight;
147
- negativeStackValues.set(x, negativeStackHeight + (yValue - yMin));
177
+ const negativeStackHeights = negativeStackValues.get(x);
178
+ let prevSectionStackHeight = (_g = negativeStackHeights === null || negativeStackHeights === void 0 ? void 0 : negativeStackHeights.prev) !== null && _g !== void 0 ? _g : 0;
179
+ let nextSectionStackHeight = (_h = negativeStackHeights === null || negativeStackHeights === void 0 ? void 0 : negativeStackHeights.next) !== null && _h !== void 0 ? _h : 0;
180
+ pointsAcc.push({
181
+ y0: yAxisTop + yMin + prevSectionStackHeight,
182
+ x: xValue,
183
+ y: yAxisTop + yValue + prevSectionStackHeight,
184
+ data: d,
185
+ series: s,
186
+ });
187
+ if (prevSectionStackHeight !== nextSectionStackHeight) {
188
+ pointsAcc.push({
189
+ y0: yAxisTop + yMin + nextSectionStackHeight,
190
+ x: xValue,
191
+ y: yAxisTop + yValue + nextSectionStackHeight,
192
+ data: d,
193
+ series: s,
194
+ });
195
+ }
196
+ if ((prevPoint === null || prevPoint === void 0 ? void 0 : prevPoint.y) !== null) {
197
+ prevSectionStackHeight =
198
+ prevSectionStackHeight + currentPointStackHeight;
199
+ }
200
+ if ((nextPoint === null || nextPoint === void 0 ? void 0 : nextPoint.y) !== null) {
201
+ nextSectionStackHeight =
202
+ nextSectionStackHeight + currentPointStackHeight;
203
+ }
204
+ negativeStackValues.set(x, {
205
+ prev: prevSectionStackHeight,
206
+ next: nextSectionStackHeight,
207
+ });
148
208
  }
149
209
  }
150
- if (s.nullMode === 'connect' && yDataValue === null) {
151
- return pointsAcc;
210
+ else {
211
+ pointsAcc.push({
212
+ y0: yAxisTop + yMin,
213
+ x: xValue,
214
+ y: null,
215
+ data: d,
216
+ series: s,
217
+ });
152
218
  }
153
- pointsAcc.push({
154
- y0,
155
- x: xValue,
156
- y,
157
- data: d,
158
- series: s,
159
- });
160
219
  return pointsAcc;
161
220
  }, []);
162
221
  const labels = [];
@@ -197,7 +256,8 @@ export const prepareAreaData = async (args) => {
197
256
  }
198
257
  if (series.some((s) => s.stacking === 'percent')) {
199
258
  xValues.forEach(([x], index) => {
200
- const stackHeight = positiveStackValues.get(x) || 0;
259
+ var _a;
260
+ const stackHeight = ((_a = positiveStackValues.get(x)) === null || _a === void 0 ? void 0 : _a.prev) || 0;
201
261
  let acc = 0;
202
262
  const ratio = plotHeight / stackHeight;
203
263
  seriesStackData.forEach((item) => {
@@ -5,6 +5,7 @@ import type { PreparedXAxis, PreparedYAxis } from '../useAxis/types';
5
5
  import type { ChartScale } from '../useAxisScales/types';
6
6
  import type { PreparedSeries, PreparedSeriesOptions } from '../useSeries/types';
7
7
  import type { PreparedSplit } from '../useSplit/types';
8
+ import type { ZoomState } from '../useZoom/types';
8
9
  import type { PreparedAreaData } from './area/types';
9
10
  import type { PreparedBarXData } from './bar-x';
10
11
  import type { PreparedBarYData } from './bar-y/types';
@@ -37,8 +38,10 @@ type Args = {
37
38
  isRangeSlider?: boolean;
38
39
  xScale?: ChartScale;
39
40
  yScale?: (ChartScale | undefined)[];
41
+ zoomState?: Partial<ZoomState>;
40
42
  };
41
43
  export declare const useShapes: (args: Args) => {
42
44
  shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
43
45
  shapesData: ShapeData[];
46
+ shapesReady: boolean;
44
47
  };
@@ -20,6 +20,7 @@ import { prepareSankeyData } from './sankey/prepare-data';
20
20
  import { ScatterSeriesShape, prepareScatterData } from './scatter';
21
21
  import { TreemapSeriesShape } from './treemap';
22
22
  import { prepareTreemapData } from './treemap/prepare-data';
23
+ import { getSeriesClipPathId } from './utils';
23
24
  import { WaterfallSeriesShapes, prepareWaterfallData } from './waterfall';
24
25
  import './styles.css';
25
26
  function IS_OUTSIDE_BOUNDS() {
@@ -30,9 +31,10 @@ function shouldUseClipPathId(seriesType, clipPathBySeriesType) {
30
31
  return (_a = clipPathBySeriesType === null || clipPathBySeriesType === void 0 ? void 0 : clipPathBySeriesType[seriesType]) !== null && _a !== void 0 ? _a : true;
31
32
  }
32
33
  export const useShapes = (args) => {
33
- const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, } = args;
34
+ const { boundsWidth, boundsHeight, clipPathId, clipPathBySeriesType, dispatcher, htmlLayout, isOutsideBounds = IS_OUTSIDE_BOUNDS, isRangeSlider, series, seriesOptions, split, xAxis, xScale, yAxis, yScale, zoomState, } = args;
34
35
  const [shapesElemens, setShapesElements] = React.useState([]);
35
36
  const [shapesElemensData, setShapesElemensData] = React.useState([]);
37
+ const shapesReadyRef = React.useRef(false);
36
38
  const countedRef = React.useRef(0);
37
39
  React.useEffect(() => {
38
40
  countedRef.current++;
@@ -44,7 +46,7 @@ export const useShapes = (args) => {
44
46
  const shapes = [];
45
47
  await Promise.all(
46
48
  // eslint-disable-next-line complexity
47
- Array.from(groupedSeries).map(async (item) => {
49
+ Array.from(groupedSeries).map(async (item, index) => {
48
50
  const [seriesType, chartSeries] = item;
49
51
  switch (seriesType) {
50
52
  case SERIES_TYPE.BarX: {
@@ -60,8 +62,8 @@ export const useShapes = (args) => {
60
62
  split,
61
63
  isRangeSlider,
62
64
  });
63
- shapes.push(React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
64
- shapesData.push(...preparedData);
65
+ shapes[index] = (React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
66
+ shapesData.splice(index, 0, ...preparedData);
65
67
  }
66
68
  break;
67
69
  }
@@ -77,8 +79,8 @@ export const useShapes = (args) => {
77
79
  yAxis,
78
80
  yScale,
79
81
  });
80
- shapes.push(React.createElement(BarYSeriesShapes, { key: SERIES_TYPE.BarY, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
81
- shapesData.push(...preparedData.shapes);
82
+ shapes[index] = (React.createElement(BarYSeriesShapes, { key: SERIES_TYPE.BarY, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
83
+ shapesData.splice(index, 0, ...preparedData.shapes);
82
84
  }
83
85
  break;
84
86
  }
@@ -92,8 +94,8 @@ export const useShapes = (args) => {
92
94
  yAxis,
93
95
  yScale,
94
96
  });
95
- shapes.push(React.createElement(WaterfallSeriesShapes, { key: SERIES_TYPE.Waterfall, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
96
- shapesData.push(...preparedData);
97
+ shapes[index] = (React.createElement(WaterfallSeriesShapes, { key: SERIES_TYPE.Waterfall, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
98
+ shapesData.splice(index, 0, ...preparedData);
97
99
  }
98
100
  break;
99
101
  }
@@ -109,8 +111,13 @@ export const useShapes = (args) => {
109
111
  isOutsideBounds,
110
112
  isRangeSlider,
111
113
  });
112
- shapes.push(React.createElement(LineSeriesShapes, { key: SERIES_TYPE.Line, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
113
- shapesData.push(...preparedData);
114
+ const resultClipPathId = getSeriesClipPathId({
115
+ clipPathId,
116
+ yAxis,
117
+ zoomState,
118
+ });
119
+ shapes[index] = (React.createElement(LineSeriesShapes, { key: SERIES_TYPE.Line, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: resultClipPathId }));
120
+ shapesData.splice(index, 0, ...preparedData);
114
121
  }
115
122
  break;
116
123
  }
@@ -127,8 +134,8 @@ export const useShapes = (args) => {
127
134
  isOutsideBounds,
128
135
  isRangeSlider,
129
136
  });
130
- shapes.push(React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
131
- shapesData.push(...preparedData);
137
+ shapes[index] = (React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
138
+ shapesData.splice(index, 0, ...preparedData);
132
139
  }
133
140
  break;
134
141
  }
@@ -142,10 +149,10 @@ export const useShapes = (args) => {
142
149
  yScale,
143
150
  isOutsideBounds,
144
151
  });
145
- shapes.push(React.createElement(ScatterSeriesShape, { key: SERIES_TYPE.Scatter, clipPathId: shouldUseClipPathId(SERIES_TYPE.Scatter, clipPathBySeriesType)
152
+ shapes[index] = (React.createElement(ScatterSeriesShape, { key: SERIES_TYPE.Scatter, clipPathId: shouldUseClipPathId(SERIES_TYPE.Scatter, clipPathBySeriesType)
146
153
  ? clipPathId
147
154
  : undefined, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
148
- shapesData.push(...preparedData);
155
+ shapesData.splice(index, 0, ...preparedData);
149
156
  }
150
157
  break;
151
158
  }
@@ -155,8 +162,8 @@ export const useShapes = (args) => {
155
162
  boundsWidth,
156
163
  boundsHeight,
157
164
  });
158
- shapes.push(React.createElement(PieSeriesShapes, { key: SERIES_TYPE.Pie, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
159
- shapesData.push(...preparedData);
165
+ shapes[index] = (React.createElement(PieSeriesShapes, { key: SERIES_TYPE.Pie, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
166
+ shapesData.splice(index, 0, ...preparedData);
160
167
  break;
161
168
  }
162
169
  case SERIES_TYPE.Treemap: {
@@ -167,8 +174,8 @@ export const useShapes = (args) => {
167
174
  width: boundsWidth,
168
175
  height: boundsHeight,
169
176
  });
170
- shapes.push(React.createElement(TreemapSeriesShape, { key: SERIES_TYPE.Treemap, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
171
- shapesData.push(preparedData);
177
+ shapes[index] = (React.createElement(TreemapSeriesShape, { key: SERIES_TYPE.Treemap, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
178
+ shapesData.splice(index, 0, preparedData);
172
179
  break;
173
180
  }
174
181
  case SERIES_TYPE.Sankey: {
@@ -177,8 +184,8 @@ export const useShapes = (args) => {
177
184
  width: boundsWidth,
178
185
  height: boundsHeight,
179
186
  });
180
- shapes.push(React.createElement(SankeySeriesShape, { key: SERIES_TYPE.Sankey, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
181
- shapesData.push(preparedData);
187
+ shapes[index] = (React.createElement(SankeySeriesShape, { key: SERIES_TYPE.Sankey, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
188
+ shapesData.splice(index, 0, preparedData);
182
189
  break;
183
190
  }
184
191
  case SERIES_TYPE.Radar: {
@@ -187,8 +194,8 @@ export const useShapes = (args) => {
187
194
  boundsWidth,
188
195
  boundsHeight,
189
196
  });
190
- shapes.push(React.createElement(RadarSeriesShapes, { key: SERIES_TYPE.Radar, dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
191
- shapesData.push(...preparedData);
197
+ shapes[index] = (React.createElement(RadarSeriesShapes, { key: SERIES_TYPE.Radar, dispatcher: dispatcher, series: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
198
+ shapesData.splice(index, 0, ...preparedData);
192
199
  break;
193
200
  }
194
201
  case SERIES_TYPE.Heatmap: {
@@ -200,8 +207,8 @@ export const useShapes = (args) => {
200
207
  yAxis: yAxis[0],
201
208
  yScale: yScale[0],
202
209
  });
203
- shapes.push(React.createElement(HeatmapSeriesShapes, { key: SERIES_TYPE.Heatmap, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
204
- shapesData.push(preparedData);
210
+ shapes[index] = (React.createElement(HeatmapSeriesShapes, { key: SERIES_TYPE.Heatmap, dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
211
+ shapesData.splice(index, 0, preparedData);
205
212
  }
206
213
  break;
207
214
  }
@@ -211,8 +218,8 @@ export const useShapes = (args) => {
211
218
  boundsWidth,
212
219
  boundsHeight,
213
220
  });
214
- shapes.push(React.createElement(FunnelSeriesShapes, { key: "funnel", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
215
- shapesData.push(preparedData);
221
+ shapes[index] = (React.createElement(FunnelSeriesShapes, { key: "funnel", dispatcher: dispatcher, preparedData: preparedData, seriesOptions: seriesOptions, htmlLayout: htmlLayout }));
222
+ shapesData.splice(index, 0, preparedData);
216
223
  break;
217
224
  }
218
225
  default: {
@@ -223,6 +230,7 @@ export const useShapes = (args) => {
223
230
  }
224
231
  }));
225
232
  if (countedRef.current === currentRun) {
233
+ shapesReadyRef.current = true;
226
234
  setShapesElements(shapes);
227
235
  setShapesElemensData(shapesData);
228
236
  }
@@ -243,6 +251,11 @@ export const useShapes = (args) => {
243
251
  xScale,
244
252
  yAxis,
245
253
  yScale,
254
+ zoomState,
246
255
  ]);
247
- return { shapes: shapesElemens, shapesData: shapesElemensData };
256
+ return {
257
+ shapes: shapesElemens,
258
+ shapesData: shapesElemensData,
259
+ shapesReady: shapesReadyRef.current,
260
+ };
248
261
  };
@@ -2,6 +2,7 @@ import type { BaseType } from 'd3';
2
2
  import type { BasicInactiveState } from '../../types';
3
3
  import type { PreparedXAxis, PreparedYAxis } from '../useAxis/types';
4
4
  import type { ChartScale } from '../useAxisScales/types';
5
+ import type { ZoomState } from '../useZoom/types';
5
6
  export declare function getXValue(args: {
6
7
  point: {
7
8
  x?: number | string | null;
@@ -46,3 +47,12 @@ export declare function getRectBorderPath(args: {
46
47
  borderWidth: number;
47
48
  borderRadius?: number | number[];
48
49
  }): string;
50
+ export declare function getClipPathIdByBounds(args: {
51
+ clipPathId: string;
52
+ bounds?: 'horizontal';
53
+ }): string;
54
+ export declare function getSeriesClipPathId(args: {
55
+ clipPathId: string;
56
+ yAxis: PreparedYAxis[];
57
+ zoomState?: Partial<ZoomState>;
58
+ }): string;
@@ -131,3 +131,18 @@ export function getRectBorderPath(args) {
131
131
  }).toString();
132
132
  return `${outerPath} ${innerPath}`;
133
133
  }
134
+ export function getClipPathIdByBounds(args) {
135
+ const { bounds, clipPathId } = args;
136
+ return bounds ? `${clipPathId}-${bounds}` : clipPathId;
137
+ }
138
+ export function getSeriesClipPathId(args) {
139
+ const { clipPathId, yAxis, zoomState } = args;
140
+ const hasMinOrMax = yAxis.some((axis) => {
141
+ return typeof (axis === null || axis === void 0 ? void 0 : axis.min) === 'number' || typeof (axis === null || axis === void 0 ? void 0 : axis.max) === 'number';
142
+ });
143
+ const hasZoom = zoomState && Object.keys(zoomState).length > 0;
144
+ if (!hasZoom && !hasMinOrMax) {
145
+ return getClipPathIdByBounds({ clipPathId, bounds: 'horizontal' });
146
+ }
147
+ return getClipPathIdByBounds({ clipPathId });
148
+ }
File without changes
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ // Global mocks for jsdom environment.
3
+ // Guarded by typeof checks so this file is safe to run in the `node` environment too.
4
+ if (typeof document !== 'undefined') {
5
+ // jsdom does not implement document.fonts
6
+ if (!document.fonts) {
7
+ Object.defineProperty(document, 'fonts', {
8
+ value: { ready: Promise.resolve() },
9
+ configurable: true,
10
+ });
11
+ }
12
+ }
13
+ if (typeof HTMLCanvasElement !== 'undefined') {
14
+ // jsdom does not implement HTMLCanvasElement.prototype.getContext (used for text measurement)
15
+ HTMLCanvasElement.prototype.getContext = (() => ({
16
+ font: '',
17
+ measureText: () => ({ width: 0 }),
18
+ }));
19
+ }
@@ -3,9 +3,9 @@ import type { ChartScale, PreparedAxis, PreparedAxisPlotBand, PreparedSplit } fr
3
3
  import type { ChartAxis } from '../../../types';
4
4
  import type { AxisDirection } from '../types';
5
5
  type Ticks = number[] | string[] | Date[];
6
- export declare function getTicksCount({ axis, range }: {
6
+ export declare function getTicksCountByPixelInterval({ axis, axisWidth, }: {
7
7
  axis: PreparedAxis;
8
- range: number;
8
+ axisWidth: number;
9
9
  }): number | undefined;
10
10
  export declare function isBandScale(scale?: ChartScale | AxisScale<AxisDomain>): scale is ScaleBand<string>;
11
11
  export declare function isTimeScale(scale?: ChartScale | AxisScale<AxisDomain>): scale is ScaleTime<number, number>;
@@ -1,9 +1,9 @@
1
1
  import { ascending, descending, reverse, sort } from 'd3';
2
2
  import clamp from 'lodash/clamp';
3
- export function getTicksCount({ axis, range }) {
3
+ export function getTicksCountByPixelInterval({ axis, axisWidth, }) {
4
4
  let ticksCount;
5
5
  if (axis.ticks.pixelInterval) {
6
- ticksCount = Math.ceil(range / axis.ticks.pixelInterval);
6
+ ticksCount = Math.ceil(axisWidth / axis.ticks.pixelInterval);
7
7
  }
8
8
  return ticksCount;
9
9
  }
@@ -1,12 +1,13 @@
1
- import type { ChartScale, PreparedAxis } from '../../../hooks';
2
- export declare function getXAxisTickValues({ scale, axis, labelLineHeight, }: {
3
- scale: ChartScale;
1
+ import type { ChartScale, PreparedAxis, PreparedSeries } from '../../../hooks';
2
+ import type { ChartSeries } from '../../../types';
3
+ type TickValue = {
4
+ x: number;
5
+ value: number | string | Date;
6
+ };
7
+ export declare function getXAxisTickValues({ axis, labelLineHeight, scale, series, }: {
4
8
  axis: PreparedAxis;
5
9
  labelLineHeight: number;
6
- }): {
7
- x: number;
8
- value: number | Date;
9
- }[] | {
10
- x: number;
11
- value: string;
12
- }[];
10
+ scale: ChartScale;
11
+ series?: ChartSeries[] | PreparedSeries[];
12
+ }): TickValue[];
13
+ export {};
@@ -1,13 +1,34 @@
1
1
  import { getMinSpaceBetween } from '../array';
2
- import { getTicksCount, isBandScale, thinOut } from './common';
3
- export function getXAxisTickValues({ scale, axis, labelLineHeight, }) {
2
+ import { isSeriesWithNumericalXValues } from '../series-type-guards';
3
+ import { getTicksCountByPixelInterval, isBandScale, thinOut } from './common';
4
+ const DEFAULT_TICKS_COUNT = 10;
5
+ function getTicksCount(args) {
6
+ const { axis, axisWidth, series } = args;
7
+ const result = getTicksCountByPixelInterval({ axis, axisWidth });
8
+ if (typeof result === 'number') {
9
+ return result;
10
+ }
11
+ if (series) {
12
+ const xDataSet = new Set();
13
+ series === null || series === void 0 ? void 0 : series.forEach((item) => {
14
+ if (isSeriesWithNumericalXValues(item)) {
15
+ item.data.forEach((data) => {
16
+ xDataSet.add(data.x);
17
+ });
18
+ }
19
+ });
20
+ return xDataSet.size < DEFAULT_TICKS_COUNT ? xDataSet.size : DEFAULT_TICKS_COUNT;
21
+ }
22
+ return DEFAULT_TICKS_COUNT;
23
+ }
24
+ export function getXAxisTickValues({ axis, labelLineHeight, scale, series, }) {
4
25
  if ('ticks' in scale && typeof scale.ticks === 'function') {
5
26
  const range = scale.range();
6
27
  const axisWidth = Math.abs(range[0] - range[1]);
7
28
  if (!axisWidth) {
8
29
  return [];
9
30
  }
10
- const scaleTicksCount = getTicksCount({ axis, range: axisWidth });
31
+ const scaleTicksCount = getTicksCount({ axis, axisWidth, series });
11
32
  const scaleTicks = scale.ticks(scaleTicksCount);
12
33
  const originalTickValues = scaleTicks.map((t) => ({
13
34
  x: scale(t),
@@ -1,4 +1,5 @@
1
1
  import type { BaseTextStyle, ChartSeries, ChartSeriesData } from '../../types';
2
+ import type { UnknownSeries } from './series-type-guards';
2
3
  import type { AxisDirection } from './types';
3
4
  export * from './axis/common';
4
5
  export * from './array';
@@ -8,41 +9,13 @@ export * from './labels';
8
9
  export * from './legend';
9
10
  export * from './math';
10
11
  export * from './series';
12
+ export * from './series-type-guards';
11
13
  export * from './symbol';
12
14
  export * from './text';
13
15
  export * from './time';
14
16
  export * from './zoom';
15
17
  export declare const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS: ChartSeries['type'][];
16
18
  export declare const CHART_SERIES_WITH_VOLUME_ON_X_AXIS: ChartSeries['type'][];
17
- type UnknownSeries = {
18
- type: ChartSeries['type'];
19
- data: unknown;
20
- };
21
- /**
22
- * Checks whether the series should be drawn with axes.
23
- *
24
- * @param series - The series object to check.
25
- * @returns `true` if the series should be drawn with axes, `false` otherwise.
26
- */
27
- export declare function isAxisRelatedSeries(series: UnknownSeries): boolean;
28
- export declare function isSeriesWithNumericalXValues(series: UnknownSeries): series is {
29
- type: ChartSeries['type'];
30
- data: {
31
- x: number;
32
- }[];
33
- };
34
- export declare function isSeriesWithNumericalYValues(series: UnknownSeries): series is {
35
- type: ChartSeries['type'];
36
- data: {
37
- y: number;
38
- }[];
39
- };
40
- export declare function isSeriesWithCategoryValues(series: UnknownSeries): series is {
41
- type: ChartSeries['type'];
42
- data: {
43
- category: string;
44
- }[];
45
- };
46
19
  export declare const getDomainDataXBySeries: (series: UnknownSeries[]) => ({} | undefined)[];
47
20
  export declare function getDefaultMaxXAxisValue(series: UnknownSeries[]): 0 | undefined;
48
21
  export declare function getDefaultMinXAxisValue(series: UnknownSeries[]): number | undefined;
@@ -5,6 +5,7 @@ import sortBy from 'lodash/sortBy';
5
5
  import { DEFAULT_AXIS_LABEL_FONT_SIZE, SERIES_TYPE } from '../../constants';
6
6
  import { getSeriesStackId } from '../../hooks/useSeries/utils';
7
7
  import { getWaterfallPointSubtotal } from './series/waterfall';
8
+ import { isSeriesWithNumericalXValues, isSeriesWithNumericalYValues } from './series-type-guards';
8
9
  export * from './axis/common';
9
10
  export * from './array';
10
11
  export * from './color';
@@ -13,35 +14,17 @@ export * from './labels';
13
14
  export * from './legend';
14
15
  export * from './math';
15
16
  export * from './series';
17
+ export * from './series-type-guards';
16
18
  export * from './symbol';
17
19
  export * from './text';
18
20
  export * from './time';
19
21
  export * from './zoom';
20
- const CHARTS_WITHOUT_AXIS = ['pie', 'treemap', 'sankey', 'radar', 'funnel'];
21
22
  export const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS = [
22
23
  'bar-x',
23
24
  'area',
24
25
  'waterfall',
25
26
  ];
26
27
  export const CHART_SERIES_WITH_VOLUME_ON_X_AXIS = ['bar-y'];
27
- /**
28
- * Checks whether the series should be drawn with axes.
29
- *
30
- * @param series - The series object to check.
31
- * @returns `true` if the series should be drawn with axes, `false` otherwise.
32
- */
33
- export function isAxisRelatedSeries(series) {
34
- return !CHARTS_WITHOUT_AXIS.includes(series.type);
35
- }
36
- export function isSeriesWithNumericalXValues(series) {
37
- return isAxisRelatedSeries(series);
38
- }
39
- export function isSeriesWithNumericalYValues(series) {
40
- return isAxisRelatedSeries(series);
41
- }
42
- export function isSeriesWithCategoryValues(series) {
43
- return isAxisRelatedSeries(series);
44
- }
45
28
  function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y') {
46
29
  const acc = [];
47
30
  const stackedSeries = group(seriesList, getSeriesStackId);
@@ -0,0 +1,30 @@
1
+ import type { ChartSeries } from '../../types';
2
+ export type UnknownSeries = {
3
+ type: ChartSeries['type'];
4
+ data: unknown;
5
+ };
6
+ /**
7
+ * Checks whether the series should be drawn with axes.
8
+ *
9
+ * @param series - The series object to check.
10
+ * @returns `true` if the series should be drawn with axes, `false` otherwise.
11
+ */
12
+ export declare function isAxisRelatedSeries(series: UnknownSeries): boolean;
13
+ export declare function isSeriesWithNumericalXValues(series: UnknownSeries): series is {
14
+ type: ChartSeries['type'];
15
+ data: {
16
+ x: number;
17
+ }[];
18
+ };
19
+ export declare function isSeriesWithNumericalYValues(series: UnknownSeries): series is {
20
+ type: ChartSeries['type'];
21
+ data: {
22
+ y: number;
23
+ }[];
24
+ };
25
+ export declare function isSeriesWithCategoryValues(series: UnknownSeries): series is {
26
+ type: ChartSeries['type'];
27
+ data: {
28
+ category: string;
29
+ }[];
30
+ };
@@ -0,0 +1,19 @@
1
+ const CHARTS_WITHOUT_AXIS = ['pie', 'treemap', 'sankey', 'radar', 'funnel'];
2
+ /**
3
+ * Checks whether the series should be drawn with axes.
4
+ *
5
+ * @param series - The series object to check.
6
+ * @returns `true` if the series should be drawn with axes, `false` otherwise.
7
+ */
8
+ export function isAxisRelatedSeries(series) {
9
+ return !CHARTS_WITHOUT_AXIS.includes(series.type);
10
+ }
11
+ export function isSeriesWithNumericalXValues(series) {
12
+ return isAxisRelatedSeries(series);
13
+ }
14
+ export function isSeriesWithNumericalYValues(series) {
15
+ return isAxisRelatedSeries(series);
16
+ }
17
+ export function isSeriesWithCategoryValues(series) {
18
+ return isAxisRelatedSeries(series);
19
+ }