@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.
- package/dist/cjs/components/ChartInner/index.js +2 -1
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +1 -2
- package/dist/cjs/hooks/useAxisScales/index.d.ts +4 -4
- package/dist/cjs/hooks/useAxisScales/index.js +95 -39
- package/dist/cjs/hooks/useAxisScales/utils.d.ts +19 -0
- package/dist/cjs/hooks/useAxisScales/utils.js +34 -0
- package/dist/cjs/hooks/useRangeSlider/index.js +2 -1
- package/dist/cjs/hooks/useRangeSlider/types.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +159 -158
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.d.ts +2 -0
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +87 -72
- package/dist/cjs/hooks/useShapes/index.js +2 -0
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +1 -1
- package/dist/cjs/hooks/useShapes/styles.css +5 -13
- package/dist/cjs/utils/chart/index.js +1 -1
- package/dist/esm/components/ChartInner/index.js +2 -1
- package/dist/esm/components/ChartInner/useChartInnerProps.js +1 -2
- package/dist/esm/hooks/useAxisScales/index.d.ts +4 -4
- package/dist/esm/hooks/useAxisScales/index.js +95 -39
- package/dist/esm/hooks/useAxisScales/utils.d.ts +19 -0
- package/dist/esm/hooks/useAxisScales/utils.js +34 -0
- package/dist/esm/hooks/useRangeSlider/index.js +2 -1
- package/dist/esm/hooks/useRangeSlider/types.d.ts +2 -0
- package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +2 -0
- package/dist/esm/hooks/useShapes/area/prepare-data.js +159 -158
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.d.ts +2 -0
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +87 -72
- package/dist/esm/hooks/useShapes/index.js +2 -0
- package/dist/esm/hooks/useShapes/line/prepare-data.js +1 -1
- package/dist/esm/hooks/useShapes/styles.css +5 -13
- package/dist/esm/utils/chart/index.js +1 -1
- 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
|
|
70
|
-
|
|
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
|
|
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
|
|
90
|
-
yMax =
|
|
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
|
|
132
|
-
|
|
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
|
|
144
|
-
|
|
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,
|
|
220
|
+
function getXScaleRange({ boundsWidth, series, seriesOptions, hasZoomX, axis, }) {
|
|
190
221
|
const xAxisZoomPadding = boundsWidth * X_AXIS_ZOOM_PADDING;
|
|
191
|
-
const xRange = [0, boundsWidth
|
|
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
|
|
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
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
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
|
|
257
|
-
xMin =
|
|
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
|
|
264
|
-
xMax =
|
|
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 =
|
|
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
|
-
|
|
293
|
-
scale.
|
|
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
|
|
324
|
-
const
|
|
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 =
|
|
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
|
-
|
|
345
|
-
scale.
|
|
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,
|
|
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
|
-
|
|
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,
|
|
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[]>;
|