@gravity-ui/charts 1.11.3 → 1.12.0

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 (103) hide show
  1. package/dist/cjs/components/ChartInner/index.js +1 -1
  2. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -0
  3. package/dist/cjs/components/ChartInner/useChartInnerProps.js +19 -12
  4. package/dist/cjs/components/Legend/index.d.ts +0 -1
  5. package/dist/cjs/components/Legend/index.js +13 -23
  6. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  7. package/dist/cjs/components/Tooltip/ChartTooltipContent.js +3 -3
  8. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
  9. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
  10. package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
  11. package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
  12. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
  13. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +102 -0
  14. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
  15. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
  16. package/dist/cjs/components/Tooltip/index.js +1 -1
  17. package/dist/cjs/components/Tooltip/styles.css +14 -2
  18. package/dist/cjs/components/Tooltip/utils.d.ts +30 -0
  19. package/dist/cjs/components/Tooltip/utils.js +126 -0
  20. package/dist/cjs/constants/axis.d.ts +6 -0
  21. package/dist/cjs/constants/axis.js +6 -0
  22. package/dist/cjs/constants/index.d.ts +6 -4
  23. package/dist/cjs/constants/index.js +6 -4
  24. package/dist/cjs/constants/tooltip.d.ts +3 -0
  25. package/dist/cjs/constants/tooltip.js +3 -0
  26. package/dist/cjs/hooks/useAxisScales/index.d.ts +14 -3
  27. package/dist/cjs/hooks/useAxisScales/index.js +73 -22
  28. package/dist/cjs/hooks/useChartOptions/x-axis.js +1 -1
  29. package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +4 -2
  30. package/dist/cjs/hooks/useChartOptions/y-axis.js +9 -3
  31. package/dist/cjs/hooks/useSeries/index.d.ts +9 -0
  32. package/dist/cjs/hooks/useSeries/index.js +59 -29
  33. package/dist/cjs/hooks/useSeries/prepare-legend.d.ts +2 -2
  34. package/dist/cjs/hooks/useSeries/prepare-legend.js +4 -6
  35. package/dist/cjs/hooks/useSeries/types.d.ts +1 -0
  36. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +1 -1
  37. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +17 -62
  38. package/dist/cjs/hooks/useShapes/waterfall/prepare-data.js +1 -1
  39. package/dist/cjs/hooks/utils/bar-y.d.ts +27 -0
  40. package/dist/cjs/hooks/utils/bar-y.js +69 -0
  41. package/dist/cjs/hooks/utils/index.d.ts +1 -0
  42. package/dist/cjs/hooks/utils/index.js +1 -0
  43. package/dist/cjs/i18n/keysets/en.json +7 -1
  44. package/dist/cjs/i18n/keysets/ru.json +7 -1
  45. package/dist/cjs/types/chart/axis.d.ts +2 -2
  46. package/dist/cjs/types/chart/tooltip.d.ts +21 -0
  47. package/dist/cjs/validation/index.js +55 -1
  48. package/dist/esm/components/ChartInner/index.js +1 -1
  49. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -0
  50. package/dist/esm/components/ChartInner/useChartInnerProps.js +19 -12
  51. package/dist/esm/components/Legend/index.d.ts +0 -1
  52. package/dist/esm/components/Legend/index.js +13 -23
  53. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  54. package/dist/esm/components/Tooltip/ChartTooltipContent.js +3 -3
  55. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
  56. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
  57. package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
  58. package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
  59. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
  60. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +102 -0
  61. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
  62. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
  63. package/dist/esm/components/Tooltip/index.js +1 -1
  64. package/dist/esm/components/Tooltip/styles.css +14 -2
  65. package/dist/esm/components/Tooltip/utils.d.ts +30 -0
  66. package/dist/esm/components/Tooltip/utils.js +126 -0
  67. package/dist/esm/constants/axis.d.ts +6 -0
  68. package/dist/esm/constants/axis.js +6 -0
  69. package/dist/esm/constants/index.d.ts +6 -4
  70. package/dist/esm/constants/index.js +6 -4
  71. package/dist/esm/constants/tooltip.d.ts +3 -0
  72. package/dist/esm/constants/tooltip.js +3 -0
  73. package/dist/esm/hooks/useAxisScales/index.d.ts +14 -3
  74. package/dist/esm/hooks/useAxisScales/index.js +73 -22
  75. package/dist/esm/hooks/useChartOptions/x-axis.js +1 -1
  76. package/dist/esm/hooks/useChartOptions/y-axis.d.ts +4 -2
  77. package/dist/esm/hooks/useChartOptions/y-axis.js +9 -3
  78. package/dist/esm/hooks/useSeries/index.d.ts +9 -0
  79. package/dist/esm/hooks/useSeries/index.js +59 -29
  80. package/dist/esm/hooks/useSeries/prepare-legend.d.ts +2 -2
  81. package/dist/esm/hooks/useSeries/prepare-legend.js +4 -6
  82. package/dist/esm/hooks/useSeries/types.d.ts +1 -0
  83. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +1 -1
  84. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +17 -62
  85. package/dist/esm/hooks/useShapes/waterfall/prepare-data.js +1 -1
  86. package/dist/esm/hooks/utils/bar-y.d.ts +27 -0
  87. package/dist/esm/hooks/utils/bar-y.js +69 -0
  88. package/dist/esm/hooks/utils/index.d.ts +1 -0
  89. package/dist/esm/hooks/utils/index.js +1 -0
  90. package/dist/esm/i18n/keysets/en.json +7 -1
  91. package/dist/esm/i18n/keysets/ru.json +7 -1
  92. package/dist/esm/types/chart/axis.d.ts +2 -2
  93. package/dist/esm/types/chart/tooltip.d.ts +21 -0
  94. package/dist/esm/validation/index.js +55 -1
  95. package/package.json +1 -1
  96. package/dist/cjs/components/Tooltip/DefaultContent.d.ts +0 -10
  97. package/dist/cjs/components/Tooltip/DefaultContent.js +0 -187
  98. package/dist/esm/components/Tooltip/DefaultContent.d.ts +0 -10
  99. package/dist/esm/components/Tooltip/DefaultContent.js +0 -187
  100. /package/dist/cjs/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
  101. /package/dist/cjs/hooks/{useShapes/constants.js → constants.js} +0 -0
  102. /package/dist/esm/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
  103. /package/dist/esm/hooks/{useShapes/constants.js → constants.js} +0 -0
@@ -1,13 +1,14 @@
1
1
  import React from 'react';
2
2
  import { extent, scaleBand, scaleLinear, scaleLog, scaleUtc } from 'd3';
3
3
  import get from 'lodash/get';
4
- import { DEFAULT_AXIS_TYPE } from '../../constants';
4
+ import { DEFAULT_AXIS_TYPE, SeriesType } from '../../constants';
5
5
  import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisHeight, getDataCategoryValue, getDefaultMaxXAxisValue, getDefaultMinXAxisValue, getDomainDataXBySeries, getDomainDataYBySeries, getOnlyVisibleSeries, isAxisRelatedSeries, isSeriesWithCategoryValues, } from '../../utils';
6
+ import { getBarYLayoutForNumericScale } from '../utils';
6
7
  const X_AXIS_ZOOM_PADDING = 0.02;
7
- const isNumericalArrayData = (data) => {
8
+ function isNumericalArrayData(data) {
8
9
  return data.every((d) => typeof d === 'number' || d === null);
9
- };
10
- const filterCategoriesByVisibleSeries = (args) => {
10
+ }
11
+ function filterCategoriesByVisibleSeries(args) {
11
12
  const { axisDirection, categories, series } = args;
12
13
  const visibleCategories = new Set();
13
14
  series.forEach((s) => {
@@ -18,18 +19,61 @@ const filterCategoriesByVisibleSeries = (args) => {
18
19
  }
19
20
  });
20
21
  return categories.filter((c) => visibleCategories.has(c));
21
- };
22
- export function createYScale(axis, series, boundsHeight) {
23
- const yType = get(axis, 'type', DEFAULT_AXIS_TYPE);
22
+ }
23
+ // axis is validated in `validation/index.ts`, so the value of `axis.type` is definitely valid.
24
+ // eslint-disable-next-line consistent-return
25
+ function getYScaleRange(args) {
26
+ const { axis, boundsHeight, series, seriesOptions } = args;
27
+ switch (axis.type) {
28
+ case 'datetime':
29
+ case 'linear':
30
+ case 'logarithmic': {
31
+ const barYSeries = series.filter((s) => s.type === SeriesType.BarY);
32
+ if (barYSeries.length) {
33
+ const { barSize, dataLength } = getBarYLayoutForNumericScale({
34
+ plotHeight: boundsHeight - boundsHeight * axis.maxPadding,
35
+ series: barYSeries,
36
+ seriesOptions: seriesOptions,
37
+ });
38
+ if (dataLength > 1) {
39
+ const alreadyCountedStackingIds = new Set();
40
+ const offsetMultiplier = barYSeries.reduce((acc, s) => {
41
+ let count = 0;
42
+ if (s.stackId) {
43
+ if (!alreadyCountedStackingIds.has(s.stackId)) {
44
+ alreadyCountedStackingIds.add(s.stackId);
45
+ count = 1;
46
+ }
47
+ }
48
+ else {
49
+ count = 1;
50
+ }
51
+ return acc + count;
52
+ }, 0);
53
+ const offset = (barSize * Math.max(offsetMultiplier, 1)) / 2;
54
+ const start = boundsHeight - offset;
55
+ const end = boundsHeight * axis.maxPadding + offset;
56
+ return [start, end];
57
+ }
58
+ }
59
+ return [boundsHeight, boundsHeight * axis.maxPadding];
60
+ }
61
+ case 'category': {
62
+ return [boundsHeight, 0];
63
+ }
64
+ }
65
+ }
66
+ export function createYScale(args) {
67
+ const { axis, boundsHeight, series, seriesOptions } = args;
24
68
  const yMinProps = get(axis, 'min');
25
69
  const yMaxProps = get(axis, 'max');
26
70
  const yCategories = get(axis, 'categories');
27
71
  const yTimestamps = get(axis, 'timestamps');
28
- switch (yType) {
72
+ const range = getYScaleRange({ axis, boundsHeight, series, seriesOptions });
73
+ switch (axis.type) {
29
74
  case 'linear':
30
75
  case 'logarithmic': {
31
76
  const domain = getDomainDataYBySeries(series);
32
- const range = [boundsHeight, boundsHeight * axis.maxPadding];
33
77
  if (isNumericalArrayData(domain)) {
34
78
  const [yMinDomain, yMaxDomain] = extent(domain);
35
79
  const yMin = typeof yMinProps === 'number' ? yMinProps : yMinDomain;
@@ -41,7 +85,7 @@ export function createYScale(axis, series, boundsHeight) {
41
85
  const hasSeriesWithVolumeOnYAxis = series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type));
42
86
  yMax = hasSeriesWithVolumeOnYAxis ? Math.max(yMaxDomain, 0) : yMaxDomain;
43
87
  }
44
- const scaleFn = yType === 'logarithmic' ? scaleLog : scaleLinear;
88
+ const scaleFn = axis.type === 'logarithmic' ? scaleLog : scaleLinear;
45
89
  return scaleFn().domain([yMin, yMax]).range(range).nice();
46
90
  }
47
91
  break;
@@ -53,12 +97,11 @@ export function createYScale(axis, series, boundsHeight) {
53
97
  categories: yCategories,
54
98
  series: series,
55
99
  });
56
- return scaleBand().domain(filteredCategories).range([boundsHeight, 0]);
100
+ return scaleBand().domain(filteredCategories).range(range);
57
101
  }
58
102
  break;
59
103
  }
60
104
  case 'datetime': {
61
- const range = [boundsHeight, boundsHeight * axis.maxPadding];
62
105
  if (yTimestamps) {
63
106
  const [yMinTimestamp, yMaxTimestamp] = extent(yTimestamps);
64
107
  const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
@@ -74,7 +117,6 @@ export function createYScale(axis, series, boundsHeight) {
74
117
  return scaleUtc().domain([yMin, yMax]).range(range).nice();
75
118
  }
76
119
  }
77
- break;
78
120
  }
79
121
  }
80
122
  throw new Error('Failed to create yScale');
@@ -97,7 +139,8 @@ function calculateXAxisPadding(series) {
97
139
  return result;
98
140
  }
99
141
  // eslint-disable-next-line complexity
100
- export function createXScale(axis, series, boundsWidth, hasZoomX) {
142
+ export function createXScale(args) {
143
+ const { axis, boundsWidth, series, hasZoomX } = args;
101
144
  const xMinProps = get(axis, 'min');
102
145
  const xMaxProps = get(axis, 'max');
103
146
  const xType = get(axis, 'type', DEFAULT_AXIS_TYPE);
@@ -193,13 +236,15 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
193
236
  throw new Error('Failed to create xScale');
194
237
  }
195
238
  const createScales = (args) => {
196
- const { boundsWidth, boundsHeight, series, xAxis, yAxis, split, hasZoomX } = args;
239
+ const { boundsWidth, boundsHeight, hasZoomX, series, seriesOptions, split, xAxis, yAxis } = args;
197
240
  let visibleSeries = getOnlyVisibleSeries(series);
198
241
  // Reassign to all series in case of all series unselected,
199
242
  // otherwise we will get an empty space without grid
200
243
  visibleSeries = visibleSeries.length === 0 ? series : visibleSeries;
201
244
  return {
202
- xScale: xAxis ? createXScale(xAxis, visibleSeries, boundsWidth, hasZoomX) : undefined,
245
+ xScale: xAxis
246
+ ? createXScale({ axis: xAxis, boundsWidth, series: visibleSeries, hasZoomX })
247
+ : undefined,
203
248
  yScale: yAxis.map((axis, index) => {
204
249
  const axisSeries = series.filter((s) => {
205
250
  const seriesAxisIndex = get(s, 'yAxis', 0);
@@ -207,7 +252,12 @@ const createScales = (args) => {
207
252
  });
208
253
  const visibleAxisSeries = getOnlyVisibleSeries(axisSeries);
209
254
  const axisHeight = getAxisHeight({ boundsHeight, split });
210
- return createYScale(axis, visibleAxisSeries.length ? visibleAxisSeries : axisSeries, axisHeight);
255
+ return createYScale({
256
+ axis,
257
+ boundsHeight: axisHeight,
258
+ series: visibleAxisSeries.length ? visibleAxisSeries : axisSeries,
259
+ seriesOptions,
260
+ });
211
261
  }),
212
262
  };
213
263
  };
@@ -215,7 +265,7 @@ const createScales = (args) => {
215
265
  * Uses to create scales for axis related series
216
266
  */
217
267
  export const useAxisScales = (args) => {
218
- const { boundsWidth, boundsHeight, series, xAxis, yAxis, split, hasZoomX, hasZoomY } = args;
268
+ const { boundsWidth, boundsHeight, hasZoomX, hasZoomY, series, seriesOptions, split, xAxis, yAxis, } = args;
219
269
  return React.useMemo(() => {
220
270
  let xScale;
221
271
  let yScale;
@@ -224,14 +274,15 @@ export const useAxisScales = (args) => {
224
274
  ({ xScale, yScale } = createScales({
225
275
  boundsWidth,
226
276
  boundsHeight,
277
+ hasZoomX,
278
+ hasZoomY,
227
279
  series,
280
+ seriesOptions,
281
+ split,
228
282
  xAxis,
229
283
  yAxis,
230
- split,
231
- hasZoomX,
232
- hasZoomY,
233
284
  }));
234
285
  }
235
286
  return { xScale, yScale };
236
- }, [boundsWidth, boundsHeight, series, xAxis, yAxis, split, hasZoomX, hasZoomY]);
287
+ }, [boundsWidth, boundsHeight, hasZoomX, hasZoomY, series, seriesOptions, split, xAxis, yAxis]);
237
288
  };
@@ -3,7 +3,7 @@ import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, axisCrosshairDefaults, axisLa
3
3
  import { calculateCos, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, getXAxisItems, hasOverlappingLabels, wrapText, } from '../../utils';
4
4
  import { createXScale } from '../useAxisScales';
5
5
  async function getLabelSettings({ axis, seriesData, width, autoRotation = true, }) {
6
- const scale = createXScale(axis, seriesData, width);
6
+ const scale = createXScale({ axis, series: seriesData, boundsWidth: width });
7
7
  const tickCount = getTicksCount({ axis, range: width });
8
8
  const ticks = getXAxisItems({
9
9
  scale: scale,
@@ -1,7 +1,9 @@
1
1
  import type { ChartSeries, ChartYAxis } from '../../types';
2
+ import type { PreparedSeriesOptions } from '../useSeries/types';
2
3
  import type { PreparedAxis } from './types';
3
- export declare const getPreparedYAxis: ({ seriesData, yAxis, height, }: {
4
+ export declare const getPreparedYAxis: ({ height, seriesData, seriesOptions, yAxis, }: {
5
+ height: number;
4
6
  seriesData: ChartSeries[];
7
+ seriesOptions: PreparedSeriesOptions;
5
8
  yAxis: ChartYAxis[] | undefined;
6
- height: number;
7
9
  }) => Promise<PreparedAxis[]>;
@@ -3,11 +3,16 @@ import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, axisCrossh
3
3
  import { formatAxisTickLabel, getClosestPointsRange, getDefaultMinYAxisValue, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, isAxisRelatedSeries, wrapText, } from '../../utils';
4
4
  import { createYScale } from '../useAxisScales';
5
5
  const getAxisLabelMaxWidth = async (args) => {
6
- const { axis, seriesData } = args;
6
+ const { axis, seriesData, seriesOptions } = args;
7
7
  if (!axis.labels.enabled) {
8
8
  return 0;
9
9
  }
10
- const scale = createYScale(axis, seriesData, 1);
10
+ const scale = createYScale({
11
+ axis,
12
+ boundsHeight: 1,
13
+ series: seriesData,
14
+ seriesOptions,
15
+ });
11
16
  const ticks = getScaleTicks(scale);
12
17
  // FIXME: it is necessary to filter data, since we do not draw overlapping ticks
13
18
  const step = getClosestPointsRange(axis, ticks);
@@ -23,7 +28,7 @@ const getAxisLabelMaxWidth = async (args) => {
23
28
  });
24
29
  return size.maxWidth;
25
30
  };
26
- export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
31
+ export const getPreparedYAxis = ({ height, seriesData, seriesOptions, yAxis, }) => {
27
32
  const axisByPlot = [];
28
33
  const axisItems = yAxis || [{}];
29
34
  const hasAxisRelatedSeries = seriesData.some(isAxisRelatedSeries);
@@ -126,6 +131,7 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
126
131
  preparedAxis.labels.width = await getAxisLabelMaxWidth({
127
132
  axis: preparedAxis,
128
133
  seriesData,
134
+ seriesOptions,
129
135
  });
130
136
  }
131
137
  return preparedAxis;
@@ -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;
@@ -2,7 +2,7 @@ import { ascending, descending, max, sort } from 'd3';
2
2
  import get from 'lodash/get';
3
3
  import { getDataCategoryValue, getLabelsSize } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../../constants';
6
6
  async function getLabelData(d) {
7
7
  if (!d.series.dataLabels.enabled) {
8
8
  return undefined;
@@ -1,54 +1,9 @@
1
- import { ascending, descending, max, sort } from 'd3';
1
+ import { ascending, descending, sort } from 'd3';
2
2
  import get from 'lodash/get';
3
- import { getDataCategoryValue, getLabelsSize } from '../../../utils';
3
+ import { getLabelsSize } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { getBarYLayoutForCategoryScale, getBarYLayoutForNumericScale, groupBarYDataByYValue, } from '../../utils';
6
6
  const DEFAULT_LABEL_PADDING = 7;
7
- function groupByYValue(series, yAxis) {
8
- const data = {};
9
- series.forEach((s) => {
10
- s.data.forEach((d) => {
11
- const axisIndex = get(s, 'yAxis', 0);
12
- const seriesYAxis = yAxis[axisIndex];
13
- const categories = get(seriesYAxis, 'categories', []);
14
- const key = seriesYAxis.type === 'category'
15
- ? getDataCategoryValue({ axisDirection: 'y', categories, data: d })
16
- : d.y;
17
- if (key) {
18
- if (!data[key]) {
19
- data[key] = {};
20
- }
21
- if (!data[key][s.stackId]) {
22
- data[key][s.stackId] = [];
23
- }
24
- data[key][s.stackId].push({ data: d, series: s });
25
- }
26
- });
27
- });
28
- return data;
29
- }
30
- function getBandWidth(series, yAxis, yScale) {
31
- let bandWidth = Infinity;
32
- if (yAxis[0].type === 'category') {
33
- bandWidth = yScale.bandwidth();
34
- }
35
- else {
36
- const scale = yScale;
37
- const axisValues = series.reduce((acc, s) => {
38
- s.data.forEach((dataItem) => acc.push(Number(dataItem.y)));
39
- return acc;
40
- }, []);
41
- axisValues.sort().forEach((value, index) => {
42
- if (index > 0 && value !== axisValues[index - 1]) {
43
- const dist = scale(value) - scale(axisValues[index - 1]);
44
- if (dist < bandWidth) {
45
- bandWidth = dist;
46
- }
47
- }
48
- });
49
- }
50
- return bandWidth;
51
- }
52
7
  async function setLabel(prepared) {
53
8
  const dataLabels = prepared.series.dataLabels;
54
9
  if (!dataLabels.enabled) {
@@ -89,10 +44,9 @@ async function setLabel(prepared) {
89
44
  export const prepareBarYData = async (args) => {
90
45
  const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
91
46
  const xLinearScale = xScale;
47
+ const yLinearScale = yScale;
48
+ const plotHeight = yLinearScale(yLinearScale.domain()[0]);
92
49
  const plotWidth = xLinearScale(xLinearScale.domain()[1]);
93
- const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
94
- const barPadding = get(seriesOptions, 'bar-y.barPadding');
95
- const groupPadding = get(seriesOptions, 'bar-y.groupPadding');
96
50
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
97
51
  const comparator = (sortingOptions === null || sortingOptions === void 0 ? void 0 : sortingOptions.direction) === 'desc' ? descending : ascending;
98
52
  const sortKey = (() => {
@@ -108,17 +62,18 @@ export const prepareBarYData = async (args) => {
108
62
  }
109
63
  }
110
64
  })();
111
- const groupedData = groupByYValue(series, yAxis);
112
- const bandWidth = getBandWidth(series, yAxis, yScale);
113
- const maxGroupSize = max(Object.values(groupedData), (d) => Object.values(d).length) || 1;
114
- const groupGap = Math.max(bandWidth * groupPadding, MIN_BAR_GROUP_GAP);
115
- const groupWidth = bandWidth - groupGap;
116
- const rectGap = Math.max(bandWidth * barPadding, MIN_BAR_GAP);
117
- const barHeight = Math.max(MIN_BAR_WIDTH, Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth));
65
+ const groupedData = groupBarYDataByYValue(series, yAxis);
66
+ const { bandSize, barGap, barSize } = yAxis[0].type === 'category'
67
+ ? getBarYLayoutForCategoryScale({ groupedData, seriesOptions, yScale })
68
+ : getBarYLayoutForNumericScale({
69
+ series,
70
+ seriesOptions,
71
+ plotHeight: plotHeight - plotHeight * yAxis[0].maxPadding,
72
+ });
118
73
  const result = [];
119
74
  Object.entries(groupedData).forEach(([yValue, val]) => {
120
75
  const stacks = Object.values(val);
121
- const currentBarHeight = barHeight * stacks.length + rectGap * (stacks.length - 1);
76
+ const currentBarHeight = barSize * stacks.length + barGap * (stacks.length - 1);
122
77
  stacks.forEach((measureValues, groupItemIndex) => {
123
78
  const base = xLinearScale(0);
124
79
  let stackSum = base;
@@ -130,20 +85,20 @@ export const prepareBarYData = async (args) => {
130
85
  let center;
131
86
  if (yAxis[0].type === 'category') {
132
87
  const bandScale = yScale;
133
- center = (bandScale(yValue) || 0) + bandWidth / 2;
88
+ center = (bandScale(yValue) || 0) + bandSize / 2;
134
89
  }
135
90
  else {
136
91
  const scale = yScale;
137
92
  center = scale(Number(yValue));
138
93
  }
139
- const y = center - currentBarHeight / 2 + (barHeight + rectGap) * groupItemIndex;
94
+ const y = center - currentBarHeight / 2 + (barSize + barGap) * groupItemIndex;
140
95
  const xValue = Number(data.x);
141
96
  const width = xValue > 0 ? xLinearScale(xValue) - base : base - xLinearScale(xValue);
142
97
  const item = {
143
98
  x: xValue > 0 ? stackSum : stackSum - width,
144
99
  y,
145
100
  width,
146
- height: barHeight,
101
+ height: barSize,
147
102
  color: data.color || s.color,
148
103
  opacity: get(data, 'opacity', null),
149
104
  data,
@@ -2,7 +2,7 @@ import get from 'lodash/get';
2
2
  import sortBy from 'lodash/sortBy';
3
3
  import { getLabelsSize } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { MIN_BAR_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { MIN_BAR_GAP, MIN_BAR_WIDTH } from '../../constants';
6
6
  import { getXValue, getYValue } from '../utils';
7
7
  async function getLabelData(d, plotHeight) {
8
8
  var _a, _b;
@@ -0,0 +1,27 @@
1
+ import type { BarYSeries, BarYSeriesData } from '../../types';
2
+ import type { ChartScale } from '../useAxisScales';
3
+ import type { PreparedAxis } from '../useChartOptions/types';
4
+ import type { PreparedBarYSeries, PreparedSeriesOptions } from '../useSeries/types';
5
+ export declare function groupBarYDataByYValue(series: PreparedBarYSeries[], yAxis: PreparedAxis[]): Record<string | number, Record<string, {
6
+ data: BarYSeriesData;
7
+ series: PreparedBarYSeries;
8
+ }[]>>;
9
+ export declare function getBarYLayoutForNumericScale(args: {
10
+ plotHeight: number;
11
+ series: (BarYSeries | PreparedBarYSeries)[];
12
+ seriesOptions: PreparedSeriesOptions;
13
+ }): {
14
+ bandSize: number;
15
+ barGap: number;
16
+ barSize: number;
17
+ dataLength: number;
18
+ };
19
+ export declare function getBarYLayoutForCategoryScale(args: {
20
+ groupedData: ReturnType<typeof groupBarYDataByYValue>;
21
+ seriesOptions: PreparedSeriesOptions;
22
+ yScale: ChartScale;
23
+ }): {
24
+ bandSize: number;
25
+ barGap: number;
26
+ barSize: number;
27
+ };