@gravity-ui/charts 1.11.3 → 1.11.4

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.
@@ -100,7 +100,7 @@ export const ChartInner = (props) => {
100
100
  React.createElement("g", { ref: plotBeforeRef }),
101
101
  shapes,
102
102
  React.createElement("g", { ref: plotAfterRef })),
103
- (preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries, boundsWidth: boundsWidth, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayout }))),
103
+ (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 }))),
104
104
  React.createElement("div", { className: b('html-layer'), ref: setHtmlLayout, style: {
105
105
  '--g-html-layout-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
106
106
  } }),
@@ -31,6 +31,7 @@ export declare function useChartInnerProps(props: Props): {
31
31
  end: number;
32
32
  }[];
33
33
  } | undefined;
34
+ maxWidth: number;
34
35
  } | undefined;
35
36
  legendItems: never[] | import("../../hooks").LegendItem[][];
36
37
  preparedLegend: import("../../hooks").PreparedLegend | null;
@@ -1,10 +1,11 @@
1
1
  import React from 'react';
2
- import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapes, useSplit, } from '../../hooks';
2
+ import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapeSeries, useShapes, useSplit, } from '../../hooks';
3
3
  import { getYAxisWidth } from '../../hooks/useChartDimensions/utils';
4
4
  import { getPreparedXAxis } from '../../hooks/useChartOptions/x-axis';
5
5
  import { getPreparedYAxis } from '../../hooks/useChartOptions/y-axis';
6
6
  import { getLegendComponents } from '../../hooks/useSeries/prepare-legend';
7
7
  import { getPreparedOptions } from '../../hooks/useSeries/prepare-options';
8
+ import { getActiveLegendItems } from '../../hooks/useSeries/utils';
8
9
  import { useZoom } from '../../hooks/useZoom';
9
10
  import { getSortedSeriesData, getZoomedSeriesData } from '../../utils';
10
11
  import { hasAtLeastOneSeriesDataPerPlot } from './utils';
@@ -52,12 +53,13 @@ export function useChartInnerProps(props) {
52
53
  seriesData: zoomedSeriesData,
53
54
  seriesOptions: data.series.options,
54
55
  });
55
- const { preparedSeries: preparedShapesSeries } = useSeries({
56
+ const activeLegendItems = React.useMemo(() => getActiveLegendItems(preparedSeries), [preparedSeries]);
57
+ const { preparedSeries: preparedShapesSeries } = useShapeSeries({
56
58
  colors,
57
- legend: data.legend,
58
- originalSeriesData: data.series.data,
59
59
  seriesData: zoomedShapesSeriesData,
60
60
  seriesOptions: data.series.options,
61
+ activeLegendItems,
62
+ preparedLegend,
61
63
  });
62
64
  const { legendConfig, legendItems } = React.useMemo(() => {
63
65
  if (!preparedLegend) {
@@ -69,9 +71,8 @@ export function useChartInnerProps(props) {
69
71
  chartMargin: chart.margin,
70
72
  series: preparedSeries,
71
73
  preparedLegend,
72
- preparedYAxis: yAxis,
73
74
  });
74
- }, [width, height, chart.margin, preparedSeries, preparedLegend, yAxis]);
75
+ }, [width, height, chart.margin, preparedSeries, preparedLegend]);
75
76
  const { boundsWidth, boundsHeight } = useChartDimensions({
76
77
  width,
77
78
  height,
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import type { LegendConfig, LegendItem, OnLegendItemClick, PreparedLegend, PreparedSeries } from '../../hooks';
3
3
  import './styles.css';
4
4
  type Props = {
5
- boundsWidth: number;
6
5
  chartSeries: PreparedSeries[];
7
6
  legend: PreparedLegend;
8
7
  items: LegendItem[][];
@@ -7,15 +7,15 @@ import { axisBottom } from '../../utils/chart/axis-generators';
7
7
  import './styles.css';
8
8
  const b = block('legend');
9
9
  const getLegendPosition = (args) => {
10
- const { align, offsetWidth = 0, width, contentWidth } = args;
10
+ const { align, offsetLeft = 0, width, contentWidth } = args;
11
11
  const top = 0;
12
12
  if (align === 'left') {
13
- return { top, left: offsetWidth };
13
+ return { top, left: offsetLeft };
14
14
  }
15
15
  if (align === 'right') {
16
- return { top, left: offsetWidth + width - contentWidth };
16
+ return { top, left: offsetLeft + width - contentWidth };
17
17
  }
18
- return { top, left: offsetWidth + width / 2 - contentWidth / 2 };
18
+ return { top, left: offsetLeft + width / 2 - contentWidth / 2 };
19
19
  };
20
20
  const appendPaginator = (args) => {
21
21
  const { container, pageIndex, legend, transform, pages, onArrowClick } = args;
@@ -135,12 +135,12 @@ function renderLegendSymbol(args) {
135
135
  });
136
136
  }
137
137
  export const Legend = (props) => {
138
- const { boundsWidth, chartSeries, legend, items, config, htmlLayout, onItemClick, onUpdate } = props;
138
+ const { chartSeries, legend, items, config, htmlLayout, onItemClick, onUpdate } = props;
139
139
  const ref = React.useRef(null);
140
140
  const [pageIndex, setPageIndex] = React.useState(0);
141
141
  React.useEffect(() => {
142
142
  setPageIndex(0);
143
- }, [boundsWidth]);
143
+ }, [config.maxWidth]);
144
144
  React.useEffect(() => {
145
145
  async function prepareLegend() {
146
146
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -250,12 +250,12 @@ export const Legend = (props) => {
250
250
  case 'center': {
251
251
  const legendLinePostion = getLegendPosition({
252
252
  align: legend.align,
253
- width: boundsWidth,
254
- offsetWidth: 0,
253
+ width: config.maxWidth,
255
254
  contentWidth,
255
+ offsetLeft: config.offset.left,
256
256
  });
257
257
  left = legendLinePostion.left;
258
- legendWidth = boundsWidth;
258
+ legendWidth = config.maxWidth;
259
259
  break;
260
260
  }
261
261
  case 'start': {
@@ -361,9 +361,9 @@ export const Legend = (props) => {
361
361
  }
362
362
  const { left } = getLegendPosition({
363
363
  align: legend.align,
364
- width: boundsWidth,
365
- offsetWidth: config.offset.left,
364
+ width: config.maxWidth,
366
365
  contentWidth: legendWidth,
366
+ offsetLeft: config.offset.left,
367
367
  });
368
368
  svgElement
369
369
  .attr('transform', `translate(${[left, config.offset.top].join(',')})`)
@@ -371,19 +371,9 @@ export const Legend = (props) => {
371
371
  htmlContainer === null || htmlContainer === void 0 ? void 0 : htmlContainer.style('transform', `translate(${left}px, ${config.offset.top}px)`);
372
372
  }
373
373
  prepareLegend();
374
- }, [
375
- boundsWidth,
376
- chartSeries,
377
- onItemClick,
378
- onUpdate,
379
- legend,
380
- items,
381
- config,
382
- pageIndex,
383
- htmlLayout,
384
- ]);
374
+ }, [chartSeries, onItemClick, onUpdate, legend, items, config, pageIndex, htmlLayout]);
385
375
  // due to asynchronous processing, we only need to work with the actual element
386
376
  // eslint-disable-next-line react-hooks/exhaustive-deps
387
377
  const key = React.useMemo(() => getUniqId(), [legend, config]);
388
- return React.createElement("g", { key: key, className: b(), ref: ref, width: boundsWidth, height: legend.height });
378
+ return React.createElement("g", { key: key, className: b(), ref: ref, width: config.maxWidth, height: legend.height });
389
379
  };
@@ -13,4 +13,13 @@ export declare const useSeries: (args: Args) => {
13
13
  preparedSeries: PreparedSeries[];
14
14
  handleLegendItemClick: OnLegendItemClick;
15
15
  };
16
+ export declare const useShapeSeries: ({ seriesData, seriesOptions, colors, preparedLegend, activeLegendItems, }: {
17
+ colors: string[];
18
+ seriesData: ChartData["series"]["data"];
19
+ seriesOptions: ChartData["series"]["options"];
20
+ activeLegendItems: string[];
21
+ preparedLegend?: PreparedLegend | null;
22
+ }) => {
23
+ preparedSeries: PreparedSeries[];
24
+ };
16
25
  export {};
@@ -5,6 +5,38 @@ import { usePrevious } from '../usePrevious';
5
5
  import { getPreparedLegend } from './prepare-legend';
6
6
  import { prepareSeries } from './prepareSeries';
7
7
  import { getActiveLegendItems, getAllLegendItems } from './utils';
8
+ const useVisibleSeries = ({ preparedSeries, activeLegendItems, }) => {
9
+ return React.useMemo(() => {
10
+ return preparedSeries.map((singleSeries) => {
11
+ if (singleSeries.legend.enabled) {
12
+ return Object.assign(Object.assign({}, singleSeries), { visible: activeLegendItems.includes(singleSeries.name) });
13
+ }
14
+ return singleSeries;
15
+ });
16
+ }, [preparedSeries, activeLegendItems]);
17
+ };
18
+ const getPreparedSeries = async ({ seriesData, seriesOptions, colors, preparedLegend, }) => {
19
+ const seriesNames = getSeriesNames(seriesData);
20
+ const colorScale = scaleOrdinal(seriesNames, colors);
21
+ const groupedSeries = group(seriesData, (item) => item.type);
22
+ const acc = [];
23
+ if (!preparedLegend) {
24
+ return acc;
25
+ }
26
+ const list = Array.from(groupedSeries);
27
+ for (let i = 0; i < list.length; i++) {
28
+ const [seriesType, seriesList] = list[i];
29
+ acc.push(...(await prepareSeries({
30
+ type: seriesType,
31
+ series: seriesList,
32
+ seriesOptions,
33
+ legend: preparedLegend,
34
+ colorScale,
35
+ colors,
36
+ })));
37
+ }
38
+ return acc;
39
+ };
8
40
  export const useSeries = (args) => {
9
41
  const { legend, originalSeriesData, seriesData, seriesOptions, colors, preparedLegend: preparedLegendProps = null, } = args;
10
42
  const [preparedLegend, setPreparedLegend] = React.useState(preparedLegendProps);
@@ -17,38 +49,18 @@ export const useSeries = (args) => {
17
49
  const [activeLegendItems, setActiveLegendItems] = React.useState(getActiveLegendItems(preparedSeries));
18
50
  React.useEffect(() => {
19
51
  (async () => {
20
- const seriesNames = getSeriesNames(seriesData);
21
- const colorScale = scaleOrdinal(seriesNames, colors);
22
- const groupedSeries = group(seriesData, (item) => item.type);
23
- const acc = [];
24
- if (!preparedLegend) {
25
- return;
26
- }
27
- const list = Array.from(groupedSeries);
28
- for (let i = 0; i < list.length; i++) {
29
- const [seriesType, seriesList] = list[i];
30
- acc.push(...(await prepareSeries({
31
- type: seriesType,
32
- series: seriesList,
33
- seriesOptions,
34
- legend: preparedLegend,
35
- colorScale,
36
- colors,
37
- })));
38
- }
39
- setPreparedSeries(acc);
40
- setActiveLegendItems(getActiveLegendItems(acc));
52
+ const items = await getPreparedSeries({
53
+ seriesData,
54
+ seriesOptions,
55
+ preparedLegend,
56
+ colors,
57
+ });
58
+ setPreparedSeries(items);
59
+ setActiveLegendItems(getActiveLegendItems(items));
41
60
  })();
42
61
  }, [seriesData, seriesOptions, preparedLegend, colors]);
43
62
  const prevOriginalSeriesData = usePrevious(originalSeriesData);
44
- const chartSeries = React.useMemo(() => {
45
- return preparedSeries.map((singleSeries) => {
46
- if (singleSeries.legend.enabled) {
47
- return Object.assign(Object.assign({}, singleSeries), { visible: activeLegendItems.includes(singleSeries.name) });
48
- }
49
- return singleSeries;
50
- });
51
- }, [preparedSeries, activeLegendItems]);
63
+ const chartSeries = useVisibleSeries({ preparedSeries, activeLegendItems });
52
64
  const handleLegendItemClick = React.useCallback(({ name, metaKey }) => {
53
65
  const allItems = getAllLegendItems(preparedSeries);
54
66
  const onlyItemSelected = activeLegendItems.length === 1 && activeLegendItems.includes(name);
@@ -81,3 +93,21 @@ export const useSeries = (args) => {
81
93
  handleLegendItemClick,
82
94
  };
83
95
  };
96
+ export const useShapeSeries = ({ seriesData, seriesOptions, colors, preparedLegend, activeLegendItems, }) => {
97
+ const [preparedSeries, setPreparedSeries] = React.useState([]);
98
+ React.useEffect(() => {
99
+ (async () => {
100
+ const items = await getPreparedSeries({
101
+ seriesData,
102
+ seriesOptions,
103
+ preparedLegend,
104
+ colors,
105
+ });
106
+ setPreparedSeries(items);
107
+ })();
108
+ }, [seriesData, seriesOptions, preparedLegend, colors]);
109
+ const chartSeries = useVisibleSeries({ preparedSeries, activeLegendItems });
110
+ return {
111
+ preparedSeries: chartSeries,
112
+ };
113
+ };
@@ -1,5 +1,5 @@
1
1
  import type { ChartData } from '../../types';
2
- import type { PreparedAxis, PreparedChart } from '../useChartOptions/types';
2
+ import type { PreparedChart } from '../useChartOptions/types';
3
3
  import type { LegendItem, PreparedLegend, PreparedSeries } from './types';
4
4
  export declare function getPreparedLegend(args: {
5
5
  legend: ChartData['legend'];
@@ -11,7 +11,6 @@ export declare function getLegendComponents(args: {
11
11
  chartMargin: PreparedChart['margin'];
12
12
  series: PreparedSeries[];
13
13
  preparedLegend: PreparedLegend;
14
- preparedYAxis: PreparedAxis[];
15
14
  }): {
16
15
  legendConfig: {
17
16
  offset: {
@@ -24,6 +23,7 @@ export declare function getLegendComponents(args: {
24
23
  end: number;
25
24
  }[];
26
25
  } | undefined;
26
+ maxWidth: number;
27
27
  };
28
28
  legendItems: LegendItem[][];
29
29
  };
@@ -4,8 +4,6 @@ import get from 'lodash/get';
4
4
  import merge from 'lodash/merge';
5
5
  import { CONTINUOUS_LEGEND_SIZE, legendDefaults } from '../../constants';
6
6
  import { getDefaultColorStops, getDomainForContinuousColorScale, getLabelsSize } from '../../utils';
7
- import { getBoundsWidth } from '../useChartDimensions';
8
- import { getYAxisWidth } from '../useChartDimensions/utils';
9
7
  export async function getPreparedLegend(args) {
10
8
  var _a, _b, _c, _d, _e, _f, _g;
11
9
  const { legend, series } = args;
@@ -168,8 +166,8 @@ function getPagination(args) {
168
166
  return { pages };
169
167
  }
170
168
  export function getLegendComponents(args) {
171
- const { chartWidth, chartHeight, chartMargin, series, preparedLegend, preparedYAxis } = args;
172
- const maxLegendWidth = getBoundsWidth({ chartWidth, chartMargin, preparedYAxis });
169
+ const { chartWidth, chartHeight, chartMargin, series, preparedLegend } = args;
170
+ const maxLegendWidth = chartWidth - chartMargin.right - chartMargin.left;
173
171
  const maxLegendHeight = (chartHeight - chartMargin.top - chartMargin.bottom - preparedLegend.margin) / 2;
174
172
  const flattenLegendItems = getFlattenLegendItems(series, preparedLegend);
175
173
  const items = getGroupedLegendItems({
@@ -199,8 +197,8 @@ export function getLegendComponents(args) {
199
197
  }
200
198
  const top = chartHeight - chartMargin.bottom - preparedLegend.height;
201
199
  const offset = {
202
- left: chartMargin.left + getYAxisWidth(preparedYAxis[0]),
200
+ left: chartMargin.left,
203
201
  top,
204
202
  };
205
- return { legendConfig: { offset, pagination }, legendItems: items };
203
+ return { legendConfig: { offset, pagination, maxWidth: maxLegendWidth }, legendItems: items };
206
204
  }
@@ -53,6 +53,7 @@ export type LegendConfig = {
53
53
  left: number;
54
54
  top: number;
55
55
  };
56
+ maxWidth: number;
56
57
  pagination?: {
57
58
  pages: {
58
59
  start: number;
@@ -100,7 +100,7 @@ export const ChartInner = (props) => {
100
100
  React.createElement("g", { ref: plotBeforeRef }),
101
101
  shapes,
102
102
  React.createElement("g", { ref: plotAfterRef })),
103
- (preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries, boundsWidth: boundsWidth, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayout }))),
103
+ (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 }))),
104
104
  React.createElement("div", { className: b('html-layer'), ref: setHtmlLayout, style: {
105
105
  '--g-html-layout-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
106
106
  } }),
@@ -31,6 +31,7 @@ export declare function useChartInnerProps(props: Props): {
31
31
  end: number;
32
32
  }[];
33
33
  } | undefined;
34
+ maxWidth: number;
34
35
  } | undefined;
35
36
  legendItems: never[] | import("../../hooks").LegendItem[][];
36
37
  preparedLegend: import("../../hooks").PreparedLegend | null;
@@ -1,10 +1,11 @@
1
1
  import React from 'react';
2
- import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapes, useSplit, } from '../../hooks';
2
+ import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapeSeries, useShapes, useSplit, } from '../../hooks';
3
3
  import { getYAxisWidth } from '../../hooks/useChartDimensions/utils';
4
4
  import { getPreparedXAxis } from '../../hooks/useChartOptions/x-axis';
5
5
  import { getPreparedYAxis } from '../../hooks/useChartOptions/y-axis';
6
6
  import { getLegendComponents } from '../../hooks/useSeries/prepare-legend';
7
7
  import { getPreparedOptions } from '../../hooks/useSeries/prepare-options';
8
+ import { getActiveLegendItems } from '../../hooks/useSeries/utils';
8
9
  import { useZoom } from '../../hooks/useZoom';
9
10
  import { getSortedSeriesData, getZoomedSeriesData } from '../../utils';
10
11
  import { hasAtLeastOneSeriesDataPerPlot } from './utils';
@@ -52,12 +53,13 @@ export function useChartInnerProps(props) {
52
53
  seriesData: zoomedSeriesData,
53
54
  seriesOptions: data.series.options,
54
55
  });
55
- const { preparedSeries: preparedShapesSeries } = useSeries({
56
+ const activeLegendItems = React.useMemo(() => getActiveLegendItems(preparedSeries), [preparedSeries]);
57
+ const { preparedSeries: preparedShapesSeries } = useShapeSeries({
56
58
  colors,
57
- legend: data.legend,
58
- originalSeriesData: data.series.data,
59
59
  seriesData: zoomedShapesSeriesData,
60
60
  seriesOptions: data.series.options,
61
+ activeLegendItems,
62
+ preparedLegend,
61
63
  });
62
64
  const { legendConfig, legendItems } = React.useMemo(() => {
63
65
  if (!preparedLegend) {
@@ -69,9 +71,8 @@ export function useChartInnerProps(props) {
69
71
  chartMargin: chart.margin,
70
72
  series: preparedSeries,
71
73
  preparedLegend,
72
- preparedYAxis: yAxis,
73
74
  });
74
- }, [width, height, chart.margin, preparedSeries, preparedLegend, yAxis]);
75
+ }, [width, height, chart.margin, preparedSeries, preparedLegend]);
75
76
  const { boundsWidth, boundsHeight } = useChartDimensions({
76
77
  width,
77
78
  height,
@@ -2,7 +2,6 @@ import React from 'react';
2
2
  import type { LegendConfig, LegendItem, OnLegendItemClick, PreparedLegend, PreparedSeries } from '../../hooks';
3
3
  import './styles.css';
4
4
  type Props = {
5
- boundsWidth: number;
6
5
  chartSeries: PreparedSeries[];
7
6
  legend: PreparedLegend;
8
7
  items: LegendItem[][];
@@ -7,15 +7,15 @@ import { axisBottom } from '../../utils/chart/axis-generators';
7
7
  import './styles.css';
8
8
  const b = block('legend');
9
9
  const getLegendPosition = (args) => {
10
- const { align, offsetWidth = 0, width, contentWidth } = args;
10
+ const { align, offsetLeft = 0, width, contentWidth } = args;
11
11
  const top = 0;
12
12
  if (align === 'left') {
13
- return { top, left: offsetWidth };
13
+ return { top, left: offsetLeft };
14
14
  }
15
15
  if (align === 'right') {
16
- return { top, left: offsetWidth + width - contentWidth };
16
+ return { top, left: offsetLeft + width - contentWidth };
17
17
  }
18
- return { top, left: offsetWidth + width / 2 - contentWidth / 2 };
18
+ return { top, left: offsetLeft + width / 2 - contentWidth / 2 };
19
19
  };
20
20
  const appendPaginator = (args) => {
21
21
  const { container, pageIndex, legend, transform, pages, onArrowClick } = args;
@@ -135,12 +135,12 @@ function renderLegendSymbol(args) {
135
135
  });
136
136
  }
137
137
  export const Legend = (props) => {
138
- const { boundsWidth, chartSeries, legend, items, config, htmlLayout, onItemClick, onUpdate } = props;
138
+ const { chartSeries, legend, items, config, htmlLayout, onItemClick, onUpdate } = props;
139
139
  const ref = React.useRef(null);
140
140
  const [pageIndex, setPageIndex] = React.useState(0);
141
141
  React.useEffect(() => {
142
142
  setPageIndex(0);
143
- }, [boundsWidth]);
143
+ }, [config.maxWidth]);
144
144
  React.useEffect(() => {
145
145
  async function prepareLegend() {
146
146
  var _a, _b, _c, _d, _e, _f, _g, _h;
@@ -250,12 +250,12 @@ export const Legend = (props) => {
250
250
  case 'center': {
251
251
  const legendLinePostion = getLegendPosition({
252
252
  align: legend.align,
253
- width: boundsWidth,
254
- offsetWidth: 0,
253
+ width: config.maxWidth,
255
254
  contentWidth,
255
+ offsetLeft: config.offset.left,
256
256
  });
257
257
  left = legendLinePostion.left;
258
- legendWidth = boundsWidth;
258
+ legendWidth = config.maxWidth;
259
259
  break;
260
260
  }
261
261
  case 'start': {
@@ -361,9 +361,9 @@ export const Legend = (props) => {
361
361
  }
362
362
  const { left } = getLegendPosition({
363
363
  align: legend.align,
364
- width: boundsWidth,
365
- offsetWidth: config.offset.left,
364
+ width: config.maxWidth,
366
365
  contentWidth: legendWidth,
366
+ offsetLeft: config.offset.left,
367
367
  });
368
368
  svgElement
369
369
  .attr('transform', `translate(${[left, config.offset.top].join(',')})`)
@@ -371,19 +371,9 @@ export const Legend = (props) => {
371
371
  htmlContainer === null || htmlContainer === void 0 ? void 0 : htmlContainer.style('transform', `translate(${left}px, ${config.offset.top}px)`);
372
372
  }
373
373
  prepareLegend();
374
- }, [
375
- boundsWidth,
376
- chartSeries,
377
- onItemClick,
378
- onUpdate,
379
- legend,
380
- items,
381
- config,
382
- pageIndex,
383
- htmlLayout,
384
- ]);
374
+ }, [chartSeries, onItemClick, onUpdate, legend, items, config, pageIndex, htmlLayout]);
385
375
  // due to asynchronous processing, we only need to work with the actual element
386
376
  // eslint-disable-next-line react-hooks/exhaustive-deps
387
377
  const key = React.useMemo(() => getUniqId(), [legend, config]);
388
- return React.createElement("g", { key: key, className: b(), ref: ref, width: boundsWidth, height: legend.height });
378
+ return React.createElement("g", { key: key, className: b(), ref: ref, width: config.maxWidth, height: legend.height });
389
379
  };
@@ -13,4 +13,13 @@ export declare const useSeries: (args: Args) => {
13
13
  preparedSeries: PreparedSeries[];
14
14
  handleLegendItemClick: OnLegendItemClick;
15
15
  };
16
+ export declare const useShapeSeries: ({ seriesData, seriesOptions, colors, preparedLegend, activeLegendItems, }: {
17
+ colors: string[];
18
+ seriesData: ChartData["series"]["data"];
19
+ seriesOptions: ChartData["series"]["options"];
20
+ activeLegendItems: string[];
21
+ preparedLegend?: PreparedLegend | null;
22
+ }) => {
23
+ preparedSeries: PreparedSeries[];
24
+ };
16
25
  export {};
@@ -5,6 +5,38 @@ import { usePrevious } from '../usePrevious';
5
5
  import { getPreparedLegend } from './prepare-legend';
6
6
  import { prepareSeries } from './prepareSeries';
7
7
  import { getActiveLegendItems, getAllLegendItems } from './utils';
8
+ const useVisibleSeries = ({ preparedSeries, activeLegendItems, }) => {
9
+ return React.useMemo(() => {
10
+ return preparedSeries.map((singleSeries) => {
11
+ if (singleSeries.legend.enabled) {
12
+ return Object.assign(Object.assign({}, singleSeries), { visible: activeLegendItems.includes(singleSeries.name) });
13
+ }
14
+ return singleSeries;
15
+ });
16
+ }, [preparedSeries, activeLegendItems]);
17
+ };
18
+ const getPreparedSeries = async ({ seriesData, seriesOptions, colors, preparedLegend, }) => {
19
+ const seriesNames = getSeriesNames(seriesData);
20
+ const colorScale = scaleOrdinal(seriesNames, colors);
21
+ const groupedSeries = group(seriesData, (item) => item.type);
22
+ const acc = [];
23
+ if (!preparedLegend) {
24
+ return acc;
25
+ }
26
+ const list = Array.from(groupedSeries);
27
+ for (let i = 0; i < list.length; i++) {
28
+ const [seriesType, seriesList] = list[i];
29
+ acc.push(...(await prepareSeries({
30
+ type: seriesType,
31
+ series: seriesList,
32
+ seriesOptions,
33
+ legend: preparedLegend,
34
+ colorScale,
35
+ colors,
36
+ })));
37
+ }
38
+ return acc;
39
+ };
8
40
  export const useSeries = (args) => {
9
41
  const { legend, originalSeriesData, seriesData, seriesOptions, colors, preparedLegend: preparedLegendProps = null, } = args;
10
42
  const [preparedLegend, setPreparedLegend] = React.useState(preparedLegendProps);
@@ -17,38 +49,18 @@ export const useSeries = (args) => {
17
49
  const [activeLegendItems, setActiveLegendItems] = React.useState(getActiveLegendItems(preparedSeries));
18
50
  React.useEffect(() => {
19
51
  (async () => {
20
- const seriesNames = getSeriesNames(seriesData);
21
- const colorScale = scaleOrdinal(seriesNames, colors);
22
- const groupedSeries = group(seriesData, (item) => item.type);
23
- const acc = [];
24
- if (!preparedLegend) {
25
- return;
26
- }
27
- const list = Array.from(groupedSeries);
28
- for (let i = 0; i < list.length; i++) {
29
- const [seriesType, seriesList] = list[i];
30
- acc.push(...(await prepareSeries({
31
- type: seriesType,
32
- series: seriesList,
33
- seriesOptions,
34
- legend: preparedLegend,
35
- colorScale,
36
- colors,
37
- })));
38
- }
39
- setPreparedSeries(acc);
40
- setActiveLegendItems(getActiveLegendItems(acc));
52
+ const items = await getPreparedSeries({
53
+ seriesData,
54
+ seriesOptions,
55
+ preparedLegend,
56
+ colors,
57
+ });
58
+ setPreparedSeries(items);
59
+ setActiveLegendItems(getActiveLegendItems(items));
41
60
  })();
42
61
  }, [seriesData, seriesOptions, preparedLegend, colors]);
43
62
  const prevOriginalSeriesData = usePrevious(originalSeriesData);
44
- const chartSeries = React.useMemo(() => {
45
- return preparedSeries.map((singleSeries) => {
46
- if (singleSeries.legend.enabled) {
47
- return Object.assign(Object.assign({}, singleSeries), { visible: activeLegendItems.includes(singleSeries.name) });
48
- }
49
- return singleSeries;
50
- });
51
- }, [preparedSeries, activeLegendItems]);
63
+ const chartSeries = useVisibleSeries({ preparedSeries, activeLegendItems });
52
64
  const handleLegendItemClick = React.useCallback(({ name, metaKey }) => {
53
65
  const allItems = getAllLegendItems(preparedSeries);
54
66
  const onlyItemSelected = activeLegendItems.length === 1 && activeLegendItems.includes(name);
@@ -81,3 +93,21 @@ export const useSeries = (args) => {
81
93
  handleLegendItemClick,
82
94
  };
83
95
  };
96
+ export const useShapeSeries = ({ seriesData, seriesOptions, colors, preparedLegend, activeLegendItems, }) => {
97
+ const [preparedSeries, setPreparedSeries] = React.useState([]);
98
+ React.useEffect(() => {
99
+ (async () => {
100
+ const items = await getPreparedSeries({
101
+ seriesData,
102
+ seriesOptions,
103
+ preparedLegend,
104
+ colors,
105
+ });
106
+ setPreparedSeries(items);
107
+ })();
108
+ }, [seriesData, seriesOptions, preparedLegend, colors]);
109
+ const chartSeries = useVisibleSeries({ preparedSeries, activeLegendItems });
110
+ return {
111
+ preparedSeries: chartSeries,
112
+ };
113
+ };
@@ -1,5 +1,5 @@
1
1
  import type { ChartData } from '../../types';
2
- import type { PreparedAxis, PreparedChart } from '../useChartOptions/types';
2
+ import type { PreparedChart } from '../useChartOptions/types';
3
3
  import type { LegendItem, PreparedLegend, PreparedSeries } from './types';
4
4
  export declare function getPreparedLegend(args: {
5
5
  legend: ChartData['legend'];
@@ -11,7 +11,6 @@ export declare function getLegendComponents(args: {
11
11
  chartMargin: PreparedChart['margin'];
12
12
  series: PreparedSeries[];
13
13
  preparedLegend: PreparedLegend;
14
- preparedYAxis: PreparedAxis[];
15
14
  }): {
16
15
  legendConfig: {
17
16
  offset: {
@@ -24,6 +23,7 @@ export declare function getLegendComponents(args: {
24
23
  end: number;
25
24
  }[];
26
25
  } | undefined;
26
+ maxWidth: number;
27
27
  };
28
28
  legendItems: LegendItem[][];
29
29
  };
@@ -4,8 +4,6 @@ import get from 'lodash/get';
4
4
  import merge from 'lodash/merge';
5
5
  import { CONTINUOUS_LEGEND_SIZE, legendDefaults } from '../../constants';
6
6
  import { getDefaultColorStops, getDomainForContinuousColorScale, getLabelsSize } from '../../utils';
7
- import { getBoundsWidth } from '../useChartDimensions';
8
- import { getYAxisWidth } from '../useChartDimensions/utils';
9
7
  export async function getPreparedLegend(args) {
10
8
  var _a, _b, _c, _d, _e, _f, _g;
11
9
  const { legend, series } = args;
@@ -168,8 +166,8 @@ function getPagination(args) {
168
166
  return { pages };
169
167
  }
170
168
  export function getLegendComponents(args) {
171
- const { chartWidth, chartHeight, chartMargin, series, preparedLegend, preparedYAxis } = args;
172
- const maxLegendWidth = getBoundsWidth({ chartWidth, chartMargin, preparedYAxis });
169
+ const { chartWidth, chartHeight, chartMargin, series, preparedLegend } = args;
170
+ const maxLegendWidth = chartWidth - chartMargin.right - chartMargin.left;
173
171
  const maxLegendHeight = (chartHeight - chartMargin.top - chartMargin.bottom - preparedLegend.margin) / 2;
174
172
  const flattenLegendItems = getFlattenLegendItems(series, preparedLegend);
175
173
  const items = getGroupedLegendItems({
@@ -199,8 +197,8 @@ export function getLegendComponents(args) {
199
197
  }
200
198
  const top = chartHeight - chartMargin.bottom - preparedLegend.height;
201
199
  const offset = {
202
- left: chartMargin.left + getYAxisWidth(preparedYAxis[0]),
200
+ left: chartMargin.left,
203
201
  top,
204
202
  };
205
- return { legendConfig: { offset, pagination }, legendItems: items };
203
+ return { legendConfig: { offset, pagination, maxWidth: maxLegendWidth }, legendItems: items };
206
204
  }
@@ -53,6 +53,7 @@ export type LegendConfig = {
53
53
  left: number;
54
54
  top: number;
55
55
  };
56
+ maxWidth: number;
56
57
  pagination?: {
57
58
  pages: {
58
59
  start: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.11.3",
3
+ "version": "1.11.4",
4
4
  "description": "React component used to render charts",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",