@gravity-ui/charts 1.24.0 → 1.24.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 (33) hide show
  1. package/dist/cjs/components/ChartInner/index.js +2 -1
  2. package/dist/cjs/components/ChartInner/useChartInnerProps.js +1 -2
  3. package/dist/cjs/hooks/useAxisScales/index.d.ts +4 -4
  4. package/dist/cjs/hooks/useAxisScales/index.js +95 -39
  5. package/dist/cjs/hooks/useAxisScales/utils.d.ts +19 -0
  6. package/dist/cjs/hooks/useAxisScales/utils.js +34 -0
  7. package/dist/cjs/hooks/useRangeSlider/index.js +2 -1
  8. package/dist/cjs/hooks/useRangeSlider/types.d.ts +2 -0
  9. package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +2 -0
  10. package/dist/cjs/hooks/useShapes/area/prepare-data.js +159 -158
  11. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.d.ts +2 -0
  12. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +87 -72
  13. package/dist/cjs/hooks/useShapes/index.js +2 -0
  14. package/dist/cjs/hooks/useShapes/line/prepare-data.js +1 -1
  15. package/dist/cjs/hooks/useShapes/styles.css +5 -13
  16. package/dist/cjs/utils/chart/index.js +1 -1
  17. package/dist/esm/components/ChartInner/index.js +2 -1
  18. package/dist/esm/components/ChartInner/useChartInnerProps.js +1 -2
  19. package/dist/esm/hooks/useAxisScales/index.d.ts +4 -4
  20. package/dist/esm/hooks/useAxisScales/index.js +95 -39
  21. package/dist/esm/hooks/useAxisScales/utils.d.ts +19 -0
  22. package/dist/esm/hooks/useAxisScales/utils.js +34 -0
  23. package/dist/esm/hooks/useRangeSlider/index.js +2 -1
  24. package/dist/esm/hooks/useRangeSlider/types.d.ts +2 -0
  25. package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +2 -0
  26. package/dist/esm/hooks/useShapes/area/prepare-data.js +159 -158
  27. package/dist/esm/hooks/useShapes/bar-x/prepare-data.d.ts +2 -0
  28. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +87 -72
  29. package/dist/esm/hooks/useShapes/index.js +2 -0
  30. package/dist/esm/hooks/useShapes/line/prepare-data.js +1 -1
  31. package/dist/esm/hooks/useShapes/styles.css +5 -13
  32. package/dist/esm/utils/chart/index.js +1 -1
  33. package/package.json +1 -1
@@ -177,6 +177,7 @@ export const ChartInner = (props) => {
177
177
  }, [
178
178
  initialized,
179
179
  preparedRangeSlider.defaultRange,
180
+ preparedSeries,
180
181
  setInitialized,
181
182
  updateRangeSliderState,
182
183
  xScale,
@@ -201,7 +202,7 @@ export const ChartInner = (props) => {
201
202
  React.createElement("g", { ref: plotBeforeRef }),
202
203
  shapes,
203
204
  React.createElement("g", { ref: plotAfterRef })),
204
- ((_e = xAxis === null || xAxis === void 0 ? void 0 : xAxis.rangeSlider) === null || _e === void 0 ? void 0 : _e.enabled) && (React.createElement(RangeSlider, { boundsOffsetLeft: debouncedOffsetLeft, boundsWidth: debouncedBoundsWidth, height: height, htmlLayout: htmlLayout, onUpdate: updateRangeSliderState, preparedChart: preparedChart, preparedLegend: preparedLegend, preparedSeries: debouncedAllPreparedSeries, preparedSeriesOptions: preparedSeriesOptions, preparedRangeSlider: xAxis.rangeSlider, rangeSliderState: rangeSliderState, width: width, xAxis: data.xAxis, yAxis: data.yAxis })),
205
+ ((_e = xAxis === null || xAxis === void 0 ? void 0 : xAxis.rangeSlider) === null || _e === void 0 ? void 0 : _e.enabled) && (React.createElement(RangeSlider, { boundsOffsetLeft: debouncedOffsetLeft, boundsWidth: debouncedBoundsWidth, height: height, htmlLayout: htmlLayout, onUpdate: updateRangeSliderState, preparedChart: preparedChart, preparedLegend: preparedLegend, preparedSeries: debouncedAllPreparedSeries, preparedSeriesOptions: preparedSeriesOptions, preparedRangeSlider: xAxis.rangeSlider, rangeSliderState: rangeSliderState, width: width, xAxis: data.xAxis, yAxis: data.yAxis, zoomState: zoomState })),
205
206
  (preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayout }))));
206
207
  return (React.createElement("div", { className: b() },
207
208
  React.createElement("svg", { ref: svgRef, width: width, height: height,
@@ -79,14 +79,13 @@ export function useChartInnerProps(props) {
79
79
  const { xScale, yScale } = useAxisScales({
80
80
  boundsWidth,
81
81
  boundsHeight,
82
- hasZoomX: Boolean(zoomState.x),
83
- hasZoomY: Boolean(zoomState.y),
84
82
  rangeSliderState,
85
83
  series: preparedSeries,
86
84
  seriesOptions: preparedSeriesOptions,
87
85
  split: preparedSplit,
88
86
  xAxis,
89
87
  yAxis,
88
+ zoomState,
90
89
  });
91
90
  const isOutsideBounds = React.useCallback((x, y) => {
92
91
  return x < 0 || x > boundsWidth || y < 0 || y > boundsHeight;
@@ -1,5 +1,5 @@
1
1
  import type { ScaleBand, ScaleLinear, ScaleTime } from 'd3';
2
- import type { PreparedAxis, PreparedSeries, PreparedSeriesOptions, PreparedSplit, RangeSliderState } from '../../hooks';
2
+ import type { PreparedAxis, PreparedSeries, PreparedSeriesOptions, PreparedSplit, RangeSliderState, ZoomState } from '../../hooks';
3
3
  import type { ChartAxis, ChartSeries } from '../../types';
4
4
  export type ChartScale = ScaleLinear<number, number> | ScaleBand<string> | ScaleTime<number, number>;
5
5
  type Args = {
@@ -10,9 +10,8 @@ type Args = {
10
10
  xAxis: PreparedAxis | null;
11
11
  yAxis: PreparedAxis[];
12
12
  split: PreparedSplit;
13
- hasZoomX?: boolean;
14
- hasZoomY?: boolean;
15
13
  rangeSliderState?: RangeSliderState;
14
+ zoomState?: Partial<ZoomState>;
16
15
  };
17
16
  type ReturnValue = {
18
17
  xScale?: ChartScale;
@@ -22,14 +21,15 @@ export declare function createYScale(args: {
22
21
  axis: PreparedAxis;
23
22
  boundsHeight: number;
24
23
  series: (PreparedSeries | ChartSeries)[];
24
+ zoomStateY?: [number, number];
25
25
  }): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never> | undefined;
26
26
  export declare function createXScale(args: {
27
27
  axis: PreparedAxis | ChartAxis;
28
28
  boundsWidth: number;
29
29
  series: (PreparedSeries | ChartSeries)[];
30
30
  seriesOptions: PreparedSeriesOptions;
31
- hasZoomX?: boolean;
32
31
  rangeSliderState?: RangeSliderState;
32
+ zoomStateX?: [number, number];
33
33
  }): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never> | undefined;
34
34
  /**
35
35
  * Uses to create scales for axis related series
@@ -5,6 +5,7 @@ import { DEFAULT_AXIS_TYPE, SERIES_TYPE } from '../../constants';
5
5
  import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisCategories, getAxisHeight, getDataCategoryValue, getDefaultMaxXAxisValue, getDefaultMinXAxisValue, getDomainDataXBySeries, getDomainDataYBySeries, getOnlyVisibleSeries, isAxisRelatedSeries, isSeriesWithCategoryValues, } from '../../utils';
6
6
  import { getBarXLayoutForNumericScale, groupBarXDataByXValue } from '../utils/bar-x';
7
7
  import { getBandSize } from '../utils/get-band-size';
8
+ import { checkIsPointDomain, getMinMaxPropsOrState, hasOnlyMarkerSeries } from './utils';
8
9
  const X_AXIS_ZOOM_PADDING = 0.02;
9
10
  function validateArrayData(data) {
10
11
  let hasNumberAndNullValues;
@@ -65,9 +66,12 @@ function isSeriesWithYAxisOffset(series) {
65
66
  }
66
67
  // eslint-disable-next-line complexity
67
68
  export function createYScale(args) {
68
- const { axis, boundsHeight, series } = args;
69
- const yMinProps = get(axis, 'min');
70
- const yMaxProps = get(axis, 'max');
69
+ const { axis, boundsHeight, series, zoomStateY } = args;
70
+ const [yMinPropsOrState, yMaxPropsOrState] = getMinMaxPropsOrState({
71
+ axis,
72
+ maxValues: [zoomStateY === null || zoomStateY === void 0 ? void 0 : zoomStateY[1]],
73
+ minValues: [zoomStateY === null || zoomStateY === void 0 ? void 0 : zoomStateY[0]],
74
+ });
71
75
  const yCategories = get(axis, 'categories');
72
76
  const yTimestamps = get(axis, 'timestamps');
73
77
  const range = getYScaleRange({ axis, boundsHeight });
@@ -84,10 +88,15 @@ export function createYScale(args) {
84
88
  }
85
89
  if (hasNumberAndNullValues) {
86
90
  const [yMinDomain, yMaxDomain] = extent(domain);
87
- const yMin = typeof yMinProps === 'number' ? yMinProps : yMinDomain;
91
+ const isPointDomain = hasOnlyMarkerSeries(series)
92
+ ? checkIsPointDomain([yMinDomain, yMaxDomain])
93
+ : false;
94
+ const yMin = typeof yMinPropsOrState === 'number' && !isPointDomain
95
+ ? yMinPropsOrState
96
+ : yMinDomain;
88
97
  let yMax;
89
- if (typeof yMaxProps === 'number') {
90
- yMax = yMaxProps;
98
+ if (typeof yMaxPropsOrState === 'number' && !isPointDomain) {
99
+ yMax = yMaxPropsOrState;
91
100
  }
92
101
  else {
93
102
  const hasSeriesWithVolumeOnYAxis = series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type));
@@ -128,8 +137,19 @@ export function createYScale(args) {
128
137
  case 'datetime': {
129
138
  if (yTimestamps) {
130
139
  const [yMinTimestamp, yMaxTimestamp] = extent(yTimestamps);
131
- const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
132
- const yMax = typeof yMaxProps === 'number' ? yMaxProps : yMaxTimestamp;
140
+ const isPointDomain = hasOnlyMarkerSeries(series)
141
+ ? checkIsPointDomain([yMinTimestamp, yMaxTimestamp])
142
+ : false;
143
+ const yMin = typeof yMinPropsOrState === 'number' &&
144
+ !isPointDomain &&
145
+ yMinPropsOrState > yMinTimestamp
146
+ ? yMinPropsOrState
147
+ : yMinTimestamp;
148
+ const yMax = typeof yMaxPropsOrState === 'number' &&
149
+ !isPointDomain &&
150
+ yMaxPropsOrState < yMaxTimestamp
151
+ ? yMaxPropsOrState
152
+ : yMaxTimestamp;
133
153
  return scaleUtc().domain([yMin, yMax]).range(range).nice();
134
154
  }
135
155
  else {
@@ -140,8 +160,19 @@ export function createYScale(args) {
140
160
  }
141
161
  if (hasNumberAndNullValues) {
142
162
  const [yMinTimestamp, yMaxTimestamp] = extent(domain);
143
- const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
144
- const yMax = typeof yMaxProps === 'number' ? yMaxProps : yMaxTimestamp;
163
+ const isPointDomain = hasOnlyMarkerSeries(series)
164
+ ? checkIsPointDomain([yMinTimestamp, yMaxTimestamp])
165
+ : false;
166
+ const yMin = typeof yMinPropsOrState === 'number' &&
167
+ !isPointDomain &&
168
+ yMinPropsOrState > yMinTimestamp
169
+ ? yMinPropsOrState
170
+ : yMinTimestamp;
171
+ const yMax = typeof yMaxPropsOrState === 'number' &&
172
+ !isPointDomain &&
173
+ yMaxPropsOrState < yMaxTimestamp
174
+ ? yMaxPropsOrState
175
+ : yMaxTimestamp;
145
176
  const scale = scaleUtc().domain([yMin, yMax]).range(range);
146
177
  let offsetMin = 0;
147
178
  let offsetMax = boundsHeight * axis.maxPadding;
@@ -186,9 +217,9 @@ function isSeriesWithXAxisOffset(series) {
186
217
  const types = [SERIES_TYPE.Heatmap];
187
218
  return series.some((s) => types.includes(s.type));
188
219
  }
189
- function getXScaleRange({ boundsWidth, series, seriesOptions, hasZoomX, axis, maxPadding, }) {
220
+ function getXScaleRange({ boundsWidth, series, seriesOptions, hasZoomX, axis, }) {
190
221
  const xAxisZoomPadding = boundsWidth * X_AXIS_ZOOM_PADDING;
191
- const xRange = [0, boundsWidth - maxPadding];
222
+ const xRange = [0, boundsWidth];
192
223
  const xRangeZoom = [0 + xAxisZoomPadding, boundsWidth - xAxisZoomPadding];
193
224
  const range = hasZoomX ? xRangeZoom : xRange;
194
225
  const barXSeries = series.filter((s) => s.type === SERIES_TYPE.BarX);
@@ -196,7 +227,7 @@ function getXScaleRange({ boundsWidth, series, seriesOptions, hasZoomX, axis, ma
196
227
  const groupedData = groupBarXDataByXValue(barXSeries, axis);
197
228
  if (Object.keys(groupedData).length > 1) {
198
229
  const { bandSize } = getBarXLayoutForNumericScale({
199
- plotWidth: boundsWidth - maxPadding,
230
+ plotWidth: boundsWidth,
200
231
  groupedData,
201
232
  seriesOptions,
202
233
  });
@@ -208,11 +239,14 @@ function getXScaleRange({ boundsWidth, series, seriesOptions, hasZoomX, axis, ma
208
239
  }
209
240
  // eslint-disable-next-line complexity
210
241
  export function createXScale(args) {
211
- var _a, _b;
212
- const { axis, boundsWidth, series, seriesOptions, hasZoomX, rangeSliderState } = args;
213
- const xMinProps = (_a = rangeSliderState === null || rangeSliderState === void 0 ? void 0 : rangeSliderState.min) !== null && _a !== void 0 ? _a : get(axis, 'min');
214
- const xMaxProps = (_b = rangeSliderState === null || rangeSliderState === void 0 ? void 0 : rangeSliderState.max) !== null && _b !== void 0 ? _b : get(axis, 'max');
242
+ const { axis, boundsWidth, series, seriesOptions, rangeSliderState, zoomStateX } = args;
243
+ const [xMinPropsOrState, xMaxPropsOrState] = getMinMaxPropsOrState({
244
+ axis,
245
+ maxValues: [zoomStateX === null || zoomStateX === void 0 ? void 0 : zoomStateX[1], rangeSliderState === null || rangeSliderState === void 0 ? void 0 : rangeSliderState.max],
246
+ minValues: [zoomStateX === null || zoomStateX === void 0 ? void 0 : zoomStateX[0], rangeSliderState === null || rangeSliderState === void 0 ? void 0 : rangeSliderState.min],
247
+ });
215
248
  const xType = get(axis, 'type', DEFAULT_AXIS_TYPE);
249
+ const hasZoomX = Boolean(zoomStateX);
216
250
  let xCategories = get(axis, 'categories');
217
251
  if (rangeSliderState && xCategories) {
218
252
  xCategories = getAxisCategories({
@@ -230,7 +264,6 @@ export function createXScale(args) {
230
264
  seriesOptions,
231
265
  hasZoomX,
232
266
  axis,
233
- maxPadding: xAxisMaxPadding,
234
267
  });
235
268
  switch (axis.order) {
236
269
  case 'sortDesc':
@@ -251,17 +284,20 @@ export function createXScale(args) {
251
284
  }
252
285
  if (hasNumberAndNullValues) {
253
286
  const [xMinDomain, xMaxDomain] = extent(domainData);
287
+ const isPointDomain = hasOnlyMarkerSeries(series)
288
+ ? checkIsPointDomain([xMinDomain, xMaxDomain])
289
+ : false;
254
290
  let xMin;
255
291
  let xMax;
256
- if (typeof xMinProps === 'number') {
257
- xMin = xMinProps;
292
+ if (typeof xMinPropsOrState === 'number' && !isPointDomain) {
293
+ xMin = xMinPropsOrState;
258
294
  }
259
295
  else {
260
296
  const xMinDefault = getDefaultMinXAxisValue(series);
261
297
  xMin = xMinDefault !== null && xMinDefault !== void 0 ? xMinDefault : xMinDomain;
262
298
  }
263
- if (typeof xMaxProps === 'number') {
264
- xMax = xMaxProps;
299
+ if (typeof xMaxPropsOrState === 'number' && !isPointDomain) {
300
+ xMax = xMaxPropsOrState;
265
301
  }
266
302
  else {
267
303
  const xMaxDefault = getDefaultMaxXAxisValue(series);
@@ -273,7 +309,7 @@ export function createXScale(args) {
273
309
  const scaleFn = xType === 'logarithmic' ? scaleLog : scaleLinear;
274
310
  const scale = scaleFn().domain([xMin, xMax]).range(range);
275
311
  let offsetMin = 0;
276
- let offsetMax = 0;
312
+ let offsetMax = xAxisMaxPadding;
277
313
  const hasOffset = isSeriesWithXAxisOffset(series);
278
314
  if (hasOffset) {
279
315
  if (domainData.length > 1) {
@@ -287,10 +323,15 @@ export function createXScale(args) {
287
323
  }
288
324
  const domainOffsetMin = Math.abs(scale.invert(offsetMin) - scale.invert(0));
289
325
  const domainOffsetMax = Math.abs(scale.invert(offsetMax) - scale.invert(0));
326
+ // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
327
+ const nicedDomain = scale.copy().nice(Math.max(10, domainData.length)).domain();
290
328
  scale.domain([xMin - domainOffsetMin, xMax + domainOffsetMax]);
291
- if (!hasZoomX && !hasOffset) {
292
- // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
293
- scale.nice(Math.max(10, domainData.length));
329
+ if (!hasZoomX && !hasOffset && nicedDomain.length === 2) {
330
+ const domainWithOffset = scale.domain();
331
+ scale.domain([
332
+ Math.min(nicedDomain[0], domainWithOffset[0]),
333
+ Math.max(nicedDomain[1], domainWithOffset[1]),
334
+ ]);
294
335
  }
295
336
  return scale;
296
337
  }
@@ -320,12 +361,21 @@ export function createXScale(args) {
320
361
  }
321
362
  if (hasNumberAndNullValues) {
322
363
  const [xMinTimestamp, xMaxTimestamp] = extent(domainData);
323
- const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
324
- const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
364
+ const isPointDomain = checkIsPointDomain([xMinTimestamp, xMaxTimestamp]);
365
+ const xMin = typeof xMinPropsOrState === 'number' &&
366
+ xMinPropsOrState > xMinTimestamp &&
367
+ !isPointDomain
368
+ ? xMinPropsOrState
369
+ : xMinTimestamp;
370
+ const xMax = typeof xMaxPropsOrState === 'number' &&
371
+ xMaxPropsOrState < xMaxTimestamp &&
372
+ !isPointDomain
373
+ ? xMaxPropsOrState
374
+ : xMaxTimestamp;
325
375
  domain = [xMin, xMax];
326
376
  const scale = scaleUtc().domain(domain).range(range);
327
377
  let offsetMin = 0;
328
- let offsetMax = 0;
378
+ let offsetMax = xAxisMaxPadding;
329
379
  const hasOffset = isSeriesWithXAxisOffset(series);
330
380
  if (hasOffset) {
331
381
  if (domainData.length > 1) {
@@ -339,10 +389,15 @@ export function createXScale(args) {
339
389
  }
340
390
  const domainOffsetMin = Math.abs(scale.invert(offsetMin).getTime() - scale.invert(0).getTime());
341
391
  const domainOffsetMax = Math.abs(scale.invert(offsetMax).getTime() - scale.invert(0).getTime());
392
+ // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
393
+ const nicedDomain = scale.copy().nice(Math.max(10, domainData.length)).domain();
342
394
  scale.domain([xMin - domainOffsetMin, xMax + domainOffsetMax]);
343
- if (!hasZoomX && !hasOffset) {
344
- // 10 is the default value for the number of ticks. Here, to preserve the appearance of a series with a small number of points
345
- scale.nice(Math.max(10, domainData.length));
395
+ if (!hasZoomX && !hasOffset && nicedDomain.length === 2) {
396
+ const domainWithOffset = scale.domain();
397
+ scale.domain([
398
+ Math.min(Number(nicedDomain[0]), Number(domainWithOffset[0])),
399
+ Math.max(Number(nicedDomain[1]), Number(domainWithOffset[1])),
400
+ ]);
346
401
  }
347
402
  return scale;
348
403
  }
@@ -352,7 +407,7 @@ export function createXScale(args) {
352
407
  throw new Error('Failed to create xScale');
353
408
  }
354
409
  const createScales = (args) => {
355
- const { boundsWidth, boundsHeight, hasZoomX, rangeSliderState, series, seriesOptions, split, xAxis, yAxis, } = args;
410
+ const { boundsWidth, boundsHeight, rangeSliderState, series, seriesOptions, split, xAxis, yAxis, zoomState, } = args;
356
411
  let visibleSeries = getOnlyVisibleSeries(series);
357
412
  // Reassign to all series in case of all series unselected,
358
413
  // otherwise we will get an empty space without grid
@@ -365,20 +420,23 @@ const createScales = (args) => {
365
420
  rangeSliderState,
366
421
  series: visibleSeries,
367
422
  seriesOptions,
368
- hasZoomX,
423
+ zoomStateX: zoomState === null || zoomState === void 0 ? void 0 : zoomState.x,
369
424
  })
370
425
  : undefined,
371
426
  yScale: yAxis.map((axis, index) => {
427
+ var _a;
372
428
  const axisSeries = series.filter((s) => {
373
429
  const seriesAxisIndex = get(s, 'yAxis', 0);
374
430
  return seriesAxisIndex === index;
375
431
  });
376
432
  const visibleAxisSeries = getOnlyVisibleSeries(axisSeries);
377
433
  const axisHeight = getAxisHeight({ boundsHeight, split });
434
+ const zoomStateY = (_a = zoomState === null || zoomState === void 0 ? void 0 : zoomState.y) === null || _a === void 0 ? void 0 : _a[index];
378
435
  return createYScale({
379
436
  axis,
380
437
  boundsHeight: axisHeight,
381
438
  series: visibleAxisSeries.length ? visibleAxisSeries : axisSeries,
439
+ zoomStateY,
382
440
  });
383
441
  }),
384
442
  };
@@ -387,7 +445,7 @@ const createScales = (args) => {
387
445
  * Uses to create scales for axis related series
388
446
  */
389
447
  export const useAxisScales = (args) => {
390
- const { boundsWidth, boundsHeight, hasZoomX, hasZoomY, rangeSliderState, series, seriesOptions, split, xAxis, yAxis, } = args;
448
+ const { boundsWidth, boundsHeight, rangeSliderState, series, seriesOptions, split, xAxis, yAxis, zoomState, } = args;
391
449
  return React.useMemo(() => {
392
450
  let xScale;
393
451
  let yScale;
@@ -396,27 +454,25 @@ export const useAxisScales = (args) => {
396
454
  ({ xScale, yScale } = createScales({
397
455
  boundsWidth,
398
456
  boundsHeight,
399
- hasZoomX,
400
- hasZoomY,
401
457
  rangeSliderState,
402
458
  series,
403
459
  seriesOptions,
404
460
  split,
405
461
  xAxis,
406
462
  yAxis,
463
+ zoomState,
407
464
  }));
408
465
  }
409
466
  return { xScale, yScale };
410
467
  }, [
411
468
  boundsWidth,
412
469
  boundsHeight,
413
- hasZoomX,
414
- hasZoomY,
415
470
  rangeSliderState,
416
471
  series,
417
472
  seriesOptions,
418
473
  split,
419
474
  xAxis,
420
475
  yAxis,
476
+ zoomState,
421
477
  ]);
422
478
  };
@@ -0,0 +1,19 @@
1
+ import type { PreparedAxis, PreparedSeries } from '../../hooks';
2
+ import type { ChartAxis, ChartSeries } from '../../types';
3
+ type OptionalNumber = number | undefined;
4
+ export declare function getMinMaxPropsOrState(args: {
5
+ axis: PreparedAxis | ChartAxis;
6
+ maxValues: OptionalNumber[];
7
+ minValues: OptionalNumber[];
8
+ }): [OptionalNumber, OptionalNumber];
9
+ /**
10
+ * Checks whether a domain represents a single point (when minimum and maximum values are equal).
11
+ *
12
+ * This is necessary for cases where exactly one marker needs to be rendered on an axis.
13
+ * In such cases, it is not allowed to use axis extremums (min/max)
14
+ * that differ from those in the domain, as this can lead to incorrect visualization
15
+ * and scale stretching around a single point.
16
+ */
17
+ export declare function checkIsPointDomain(domain: [number, number]): boolean;
18
+ export declare function hasOnlyMarkerSeries(series: (PreparedSeries | ChartSeries)[]): boolean;
19
+ export {};
@@ -0,0 +1,34 @@
1
+ import get from 'lodash/get';
2
+ import { SERIES_TYPE } from '../../constants';
3
+ const MARKER_SERIES_TYPES = [SERIES_TYPE.Area, SERIES_TYPE.Line, SERIES_TYPE.Scatter];
4
+ function getNormilizedMinMax(args) {
5
+ const { maxValues, minValues } = args;
6
+ const filteredMaxValues = maxValues.filter((v) => typeof v === 'number');
7
+ const filteredMinValues = minValues.filter((v) => typeof v === 'number');
8
+ const max = filteredMaxValues.length ? Math.max(...filteredMaxValues) : undefined;
9
+ const min = filteredMinValues.length ? Math.min(...filteredMinValues) : undefined;
10
+ return [min, max];
11
+ }
12
+ export function getMinMaxPropsOrState(args) {
13
+ const { axis, maxValues, minValues } = args;
14
+ const minProps = get(axis, 'min');
15
+ const maxProps = get(axis, 'max');
16
+ const [minState, maxState] = getNormilizedMinMax({ maxValues, minValues });
17
+ const min = minState !== null && minState !== void 0 ? minState : minProps;
18
+ const max = maxState !== null && maxState !== void 0 ? maxState : maxProps;
19
+ return [min, max];
20
+ }
21
+ /**
22
+ * Checks whether a domain represents a single point (when minimum and maximum values are equal).
23
+ *
24
+ * This is necessary for cases where exactly one marker needs to be rendered on an axis.
25
+ * In such cases, it is not allowed to use axis extremums (min/max)
26
+ * that differ from those in the domain, as this can lead to incorrect visualization
27
+ * and scale stretching around a single point.
28
+ */
29
+ export function checkIsPointDomain(domain) {
30
+ return domain[0] === domain[1];
31
+ }
32
+ export function hasOnlyMarkerSeries(series) {
33
+ return series.every((s) => MARKER_SERIES_TYPES.includes(s.type));
34
+ }
@@ -17,7 +17,7 @@ const CLIP_PATH_BY_SERIES_TYPE = {
17
17
  [SERIES_TYPE.Scatter]: true,
18
18
  };
19
19
  export function useRangeSlider(props) {
20
- const { boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
20
+ const { boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, zoomState, } = props;
21
21
  const filteredPreparedSeries = React.useMemo(() => {
22
22
  return preparedSeries.filter((s) => {
23
23
  if ('rangeSlider' in s && !s.rangeSlider.visible) {
@@ -45,6 +45,7 @@ export function useRangeSlider(props) {
45
45
  split: EMPTY_PREPARED_SPLIT,
46
46
  xAxis: preparedXAxis,
47
47
  yAxis: preparedYAxis,
48
+ zoomState,
48
49
  });
49
50
  const { shapes } = useShapes({
50
51
  boundsHeight: preparedRangeSlider.height,
@@ -4,6 +4,7 @@ import type { ChartScale } from '../useAxisScales';
4
4
  import type { BrushSelection, UseBrushProps } from '../useBrush/types';
5
5
  import type { PreparedChart } from '../useChartOptions/types';
6
6
  import type { PreparedLegend, PreparedSeries, PreparedSeriesOptions } from '../useSeries/types';
7
+ import type { ZoomState } from '../useZoom/types';
7
8
  export type RangeSliderState = {
8
9
  max: number;
9
10
  min: number;
@@ -23,6 +24,7 @@ export interface RangeSliderProps {
23
24
  rangeSliderState?: RangeSliderState;
24
25
  xAxis?: ChartXAxis;
25
26
  yAxis?: ChartYAxis[];
27
+ zoomState?: Partial<ZoomState>;
26
28
  }
27
29
  export interface UseRangeSliderProps extends RangeSliderProps {
28
30
  clipPathId: string;
@@ -1,6 +1,7 @@
1
1
  import type { PreparedXAxis, PreparedYAxis } from '../../useAxis/types';
2
2
  import type { ChartScale } from '../../useAxisScales';
3
3
  import type { PreparedAreaSeries } from '../../useSeries/types';
4
+ import type { PreparedSplit } from '../../useSplit/types';
4
5
  import type { PreparedAreaData } from './types';
5
6
  export declare const prepareAreaData: (args: {
6
7
  series: PreparedAreaSeries[];
@@ -9,5 +10,6 @@ export declare const prepareAreaData: (args: {
9
10
  yAxis: PreparedYAxis[];
10
11
  yScale: (ChartScale | undefined)[];
11
12
  boundsHeight: number;
13
+ split: PreparedSplit;
12
14
  isOutsideBounds: (x: number, y: number) => boolean;
13
15
  }) => Promise<PreparedAreaData[]>;