@gravity-ui/charts 1.38.5 → 1.38.7

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 (69) hide show
  1. package/dist/cjs/components/AxisX/prepare-axis-data.d.ts +1 -1
  2. package/dist/cjs/components/AxisX/prepare-axis-data.js +10 -9
  3. package/dist/cjs/components/AxisY/prepare-axis-data.d.ts +1 -1
  4. package/dist/cjs/components/AxisY/prepare-axis-data.js +2 -2
  5. package/dist/cjs/components/ChartInner/index.js +8 -3
  6. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +18 -19
  7. package/dist/cjs/components/ChartInner/useChartInnerProps.js +232 -138
  8. package/dist/cjs/components/ChartInner/useChartInnerState.js +2 -1
  9. package/dist/cjs/components/Legend/index.d.ts +1 -1
  10. package/dist/cjs/components/Legend/index.js +1 -1
  11. package/dist/cjs/hooks/useAxis/index.d.ts +40 -5
  12. package/dist/cjs/hooks/useAxis/index.js +55 -41
  13. package/dist/cjs/hooks/useAxis/types.d.ts +0 -2
  14. package/dist/cjs/hooks/useAxisScales/index.d.ts +4 -0
  15. package/dist/cjs/hooks/useAxisScales/index.js +1 -1
  16. package/dist/cjs/hooks/useChartDimensions/index.d.ts +1 -1
  17. package/dist/cjs/hooks/useChartDimensions/index.js +14 -29
  18. package/dist/cjs/hooks/useCrosshair/index.d.ts +1 -1
  19. package/dist/cjs/hooks/useNormalizedOriginalData/index.d.ts +29 -34
  20. package/dist/cjs/hooks/useNormalizedOriginalData/index.js +19 -30
  21. package/dist/cjs/hooks/useSeries/index.d.ts +10 -14
  22. package/dist/cjs/hooks/useSeries/index.js +8 -80
  23. package/dist/cjs/hooks/useShapes/index.d.ts +4 -0
  24. package/dist/cjs/hooks/useShapes/index.js +194 -189
  25. package/dist/cjs/hooks/useSplit/index.d.ts +5 -2
  26. package/dist/cjs/hooks/useSplit/index.js +27 -30
  27. package/dist/cjs/hooks/useYAxisLabelWidth/index.d.ts +39 -6
  28. package/dist/cjs/hooks/useYAxisLabelWidth/index.js +30 -43
  29. package/dist/cjs/hooks/useZoom/index.d.ts +1 -1
  30. package/dist/cjs/hooks/useZoom/index.js +2 -2
  31. package/dist/cjs/utils/chart/axis/common.d.ts +1 -1
  32. package/dist/cjs/utils/chart/axis/common.js +1 -1
  33. package/dist/esm/components/AxisX/prepare-axis-data.d.ts +1 -1
  34. package/dist/esm/components/AxisX/prepare-axis-data.js +10 -9
  35. package/dist/esm/components/AxisY/prepare-axis-data.d.ts +1 -1
  36. package/dist/esm/components/AxisY/prepare-axis-data.js +2 -2
  37. package/dist/esm/components/ChartInner/index.js +8 -3
  38. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +18 -19
  39. package/dist/esm/components/ChartInner/useChartInnerProps.js +232 -138
  40. package/dist/esm/components/ChartInner/useChartInnerState.js +2 -1
  41. package/dist/esm/components/Legend/index.d.ts +1 -1
  42. package/dist/esm/components/Legend/index.js +1 -1
  43. package/dist/esm/hooks/useAxis/index.d.ts +40 -5
  44. package/dist/esm/hooks/useAxis/index.js +55 -41
  45. package/dist/esm/hooks/useAxis/types.d.ts +0 -2
  46. package/dist/esm/hooks/useAxisScales/index.d.ts +4 -0
  47. package/dist/esm/hooks/useAxisScales/index.js +1 -1
  48. package/dist/esm/hooks/useChartDimensions/index.d.ts +1 -1
  49. package/dist/esm/hooks/useChartDimensions/index.js +14 -29
  50. package/dist/esm/hooks/useCrosshair/index.d.ts +1 -1
  51. package/dist/esm/hooks/useNormalizedOriginalData/index.d.ts +29 -34
  52. package/dist/esm/hooks/useNormalizedOriginalData/index.js +19 -30
  53. package/dist/esm/hooks/useSeries/index.d.ts +10 -14
  54. package/dist/esm/hooks/useSeries/index.js +8 -80
  55. package/dist/esm/hooks/useShapes/index.d.ts +4 -0
  56. package/dist/esm/hooks/useShapes/index.js +194 -189
  57. package/dist/esm/hooks/useSplit/index.d.ts +5 -2
  58. package/dist/esm/hooks/useSplit/index.js +27 -30
  59. package/dist/esm/hooks/useYAxisLabelWidth/index.d.ts +39 -6
  60. package/dist/esm/hooks/useYAxisLabelWidth/index.js +30 -43
  61. package/dist/esm/hooks/useZoom/index.d.ts +1 -1
  62. package/dist/esm/hooks/useZoom/index.js +2 -2
  63. package/dist/esm/utils/chart/axis/common.d.ts +1 -1
  64. package/dist/esm/utils/chart/axis/common.js +1 -1
  65. package/package.json +1 -1
  66. package/dist/cjs/components/ChartInner/useLegend.d.ts +0 -14
  67. package/dist/cjs/components/ChartInner/useLegend.js +0 -34
  68. package/dist/esm/components/ChartInner/useLegend.d.ts +0 -14
  69. package/dist/esm/components/ChartInner/useLegend.js +0 -34
@@ -8,6 +8,6 @@ export declare function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetR
8
8
  height: number;
9
9
  scale: ChartScale;
10
10
  series: PreparedSeries[];
11
- split: PreparedSplit;
11
+ split: PreparedSplit | undefined;
12
12
  yAxis: PreparedAxis[];
13
13
  }): Promise<AxisXData[]>;
@@ -70,19 +70,20 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
70
70
  }
71
71
  // eslint-disable-next-line complexity
72
72
  export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRight, boundsWidth, height, scale, series, split, yAxis, }) {
73
- var _a, _b, _c, _d, _e, _f;
73
+ var _a, _b, _c, _d, _e, _f, _g;
74
74
  const xAxisItems = [];
75
- for (let plotIndex = 0; plotIndex < split.plots.length; plotIndex++) {
76
- const plot = split.plots[plotIndex];
75
+ const splitPlots = (_a = split === null || split === void 0 ? void 0 : split.plots) !== null && _a !== void 0 ? _a : [];
76
+ for (let plotIndex = 0; plotIndex < splitPlots.length; plotIndex++) {
77
+ const plot = splitPlots[plotIndex];
77
78
  const axisTop = plot.top;
78
79
  const axisHeight = plot.height;
79
80
  const axisWidth = boundsWidth;
80
- const isBottomPlot = plotIndex === split.plots.length - 1;
81
+ const isBottomPlot = plotIndex === splitPlots.length - 1;
81
82
  const plotYAxes = yAxis.filter((a) => a.plotIndex === plotIndex);
82
- const yDomainLeftPosition = ((_a = plotYAxes.find((a) => a.position === 'left')) === null || _a === void 0 ? void 0 : _a.visible)
83
+ const yDomainLeftPosition = ((_b = plotYAxes.find((a) => a.position === 'left')) === null || _b === void 0 ? void 0 : _b.visible)
83
84
  ? 0
84
85
  : null;
85
- const yDomainRightPosition = ((_b = plotYAxes.find((a) => a.position === 'right')) === null || _b === void 0 ? void 0 : _b.visible)
86
+ const yDomainRightPosition = ((_c = plotYAxes.find((a) => a.position === 'right')) === null || _c === void 0 ? void 0 : _c.visible)
86
87
  ? axisWidth
87
88
  : null;
88
89
  let domain = null;
@@ -90,7 +91,7 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
90
91
  domain = {
91
92
  start: [0, axisTop + axisHeight],
92
93
  end: [axisWidth, axisTop + axisHeight],
93
- lineColor: (_c = axis.lineColor) !== null && _c !== void 0 ? _c : '',
94
+ lineColor: (_d = axis.lineColor) !== null && _d !== void 0 ? _d : '',
94
95
  };
95
96
  }
96
97
  const ticks = [];
@@ -255,7 +256,7 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
255
256
  axisScale,
256
257
  axis: 'x',
257
258
  });
258
- const halfBandwidth = ((_e = (_d = axisScale.bandwidth) === null || _d === void 0 ? void 0 : _d.call(axisScale)) !== null && _e !== void 0 ? _e : 0) / 2;
259
+ const halfBandwidth = ((_f = (_e = axisScale.bandwidth) === null || _e === void 0 ? void 0 : _e.call(axisScale)) !== null && _f !== void 0 ? _f : 0) / 2;
259
260
  const startPos = halfBandwidth + Math.min(from, to);
260
261
  const endPos = Math.min(Math.abs(to - from), axisWidth - Math.min(from, to));
261
262
  const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
@@ -279,7 +280,7 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
279
280
  text: plotBand.label.text,
280
281
  style: plotBand.label.style,
281
282
  x: plotBand.label.padding,
282
- y: plotBand.label.padding + ((_f = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _f !== void 0 ? _f : 0),
283
+ y: plotBand.label.padding + ((_g = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _g !== void 0 ? _g : 0),
283
284
  rotate: -90,
284
285
  qa: plotBand.label.qa,
285
286
  }
@@ -2,7 +2,7 @@ import type { ChartScale, PreparedAxis, PreparedSeries, PreparedSplit } from '..
2
2
  import type { AxisYData } from './types';
3
3
  export declare function prepareYAxisData({ axis, split, scale, top: topOffset, width, height, series, }: {
4
4
  axis: PreparedAxis;
5
- split: PreparedSplit;
5
+ split: PreparedSplit | undefined;
6
6
  scale: ChartScale;
7
7
  top: number;
8
8
  width: number;
@@ -110,8 +110,8 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxHei
110
110
  }
111
111
  export async function prepareYAxisData({ axis, split, scale, top: topOffset, width, height, series, }) {
112
112
  var _a, _b, _c;
113
- const axisPlotTopPosition = ((_a = split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
114
- const axisHeight = ((_b = split.plots[axis.plotIndex]) === null || _b === void 0 ? void 0 : _b.height) || height;
113
+ const axisPlotTopPosition = ((_a = split === null || split === void 0 ? void 0 : split.plots[axis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
114
+ const axisHeight = ((_b = split === null || split === void 0 ? void 0 : split.plots[axis.plotIndex]) === null || _b === void 0 ? void 0 : _b.height) || height;
115
115
  const domainX = axis.position === 'left' ? 0 : width;
116
116
  let domain = null;
117
117
  if (axis.visible) {
@@ -63,12 +63,14 @@ export const ChartInner = (props) => {
63
63
  preparedRangeSlider,
64
64
  tooltip: preparedTooltip,
65
65
  });
66
- const { allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, isOutsideBounds, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, prevHeight, prevWidth, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
66
+ const { allPreparedSeries, boundsHeight, boundsOffsetLeft, boundsOffsetTop, boundsWidth, handleLegendItemClick, isOutsideBounds, legendConfig, legendItems, preparedLegend, preparedSeries, preparedSeriesOptions, preparedSplit, shapes, shapesData, shapesReady, xAxis, xScale, yAxis, yScale, } = useChartInnerProps(Object.assign(Object.assign({}, props), { clipPathId,
67
67
  dispatcher,
68
68
  htmlLayout, plotNode: plotRef.current, preparedChart,
69
69
  rangeSliderState,
70
70
  updateZoomState,
71
71
  zoomState }));
72
+ const prevWidth = usePrevious(width);
73
+ const prevHeight = usePrevious(height);
72
74
  const debouncedBoundsWidth = useDebouncedValue({
73
75
  value: boundsWidth,
74
76
  delay: DEBOUNCED_VALUE_DELAY,
@@ -237,7 +239,7 @@ export const ChartInner = (props) => {
237
239
  React.createElement("clipPath", { id: getClipPathIdByBounds({ clipPathId, bounds: 'horizontal' }) },
238
240
  React.createElement("rect", { x: 0, y: -boundsHeight, width: boundsWidth, height: boundsHeight * 3 }))),
239
241
  preparedTitle && React.createElement(Title, Object.assign({}, preparedTitle, { chartWidth: width })),
240
- React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit.plots.map((plot, index) => {
242
+ React.createElement("g", { transform: `translate(0, ${boundsOffsetTop})` }, preparedSplit === null || preparedSplit === void 0 ? void 0 : preparedSplit.plots.map((plot, index) => {
241
243
  return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
242
244
  })),
243
245
  React.createElement("g", { className: b('content'), width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
@@ -253,7 +255,10 @@ export const ChartInner = (props) => {
253
255
  React.createElement("g", { ref: plotBeforeRef }),
254
256
  shapes,
255
257
  React.createElement("g", { ref: plotAfterRef })),
256
- ((_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, ref: rangeSliderRef, width: width, xAxis: data.xAxis, yAxis: data.yAxis, legendConfig: legendConfig })),
258
+ ((_e = xAxis === null || xAxis === void 0 ? void 0 : xAxis.rangeSlider) === null || _e === void 0 ? void 0 : _e.enabled) &&
259
+ preparedLegend &&
260
+ debouncedAllPreparedSeries &&
261
+ preparedSeriesOptions && (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, ref: rangeSliderRef, width: width, xAxis: data.xAxis, yAxis: data.yAxis, legendConfig: legendConfig })),
257
262
  (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 }))));
258
263
  return (React.createElement("div", { className: b() },
259
264
  React.createElement("svg", { ref: svgRef, width: width, height: height,
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import type { Dispatch } from 'd3';
3
- import type { PreparedChart, PreparedLegend, RangeSliderState, ZoomState } from '../../hooks';
3
+ import type { ChartScale, LegendItem, OnLegendItemClick, PreparedChart, PreparedLegend, PreparedSeries, PreparedSplit, PreparedXAxis, RangeSliderState, ShapeData, ZoomState } from '../../hooks';
4
4
  import type { LegendConfig } from '../../types';
5
5
  import type { ChartInnerProps } from './types';
6
6
  type Props = ChartInnerProps & {
@@ -14,26 +14,12 @@ type Props = ChartInnerProps & {
14
14
  rangeSliderState?: RangeSliderState;
15
15
  };
16
16
  export declare function useChartInnerProps(props: Props): {
17
- allPreparedSeries: import("../../hooks").PreparedSeries[];
18
- boundsHeight: number;
17
+ preparedSeries: PreparedSeries[];
19
18
  boundsOffsetLeft: number;
20
19
  boundsOffsetTop: number;
20
+ boundsHeight: number;
21
21
  boundsWidth: number;
22
- handleLegendItemClick: import("../../hooks").OnLegendItemClick;
23
- isOutsideBounds: (x: number, y: number) => boolean;
24
- legendConfig: LegendConfig | undefined;
25
- legendItems: import("../../hooks").LegendItem[][];
26
- preparedLegend: PreparedLegend | null;
27
- preparedSeries: import("../../hooks").PreparedSeries[];
28
- preparedSeriesOptions: import("../../constants").SeriesOptionsDefaults;
29
- preparedSplit: import("../../hooks").PreparedSplit;
30
- prevHeight: number | undefined;
31
- prevWidth: number | undefined;
32
- shapes: React.ReactElement<any, string | React.JSXElementConstructor<any>>[];
33
- shapesData: import("../../hooks").ShapeData[];
34
- shapesReady: boolean;
35
- xAxis: import("../../hooks").PreparedXAxis | null;
36
- xScale: import("../../hooks").ChartScale | undefined;
22
+ xAxis: PreparedXAxis | null;
37
23
  yAxis: (Omit<import("../../types").ChartAxis, "type" | "labels" | "plotLines" | "plotBands"> & {
38
24
  type: import("../../types").ChartAxisType;
39
25
  labels: Omit<import("../../types").ChartAxisLabels, "enabled" | "style" | "padding" | "autoRotation"> & Required<Pick<import("../../types").ChartAxisLabels, "margin" | "html" | "enabled" | "rotation" | "padding">> & {
@@ -71,6 +57,19 @@ export declare function useChartInnerProps(props: Props): {
71
57
  plotBands: import("../../hooks").PreparedAxisPlotBand[];
72
58
  crosshair: Required<import("../../types").AxisCrosshair>;
73
59
  })[];
74
- yScale: (import("../../hooks").ChartScale | undefined)[] | undefined;
60
+ shapesData: ShapeData[];
61
+ shapesReady: boolean;
62
+ handleLegendItemClick: OnLegendItemClick;
63
+ isOutsideBounds: (x: number, y: number) => boolean;
64
+ allPreparedSeries?: PreparedSeries[] | undefined;
65
+ legendConfig?: LegendConfig | undefined;
66
+ legendItems?: LegendItem[][] | undefined;
67
+ preparedLegend?: PreparedLegend | undefined;
68
+ preparedSeriesOptions?: import("../../constants").SeriesOptionsDefaults | undefined;
69
+ preparedSplit?: PreparedSplit | undefined;
70
+ shapes?: React.ReactElement<any, string | React.JSXElementConstructor<any>>[] | undefined;
71
+ xScale?: ChartScale | undefined;
72
+ yScale?: (ChartScale | undefined)[] | undefined;
73
+ activeLegendItems?: string[] | undefined;
75
74
  };
76
75
  export {};
@@ -1,10 +1,12 @@
1
1
  import React from 'react';
2
+ import isEqual from 'lodash/isEqual';
2
3
  import { DEFAULT_PALETTE, SERIES_TYPE } from '../../constants';
3
- import { useAxis, useAxisScales, useChartDimensions, useNormalizedOriginalData, usePrevious, useSeries, useShapes, useSplit, useYAxisLabelWidth, useZoom, } from '../../hooks';
4
+ import { createScales, getAxes, getChartDimensions, getNormalizedXAxis, getNormalizedYAxis, getPreparedSeries, getShapes, getSplit, getVisibleSeries, recalculateYAxisLabelsWidth, useZoom, } from '../../hooks';
4
5
  import { getYAxisWidth } from '../../hooks/useChartDimensions/utils';
6
+ import { getLegendComponents, getPreparedLegend } from '../../hooks/useSeries/prepare-legend';
5
7
  import { getPreparedOptions } from '../../hooks/useSeries/prepare-options';
6
- import { getEffectiveXRange, getZoomedSeriesData } from '../../utils';
7
- import { useLegend } from './useLegend';
8
+ import { getActiveLegendItems, getAllLegendItems } from '../../hooks/useSeries/utils';
9
+ import { getEffectiveXRange, getSortedSeriesData, getZoomedSeriesData, isAxisRelatedSeries, } from '../../utils';
8
10
  import { hasAtLeastOneSeriesDataPerPlot } from './utils';
9
11
  const CLIP_PATH_BY_SERIES_TYPE = {
10
12
  [SERIES_TYPE.Scatter]: false,
@@ -34,111 +36,235 @@ function getBoundsOffsetLeft(args) {
34
36
  }, 0);
35
37
  return chartMarginLeft + legendOffset + leftAxisWidth;
36
38
  }
39
+ // eslint-disable-next-line complexity
37
40
  export function useChartInnerProps(props) {
41
+ var _a, _b, _c, _d, _e, _f, _g, _h;
38
42
  const { clipPathId, data, dispatcher, height, htmlLayout, plotNode, preparedChart, rangeSliderState, width, updateZoomState, zoomState, } = props;
39
- const prevWidth = usePrevious(width);
40
- const prevHeight = usePrevious(height);
41
- const colors = React.useMemo(() => {
42
- var _a;
43
- return (_a = data.colors) !== null && _a !== void 0 ? _a : DEFAULT_PALETTE;
44
- }, [data.colors]);
45
- const { normalizedSeriesData, normalizedXAxis, normalizedYAxis } = useNormalizedOriginalData({
46
- seriesData: data.series.data,
47
- xAxis: data.xAxis,
48
- yAxis: data.yAxis,
49
- });
50
- const preparedSeriesOptions = React.useMemo(() => {
51
- return getPreparedOptions(data.series.options);
52
- }, [data.series.options]);
53
- const { preparedSeries: allPreparedSeries, preparedLegend, handleLegendItemClick, } = useSeries({
54
- colors,
55
- legend: data.legend,
56
- originalSeriesData: normalizedSeriesData,
57
- seriesData: normalizedSeriesData,
58
- seriesOptions: data.series.options,
59
- });
60
- const effectiveZoomState = React.useMemo(() => {
61
- const result = {};
62
- const effectiveX = getEffectiveXRange(zoomState.x, rangeSliderState);
63
- if (effectiveX !== undefined) {
64
- result.x = effectiveX;
65
- }
66
- if (zoomState.y !== undefined) {
67
- result.y = zoomState.y;
68
- }
69
- return result;
70
- }, [zoomState, rangeSliderState]);
71
- const { preparedSeries, preparedShapesSeries } = React.useMemo(() => {
72
- return getZoomedSeriesData({
73
- seriesData: allPreparedSeries,
74
- xAxis: normalizedXAxis,
75
- yAxis: normalizedYAxis,
76
- zoomState: effectiveZoomState,
77
- });
78
- }, [allPreparedSeries, normalizedXAxis, normalizedYAxis, effectiveZoomState]);
79
- const { legendConfig, legendItems } = useLegend({
80
- width,
81
- height,
82
- preparedChart,
83
- preparedSeries,
84
- preparedLegend,
85
- });
86
- const { xAxis, yAxis, setAxes } = useAxis({
43
+ const [selectedLegendItems, setSelectedLegendItems] = React.useState(null);
44
+ const [chartState, setState] = React.useState(null);
45
+ const prevStateValue = React.useRef(chartState);
46
+ const previousChartData = React.useRef(null);
47
+ const currentRunRef = React.useRef(0);
48
+ React.useEffect(() => {
49
+ currentRunRef.current++;
50
+ const currentRun = currentRunRef.current;
51
+ (async function () {
52
+ var _a, _b, _c;
53
+ const chartDataChanged = !(previousChartData.current && isEqual(previousChartData.current, data));
54
+ const colors = (_a = data.colors) !== null && _a !== void 0 ? _a : DEFAULT_PALETTE;
55
+ const normalizedSeriesData = getSortedSeriesData({
56
+ seriesData: data.series.data,
57
+ xAxis: data.xAxis,
58
+ yAxis: data.yAxis,
59
+ });
60
+ const normalizedXAxis = getNormalizedXAxis({ xAxis: data.xAxis });
61
+ const normalizedYAxis = getNormalizedYAxis({ yAxis: data.yAxis });
62
+ const preparedSeriesOptions = getPreparedOptions(data.series.options);
63
+ const preparedLegend = await getPreparedLegend({
64
+ legend: data.legend,
65
+ series: normalizedSeriesData,
66
+ });
67
+ let allPreparedSeries;
68
+ if (chartDataChanged) {
69
+ allPreparedSeries = await getPreparedSeries({
70
+ seriesData: normalizedSeriesData,
71
+ seriesOptions: data.series.options,
72
+ preparedLegend,
73
+ colors,
74
+ });
75
+ }
76
+ else {
77
+ allPreparedSeries = (_c = (_b = prevStateValue.current) === null || _b === void 0 ? void 0 : _b.allPreparedSeries) !== null && _c !== void 0 ? _c : [];
78
+ }
79
+ const activeLegendItems = selectedLegendItems !== null && selectedLegendItems !== void 0 ? selectedLegendItems : getActiveLegendItems(allPreparedSeries);
80
+ const visiblePreparedSeries = getVisibleSeries({
81
+ preparedSeries: allPreparedSeries,
82
+ activeLegendItems,
83
+ });
84
+ const effectiveZoomState = {};
85
+ const effectiveX = getEffectiveXRange(zoomState.x, rangeSliderState);
86
+ if (effectiveX !== undefined) {
87
+ effectiveZoomState.x = effectiveX;
88
+ }
89
+ if (zoomState.y !== undefined) {
90
+ effectiveZoomState.y = zoomState.y;
91
+ }
92
+ const { preparedSeries, preparedShapesSeries } = getZoomedSeriesData({
93
+ seriesData: visiblePreparedSeries,
94
+ xAxis: normalizedXAxis,
95
+ yAxis: normalizedYAxis,
96
+ zoomState: effectiveZoomState,
97
+ });
98
+ const { legendConfig, legendItems } = await getLegendComponents({
99
+ chartWidth: width,
100
+ chartHeight: height,
101
+ chartMargin: preparedChart.margin,
102
+ series: preparedSeries,
103
+ preparedLegend,
104
+ });
105
+ const axes = await getAxes({
106
+ height,
107
+ preparedChart,
108
+ legendConfig,
109
+ preparedLegend,
110
+ preparedSeries,
111
+ preparedSeriesOptions,
112
+ width,
113
+ xAxis: normalizedXAxis,
114
+ yAxis: normalizedYAxis,
115
+ });
116
+ const xAxis = axes.xAxis;
117
+ let yAxis = axes.yAxis;
118
+ let preparedSplit = { plots: [], gap: 0 };
119
+ let xScale;
120
+ let yScale;
121
+ let boundsWidth = 0;
122
+ let boundsHeight = 0;
123
+ const calculateAxisBasedProps = () => {
124
+ const chartDimensions = getChartDimensions({
125
+ height,
126
+ margin: preparedChart.margin,
127
+ preparedLegend,
128
+ preparedSeries: preparedSeries,
129
+ preparedYAxis: yAxis,
130
+ preparedXAxis: xAxis,
131
+ width,
132
+ legendConfig,
133
+ });
134
+ boundsHeight = chartDimensions.boundsHeight;
135
+ boundsWidth = chartDimensions.boundsWidth;
136
+ preparedSplit = getSplit({ split: data.split, boundsHeight, chartWidth: width });
137
+ if (preparedSeries.some(isAxisRelatedSeries)) {
138
+ ({ xScale, yScale } = createScales({
139
+ boundsWidth,
140
+ boundsHeight,
141
+ isRangeSlider: false,
142
+ rangeSliderState,
143
+ series: preparedSeries,
144
+ split: preparedSplit,
145
+ xAxis,
146
+ yAxis,
147
+ zoomState,
148
+ }));
149
+ }
150
+ };
151
+ calculateAxisBasedProps();
152
+ const newYAxis = await recalculateYAxisLabelsWidth({
153
+ seriesData: preparedSeries,
154
+ yAxis,
155
+ yScale,
156
+ });
157
+ if (!isEqual(yAxis, newYAxis)) {
158
+ yAxis = newYAxis;
159
+ calculateAxisBasedProps();
160
+ }
161
+ const isOutsideBounds = (x, y) => {
162
+ return x < 0 || x > boundsWidth || y < 0 || y > boundsHeight;
163
+ };
164
+ const { shapes, shapesData } = await getShapes({
165
+ boundsWidth,
166
+ boundsHeight,
167
+ clipPathBySeriesType: CLIP_PATH_BY_SERIES_TYPE,
168
+ dispatcher,
169
+ series: preparedShapesSeries,
170
+ seriesOptions: preparedSeriesOptions,
171
+ xAxis,
172
+ xScale,
173
+ yAxis,
174
+ yScale,
175
+ split: preparedSplit,
176
+ htmlLayout,
177
+ clipPathId,
178
+ isOutsideBounds,
179
+ zoomState: effectiveZoomState,
180
+ });
181
+ const boundsOffsetTop = getBoundsOffsetTop({
182
+ chartMarginTop: preparedChart.margin.top,
183
+ preparedLegend,
184
+ legendConfig,
185
+ });
186
+ // We need to calculate the width of each left axis because the first axis can be hidden
187
+ const boundsOffsetLeft = getBoundsOffsetLeft({
188
+ chartMarginLeft: preparedChart.margin.left,
189
+ preparedLegend,
190
+ yAxis,
191
+ getYAxisWidth,
192
+ legendConfig,
193
+ });
194
+ //end
195
+ const newStateValue = {
196
+ allPreparedSeries,
197
+ boundsHeight,
198
+ boundsOffsetLeft,
199
+ boundsOffsetTop,
200
+ boundsWidth,
201
+ isOutsideBounds,
202
+ legendConfig,
203
+ legendItems,
204
+ preparedLegend,
205
+ preparedSeries,
206
+ preparedSeriesOptions,
207
+ preparedSplit,
208
+ shapes,
209
+ shapesData,
210
+ xAxis,
211
+ xScale,
212
+ yAxis,
213
+ yScale,
214
+ activeLegendItems,
215
+ };
216
+ if (currentRunRef.current === currentRun) {
217
+ if (!isEqual(prevStateValue.current, newStateValue)) {
218
+ setState(newStateValue);
219
+ prevStateValue.current = newStateValue;
220
+ }
221
+ previousChartData.current = data;
222
+ }
223
+ })();
224
+ }, [
87
225
  height,
88
- preparedChart,
89
- legendConfig,
90
- preparedLegend,
91
- preparedSeries,
92
- preparedSeriesOptions,
93
226
  width,
94
- xAxis: normalizedXAxis,
95
- yAxis: normalizedYAxis,
96
- });
97
- const { boundsWidth, boundsHeight } = useChartDimensions({
98
- height,
99
- margin: preparedChart.margin,
100
- preparedLegend,
101
- preparedSeries: preparedSeries,
102
- preparedYAxis: yAxis,
103
- preparedXAxis: xAxis,
104
- width,
105
- legendConfig,
106
- });
107
- const preparedSplit = useSplit({ split: data.split, boundsHeight, chartWidth: width });
108
- const { xScale, yScale } = useAxisScales({
109
- boundsWidth,
110
- boundsHeight,
111
- rangeSliderState,
112
- series: preparedSeries,
113
- split: preparedSplit,
114
- xAxis,
115
- yAxis,
227
+ data,
228
+ selectedLegendItems,
116
229
  zoomState,
117
- });
118
- useYAxisLabelWidth({ seriesData: preparedSeries, setAxes, yAxis, yScale });
119
- const isOutsideBounds = React.useCallback((x, y) => {
120
- return x < 0 || x > boundsWidth || y < 0 || y > boundsHeight;
121
- }, [boundsHeight, boundsWidth]);
122
- const { shapes, shapesData, shapesReady } = useShapes({
123
- boundsWidth,
124
- boundsHeight,
125
- clipPathBySeriesType: CLIP_PATH_BY_SERIES_TYPE,
230
+ rangeSliderState,
231
+ preparedChart,
126
232
  dispatcher,
127
- series: preparedShapesSeries,
128
- seriesOptions: preparedSeriesOptions,
129
- xAxis,
130
- xScale,
131
- yAxis,
132
- yScale,
133
- split: preparedSplit,
134
233
  htmlLayout,
135
234
  clipPathId,
136
- isOutsideBounds,
137
- zoomState: effectiveZoomState,
138
- });
139
- const handleAttemptToSetZoomState = React.useCallback((nextZoomState) => {
235
+ ]);
236
+ // additional start
237
+ const preparedSeries = React.useMemo(() => { var _a; return (_a = chartState === null || chartState === void 0 ? void 0 : chartState.preparedSeries) !== null && _a !== void 0 ? _a : []; }, [chartState === null || chartState === void 0 ? void 0 : chartState.preparedSeries]);
238
+ const activeLegendItems = React.useMemo(() => { var _a; return (_a = chartState === null || chartState === void 0 ? void 0 : chartState.activeLegendItems) !== null && _a !== void 0 ? _a : []; }, [chartState === null || chartState === void 0 ? void 0 : chartState.activeLegendItems]);
239
+ const boundsHeight = (_a = chartState === null || chartState === void 0 ? void 0 : chartState.boundsHeight) !== null && _a !== void 0 ? _a : 0;
240
+ const boundsWidth = (_b = chartState === null || chartState === void 0 ? void 0 : chartState.boundsWidth) !== null && _b !== void 0 ? _b : 0;
241
+ const handleLegendItemClick = React.useCallback(({ id, metaKey }) => {
242
+ const allItems = getAllLegendItems(preparedSeries);
243
+ const onlyItemSelected = (selectedLegendItems !== null && selectedLegendItems !== void 0 ? selectedLegendItems : []).length === 1 && activeLegendItems.includes(id);
244
+ let nextActiveLegendItems;
245
+ if (metaKey && activeLegendItems.includes(id)) {
246
+ nextActiveLegendItems = activeLegendItems.filter((item) => item !== id);
247
+ }
248
+ else if (metaKey && !activeLegendItems.includes(id)) {
249
+ nextActiveLegendItems = activeLegendItems.concat(id);
250
+ }
251
+ else if (onlyItemSelected && allItems.length === 1) {
252
+ nextActiveLegendItems = [];
253
+ }
254
+ else if (onlyItemSelected) {
255
+ nextActiveLegendItems = allItems;
256
+ }
257
+ else {
258
+ nextActiveLegendItems = [id];
259
+ }
260
+ setSelectedLegendItems(nextActiveLegendItems);
261
+ }, [preparedSeries, selectedLegendItems, activeLegendItems]);
262
+ const xAxis = (_c = chartState === null || chartState === void 0 ? void 0 : chartState.xAxis) !== null && _c !== void 0 ? _c : null;
263
+ const yAxis = (_d = chartState === null || chartState === void 0 ? void 0 : chartState.yAxis) !== null && _d !== void 0 ? _d : [];
264
+ const handleAttemptToSetZoomState = (nextZoomState) => {
265
+ var _a;
140
266
  const { preparedSeries: nextZoomedSeriesData } = getZoomedSeriesData({
141
- seriesData: preparedSeries,
267
+ seriesData: (_a = chartState === null || chartState === void 0 ? void 0 : chartState.preparedSeries) !== null && _a !== void 0 ? _a : [],
142
268
  xAxis,
143
269
  yAxis,
144
270
  zoomState: nextZoomState,
@@ -147,54 +273,22 @@ export function useChartInnerProps(props) {
147
273
  if (hasData) {
148
274
  updateZoomState(nextZoomState);
149
275
  }
150
- }, [xAxis, yAxis, preparedSeries, updateZoomState]);
276
+ };
151
277
  useZoom({
152
278
  node: plotNode,
153
279
  onUpdate: handleAttemptToSetZoomState,
154
280
  plotContainerHeight: boundsHeight,
155
281
  plotContainerWidth: boundsWidth,
156
- preparedSplit,
282
+ preparedSplit: chartState === null || chartState === void 0 ? void 0 : chartState.preparedSplit,
157
283
  preparedZoom: preparedChart.zoom,
158
284
  xAxis,
159
- xScale,
285
+ xScale: chartState === null || chartState === void 0 ? void 0 : chartState.xScale,
160
286
  yAxis,
161
- yScale,
162
- });
163
- const boundsOffsetTop = getBoundsOffsetTop({
164
- chartMarginTop: preparedChart.margin.top,
165
- preparedLegend,
166
- legendConfig,
287
+ yScale: chartState === null || chartState === void 0 ? void 0 : chartState.yScale,
167
288
  });
168
- // We need to calculate the width of each left axis because the first axis can be hidden
169
- const boundsOffsetLeft = getBoundsOffsetLeft({
170
- chartMarginLeft: preparedChart.margin.left,
171
- preparedLegend,
172
- yAxis,
173
- getYAxisWidth,
174
- legendConfig,
175
- });
176
- return {
177
- allPreparedSeries,
178
- boundsHeight,
179
- boundsOffsetLeft,
180
- boundsOffsetTop,
289
+ // additional end
290
+ return Object.assign(Object.assign({}, chartState), { preparedSeries, boundsOffsetLeft: (_e = chartState === null || chartState === void 0 ? void 0 : chartState.boundsOffsetLeft) !== null && _e !== void 0 ? _e : 0, boundsOffsetTop: (_f = chartState === null || chartState === void 0 ? void 0 : chartState.boundsOffsetTop) !== null && _f !== void 0 ? _f : 0, boundsHeight,
181
291
  boundsWidth,
182
- handleLegendItemClick,
183
- isOutsideBounds,
184
- legendConfig,
185
- legendItems,
186
- preparedLegend,
187
- preparedSeries,
188
- preparedSeriesOptions,
189
- preparedSplit,
190
- prevHeight,
191
- prevWidth,
192
- shapes,
193
- shapesData,
194
- shapesReady,
195
292
  xAxis,
196
- xScale,
197
- yAxis,
198
- yScale,
199
- };
293
+ yAxis, shapesData: (_g = chartState === null || chartState === void 0 ? void 0 : chartState.shapesData) !== null && _g !== void 0 ? _g : [], shapesReady: Boolean(chartState), handleLegendItemClick, isOutsideBounds: (_h = chartState === null || chartState === void 0 ? void 0 : chartState.isOutsideBounds) !== null && _h !== void 0 ? _h : (() => false) });
200
294
  }
@@ -41,8 +41,9 @@ export function useChartInnerState(props) {
41
41
  else if (nextZoomState.x !== undefined) {
42
42
  setRangeSliderState({ min: nextZoomState.x[0], max: nextZoomState.x[1] });
43
43
  }
44
+ dispatcher.call(EventType.HOVER_SHAPE, {}, undefined);
44
45
  }
45
- }, [zoomState]);
46
+ }, [dispatcher, zoomState]);
46
47
  const updateRangeSliderState = React.useCallback((nextRangeSliderState) => {
47
48
  if (!isEqual(rangeSliderState, nextRangeSliderState)) {
48
49
  setRangeSliderState(nextRangeSliderState
@@ -5,7 +5,7 @@ import './styles.css';
5
5
  type Props = {
6
6
  chartSeries: PreparedSeries[];
7
7
  legend: PreparedLegend;
8
- items: LegendItem[][];
8
+ items: LegendItem[][] | undefined;
9
9
  config: LegendConfig;
10
10
  htmlLayout: HTMLElement | null;
11
11
  onItemClick: OnLegendItemClick;
@@ -130,7 +130,7 @@ function renderLegendSymbol(args) {
130
130
  });
131
131
  }
132
132
  export const Legend = (props) => {
133
- const { chartSeries, legend, items, config, htmlLayout, onItemClick, onUpdate } = props;
133
+ const { chartSeries, legend, items = [], config, htmlLayout, onItemClick, onUpdate } = props;
134
134
  const ref = React.useRef(null);
135
135
  const [pageIndex, setPageIndex] = React.useState(0);
136
136
  React.useEffect(() => {