@gravity-ui/charts 1.11.1 → 1.11.3

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 (77) hide show
  1. package/dist/cjs/components/Axis/AxisY.d.ts +1 -0
  2. package/dist/cjs/components/Axis/AxisY.js +14 -13
  3. package/dist/cjs/components/ChartInner/index.js +2 -2
  4. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -0
  5. package/dist/cjs/components/ChartInner/useChartInnerProps.js +44 -13
  6. package/dist/cjs/components/Legend/index.js +6 -2
  7. package/dist/cjs/components/Tooltip/DefaultContent.js +4 -4
  8. package/dist/cjs/hooks/useAxisScales/index.js +15 -6
  9. package/dist/cjs/hooks/useChartOptions/index.d.ts +6 -2
  10. package/dist/cjs/hooks/useChartOptions/index.js +4 -4
  11. package/dist/cjs/hooks/useSeries/index.d.ts +1 -19
  12. package/dist/cjs/hooks/useSeries/index.js +7 -25
  13. package/dist/cjs/hooks/useSeries/prepare-area.js +1 -2
  14. package/dist/cjs/hooks/useSeries/prepare-legend.js +5 -1
  15. package/dist/cjs/hooks/useSeries/types.d.ts +1 -0
  16. package/dist/cjs/hooks/useShapes/area/prepare-data.js +2 -1
  17. package/dist/cjs/hooks/useShapes/line/prepare-data.js +3 -2
  18. package/dist/cjs/hooks/useShapes/utils.d.ts +6 -0
  19. package/dist/cjs/hooks/useShapes/utils.js +29 -4
  20. package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -1
  21. package/dist/cjs/libs/format-number/index.d.ts +7 -3
  22. package/dist/cjs/libs/format-number/index.js +8 -3
  23. package/dist/cjs/libs/format-number/types.d.ts +0 -1
  24. package/dist/cjs/types/chart/tooltip.d.ts +1 -0
  25. package/dist/cjs/types/formatter.d.ts +0 -1
  26. package/dist/cjs/utils/chart/axis-generators/bottom.js +21 -28
  27. package/dist/cjs/utils/chart/get-closest-data.d.ts +1 -0
  28. package/dist/cjs/utils/chart/get-closest-data.js +2 -5
  29. package/dist/cjs/utils/chart/index.d.ts +1 -0
  30. package/dist/cjs/utils/chart/index.js +3 -2
  31. package/dist/cjs/utils/chart/series/index.d.ts +1 -0
  32. package/dist/cjs/utils/chart/series/index.js +1 -0
  33. package/dist/cjs/utils/chart/series/sorting.d.ts +2 -0
  34. package/dist/cjs/utils/chart/series/sorting.js +12 -0
  35. package/dist/{esm/hooks/hooks-utils → cjs/utils/chart}/zoom.d.ts +5 -2
  36. package/dist/{esm/hooks/hooks-utils → cjs/utils/chart}/zoom.js +36 -9
  37. package/dist/esm/components/Axis/AxisY.d.ts +1 -0
  38. package/dist/esm/components/Axis/AxisY.js +14 -13
  39. package/dist/esm/components/ChartInner/index.js +2 -2
  40. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -0
  41. package/dist/esm/components/ChartInner/useChartInnerProps.js +44 -13
  42. package/dist/esm/components/Legend/index.js +6 -2
  43. package/dist/esm/components/Tooltip/DefaultContent.js +4 -4
  44. package/dist/esm/hooks/useAxisScales/index.js +15 -6
  45. package/dist/esm/hooks/useChartOptions/index.d.ts +6 -2
  46. package/dist/esm/hooks/useChartOptions/index.js +4 -4
  47. package/dist/esm/hooks/useSeries/index.d.ts +1 -19
  48. package/dist/esm/hooks/useSeries/index.js +7 -25
  49. package/dist/esm/hooks/useSeries/prepare-area.js +1 -2
  50. package/dist/esm/hooks/useSeries/prepare-legend.js +5 -1
  51. package/dist/esm/hooks/useSeries/types.d.ts +1 -0
  52. package/dist/esm/hooks/useShapes/area/prepare-data.js +2 -1
  53. package/dist/esm/hooks/useShapes/line/prepare-data.js +3 -2
  54. package/dist/esm/hooks/useShapes/utils.d.ts +6 -0
  55. package/dist/esm/hooks/useShapes/utils.js +29 -4
  56. package/dist/esm/hooks/useShapes/waterfall/index.js +1 -1
  57. package/dist/esm/libs/format-number/index.d.ts +7 -3
  58. package/dist/esm/libs/format-number/index.js +8 -3
  59. package/dist/esm/libs/format-number/types.d.ts +0 -1
  60. package/dist/esm/types/chart/tooltip.d.ts +1 -0
  61. package/dist/esm/types/formatter.d.ts +0 -1
  62. package/dist/esm/utils/chart/axis-generators/bottom.js +21 -28
  63. package/dist/esm/utils/chart/get-closest-data.d.ts +1 -0
  64. package/dist/esm/utils/chart/get-closest-data.js +2 -5
  65. package/dist/esm/utils/chart/index.d.ts +1 -0
  66. package/dist/esm/utils/chart/index.js +3 -2
  67. package/dist/esm/utils/chart/series/index.d.ts +1 -0
  68. package/dist/esm/utils/chart/series/index.js +1 -0
  69. package/dist/esm/utils/chart/series/sorting.d.ts +2 -0
  70. package/dist/esm/utils/chart/series/sorting.js +12 -0
  71. package/dist/{cjs/hooks/hooks-utils → esm/utils/chart}/zoom.d.ts +5 -2
  72. package/dist/{cjs/hooks/hooks-utils → esm/utils/chart}/zoom.js +36 -9
  73. package/package.json +1 -1
  74. package/dist/cjs/hooks/hooks-utils/index.d.ts +0 -1
  75. package/dist/cjs/hooks/hooks-utils/index.js +0 -1
  76. package/dist/esm/hooks/hooks-utils/index.d.ts +0 -1
  77. package/dist/esm/hooks/hooks-utils/index.js +0 -1
@@ -1,7 +1,11 @@
1
- import type { ChartData } from '../../types';
1
+ import type { ChartSeries, ChartTitle, ChartTooltip, ChartOptions as GeneralChartOptions } from '../../types';
2
2
  import type { ChartOptions } from './types';
3
3
  type Args = {
4
- data: ChartData;
4
+ seriesData: ChartSeries[];
5
+ chart?: GeneralChartOptions;
6
+ colors?: string[];
7
+ title?: ChartTitle;
8
+ tooltip?: ChartTooltip;
5
9
  };
6
10
  export declare const useChartOptions: (args: Args) => ChartOptions;
7
11
  export {};
@@ -4,21 +4,21 @@ import { getPreparedChart } from './chart';
4
4
  import { getPreparedTitle } from './title';
5
5
  import { getPreparedTooltip } from './tooltip';
6
6
  export const useChartOptions = (args) => {
7
- const { data: { chart, title, tooltip, colors, series }, } = args;
7
+ const { chart, colors, seriesData, title, tooltip } = args;
8
8
  const options = React.useMemo(() => {
9
9
  const preparedTitle = getPreparedTitle({ title });
10
10
  const preparedTooltip = getPreparedTooltip({ tooltip });
11
11
  const preparedChart = getPreparedChart({
12
12
  chart,
13
13
  preparedTitle,
14
- seriesData: series.data,
14
+ seriesData,
15
15
  });
16
16
  return {
17
+ colors: colors !== null && colors !== void 0 ? colors : DEFAULT_PALETTE,
17
18
  chart: preparedChart,
18
19
  title: preparedTitle,
19
20
  tooltip: preparedTooltip,
20
- colors: colors !== null && colors !== void 0 ? colors : DEFAULT_PALETTE,
21
21
  };
22
- }, [chart, colors, title, tooltip, series.data]);
22
+ }, [chart, colors, seriesData, title, tooltip]);
23
23
  return options;
24
24
  };
@@ -1,34 +1,16 @@
1
1
  import type { ChartData } from '../../types';
2
- import type { PreparedAxis, PreparedChart } from '../useChartOptions/types';
3
2
  import type { OnLegendItemClick, PreparedLegend, PreparedSeries } from './types';
4
3
  type Args = {
5
- chartWidth: number;
6
- chartHeight: number;
7
- chartMargin: PreparedChart['margin'];
8
4
  colors: string[];
9
5
  legend: ChartData['legend'];
10
6
  originalSeriesData: ChartData['series']['data'];
11
7
  seriesData: ChartData['series']['data'];
12
8
  seriesOptions: ChartData['series']['options'];
13
- preparedYAxis: PreparedAxis[];
9
+ preparedLegend?: PreparedLegend;
14
10
  };
15
11
  export declare const useSeries: (args: Args) => {
16
- legendItems: never[] | import("./types").LegendItem[][];
17
- legendConfig: {
18
- offset: {
19
- left: number;
20
- top: number;
21
- };
22
- pagination: {
23
- pages: {
24
- start: number;
25
- end: number;
26
- }[];
27
- } | undefined;
28
- } | undefined;
29
12
  preparedLegend: PreparedLegend | null;
30
13
  preparedSeries: PreparedSeries[];
31
- preparedSeriesOptions: import("../../constants").SeriesOptionsDefaults;
32
14
  handleLegendItemClick: OnLegendItemClick;
33
15
  };
34
16
  export {};
@@ -2,16 +2,17 @@ import React from 'react';
2
2
  import { group, scaleOrdinal } from 'd3';
3
3
  import { getSeriesNames } from '../../utils';
4
4
  import { usePrevious } from '../usePrevious';
5
- import { getLegendComponents, getPreparedLegend } from './prepare-legend';
6
- import { getPreparedOptions } from './prepare-options';
5
+ import { getPreparedLegend } from './prepare-legend';
7
6
  import { prepareSeries } from './prepareSeries';
8
7
  import { getActiveLegendItems, getAllLegendItems } from './utils';
9
8
  export const useSeries = (args) => {
10
- const { chartWidth, chartHeight, chartMargin, legend, originalSeriesData, preparedYAxis, seriesData, seriesOptions, colors, } = args;
11
- const [preparedLegend, setPreparedLegend] = React.useState(null);
9
+ const { legend, originalSeriesData, seriesData, seriesOptions, colors, preparedLegend: preparedLegendProps = null, } = args;
10
+ const [preparedLegend, setPreparedLegend] = React.useState(preparedLegendProps);
12
11
  React.useEffect(() => {
13
- getPreparedLegend({ legend, series: seriesData }).then((value) => setPreparedLegend(value));
14
- }, [legend, seriesData]);
12
+ if (!preparedLegendProps) {
13
+ getPreparedLegend({ legend, series: seriesData }).then((value) => setPreparedLegend(value));
14
+ }
15
+ }, [legend, preparedLegendProps, seriesData]);
15
16
  const [preparedSeries, setPreparedSeries] = React.useState([]);
16
17
  const [activeLegendItems, setActiveLegendItems] = React.useState(getActiveLegendItems(preparedSeries));
17
18
  React.useEffect(() => {
@@ -39,9 +40,6 @@ export const useSeries = (args) => {
39
40
  setActiveLegendItems(getActiveLegendItems(acc));
40
41
  })();
41
42
  }, [seriesData, seriesOptions, preparedLegend, colors]);
42
- const preparedSeriesOptions = React.useMemo(() => {
43
- return getPreparedOptions(seriesOptions);
44
- }, [seriesOptions]);
45
43
  const prevOriginalSeriesData = usePrevious(originalSeriesData);
46
44
  const chartSeries = React.useMemo(() => {
47
45
  return preparedSeries.map((singleSeries) => {
@@ -51,19 +49,6 @@ export const useSeries = (args) => {
51
49
  return singleSeries;
52
50
  });
53
51
  }, [preparedSeries, activeLegendItems]);
54
- const { legendConfig, legendItems } = React.useMemo(() => {
55
- if (!preparedLegend) {
56
- return { legendConfig: undefined, legendItems: [] };
57
- }
58
- return getLegendComponents({
59
- chartHeight,
60
- chartMargin,
61
- chartWidth,
62
- series: chartSeries,
63
- preparedLegend,
64
- preparedYAxis,
65
- });
66
- }, [chartWidth, chartHeight, chartMargin, chartSeries, preparedLegend, preparedYAxis]);
67
52
  const handleLegendItemClick = React.useCallback(({ name, metaKey }) => {
68
53
  const allItems = getAllLegendItems(preparedSeries);
69
54
  const onlyItemSelected = activeLegendItems.length === 1 && activeLegendItems.includes(name);
@@ -91,11 +76,8 @@ export const useSeries = (args) => {
91
76
  }
92
77
  }, [originalSeriesData, prevOriginalSeriesData, preparedSeries]);
93
78
  return {
94
- legendItems,
95
- legendConfig,
96
79
  preparedLegend,
97
80
  preparedSeries: chartSeries,
98
- preparedSeriesOptions,
99
81
  handleLegendItemClick,
100
82
  };
101
83
  };
@@ -1,4 +1,3 @@
1
- import { sort } from 'd3';
2
1
  import get from 'lodash/get';
3
2
  import merge from 'lodash/merge';
4
3
  import { DEFAULT_DATALABELS_STYLE } from '../../constants';
@@ -46,7 +45,7 @@ export function prepareArea(args) {
46
45
  enabled: get(series, 'legend.enabled', legend.enabled),
47
46
  symbol: prepareLegendSymbol(series),
48
47
  },
49
- data: sort(series.data, (d) => d.x),
48
+ data: series.data,
50
49
  stacking: series.stacking,
51
50
  stackId: getSeriesStackId(series),
52
51
  dataLabels: {
@@ -21,9 +21,13 @@ export async function getPreparedLegend(args) {
21
21
  const titleText = isTitleEnabled ? get(legend, 'title.text', '') : '';
22
22
  const titleSize = await getLabelsSize({ labels: [titleText], style: titleStyle });
23
23
  const titleHeight = isTitleEnabled ? titleSize.maxHeight : 0;
24
+ const tickStyle = {
25
+ fontSize: '12px',
26
+ };
24
27
  const ticks = {
25
28
  labelsMargin: 4,
26
- labelsLineHeight: 12,
29
+ labelsLineHeight: (await getLabelsSize({ labels: ['Tmp'], style: tickStyle })).maxHeight,
30
+ style: tickStyle,
27
31
  };
28
32
  const colorScale = {
29
33
  colors: [],
@@ -26,6 +26,7 @@ export type PreparedLegend = Required<Omit<ChartLegend, 'title' | 'colorScale'>>
26
26
  ticks: {
27
27
  labelsMargin: number;
28
28
  labelsLineHeight: number;
29
+ style: BaseTextStyle;
29
30
  };
30
31
  colorScale: {
31
32
  colors: string[];
@@ -36,7 +36,7 @@ function getXValues(series, xAxis, xScale) {
36
36
  ? getDataCategoryValue({ axisDirection: 'x', categories, data: d })
37
37
  : d.x);
38
38
  if (!acc.has(key)) {
39
- acc.set(key, getXValue({ point: d, xAxis, xScale }));
39
+ acc.set(key, getXValue({ point: d, points: s.data, xAxis, xScale }));
40
40
  }
41
41
  });
42
42
  return acc;
@@ -73,6 +73,7 @@ export const prepareAreaData = async (args) => {
73
73
  const seriesYScale = yScale[yAxisIndex];
74
74
  const yMin = getYValue({
75
75
  point: { y: 0 },
76
+ points: s.data,
76
77
  yAxis: seriesYAxis,
77
78
  yScale: seriesYScale,
78
79
  });
@@ -51,8 +51,9 @@ export const prepareLineData = async (args) => {
51
51
  const yAxisTop = ((_a = split.plots[seriesYAxis.plotIndex]) === null || _a === void 0 ? void 0 : _a.top) || 0;
52
52
  const seriesYScale = yScale[s.yAxis];
53
53
  const points = s.data.map((d) => ({
54
- x: getXValue({ point: d, xAxis, xScale }),
55
- y: yAxisTop + getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale }),
54
+ x: getXValue({ point: d, points: s.data, xAxis, xScale }),
55
+ y: yAxisTop +
56
+ getYValue({ point: d, points: s.data, yAxis: seriesYAxis, yScale: seriesYScale }),
56
57
  active: true,
57
58
  data: d,
58
59
  series: s,
@@ -6,6 +6,9 @@ export declare function getXValue(args: {
6
6
  point: {
7
7
  x?: number | string;
8
8
  };
9
+ points?: {
10
+ x?: number | string;
11
+ }[];
9
12
  xAxis: PreparedAxis;
10
13
  xScale: ChartScale;
11
14
  }): number;
@@ -13,6 +16,9 @@ export declare function getYValue(args: {
13
16
  point: {
14
17
  y?: number | string;
15
18
  };
19
+ points?: {
20
+ y?: number | string;
21
+ }[];
16
22
  yAxis: PreparedAxis;
17
23
  yScale: ChartScale;
18
24
  }): number;
@@ -1,26 +1,51 @@
1
1
  import { path, select } from 'd3';
2
2
  import get from 'lodash/get';
3
3
  import { getDataCategoryValue } from '../../utils';
4
+ const ONE_POINT_DOMAIN_DATA_CAPACITY = 3;
4
5
  export function getXValue(args) {
5
- const { point, xAxis, xScale } = args;
6
+ const { point, points, xAxis, xScale } = args;
6
7
  if (xAxis.type === 'category') {
7
8
  const xBandScale = xScale;
8
9
  const categories = get(xAxis, 'categories', []);
9
10
  const dataCategory = getDataCategoryValue({ axisDirection: 'x', categories, data: point });
10
11
  return (xBandScale(dataCategory) || 0) + xBandScale.step() / 2;
11
12
  }
12
- const xLinearScale = xScale;
13
+ let xLinearScale = xScale;
14
+ const [xMinDomain, xMaxDomain] = xLinearScale.domain();
15
+ if (Number(xMinDomain) === Number(xMaxDomain) &&
16
+ (points === null || points === void 0 ? void 0 : points.length) === ONE_POINT_DOMAIN_DATA_CAPACITY) {
17
+ const x1 = points[0].x;
18
+ const xTarget = points[1].x;
19
+ const x3 = points[2].x;
20
+ const xMin = Math.min(x1, xTarget, x3);
21
+ const xMax = Math.max(x1, xTarget, x3);
22
+ xLinearScale = xLinearScale
23
+ .copy()
24
+ .domain([xMin + (xTarget - xMin) / 2, xMax - (xMax - xTarget) / 2]);
25
+ }
13
26
  return xLinearScale(point.x);
14
27
  }
15
28
  export function getYValue(args) {
16
- const { point, yAxis, yScale } = args;
29
+ const { point, points, yAxis, yScale } = args;
17
30
  if (yAxis.type === 'category') {
18
31
  const yBandScale = yScale;
19
32
  const categories = get(yAxis, 'categories', []);
20
33
  const dataCategory = getDataCategoryValue({ axisDirection: 'y', categories, data: point });
21
34
  return (yBandScale(dataCategory) || 0) + yBandScale.step() / 2;
22
35
  }
23
- const yLinearScale = yScale;
36
+ let yLinearScale = yScale;
37
+ const [yMinDomain, yMaxDomain] = yLinearScale.domain();
38
+ if (Number(yMinDomain) === Number(yMaxDomain) &&
39
+ (points === null || points === void 0 ? void 0 : points.length) === ONE_POINT_DOMAIN_DATA_CAPACITY) {
40
+ const y1 = points[0].y;
41
+ const yTarget = points[1].y;
42
+ const y2 = points[2].y;
43
+ const yMin = Math.min(y1, yTarget, y2);
44
+ const yMax = Math.max(y1, yTarget, y2);
45
+ yLinearScale = yLinearScale
46
+ .copy()
47
+ .domain([yMin + (yTarget - yMin) / 2, yMax - (yMax - yTarget) / 2]);
48
+ }
24
49
  return yLinearScale(point.y);
25
50
  }
26
51
  export function shapeKey(d) {
@@ -125,7 +125,7 @@ export const WaterfallSeriesShapes = (args) => {
125
125
  return () => {
126
126
  dispatcher.on('hover-shape.waterfall', null);
127
127
  };
128
- }, [dispatcher, preparedData, seriesOptions]);
128
+ }, [connectorSelector, dispatcher, preparedData, seriesOptions]);
129
129
  return (React.createElement(React.Fragment, null,
130
130
  React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
131
131
  React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
@@ -1,5 +1,9 @@
1
1
  import type { FormatNumberOptions, FormatOptions } from './types';
2
- export declare const formatBytes: (value: number, options?: FormatOptions) => string;
3
- export declare const formatDuration: (value: number, options?: FormatOptions) => string;
4
- export declare const getNumberUnitRate: (value: number) => number;
2
+ export declare const formatBytes: (value: number, options?: FormatOptions & {
3
+ unitRate?: number;
4
+ }) => string;
5
+ export declare const formatDuration: (value: number, options?: FormatOptions & {
6
+ unitRate?: number;
7
+ }) => string;
8
+ export declare const getDefaultUnit: (value: number) => string | undefined;
5
9
  export declare const formatNumber: (value: number | string, options?: FormatNumberOptions) => string;
@@ -59,7 +59,6 @@ const baseFormatNumber = unitFormatter({
59
59
  unitDelimiterI18nKey: 'value_number-delimiter',
60
60
  unitsI18nKeys: BASE_NUMBER_FORMAT_UNIT_KEYS,
61
61
  });
62
- export const getNumberUnitRate = (value) => getUnitRate(value, 1000, BASE_NUMBER_FORMAT_UNIT_KEYS);
63
62
  const NUMBER_UNIT_RATE_BY_UNIT = {
64
63
  default: 0,
65
64
  auto: undefined,
@@ -68,11 +67,17 @@ const NUMBER_UNIT_RATE_BY_UNIT = {
68
67
  b: 3,
69
68
  t: 4,
70
69
  };
70
+ export const getDefaultUnit = (value) => {
71
+ var _a;
72
+ const unitRate = getUnitRate(value, 1000, BASE_NUMBER_FORMAT_UNIT_KEYS);
73
+ const [unit] = (_a = Object.entries(NUMBER_UNIT_RATE_BY_UNIT).find(([_key, val]) => val === unitRate)) !== null && _a !== void 0 ? _a : [];
74
+ return unit;
75
+ };
71
76
  export const formatNumber = (value, options = {}) => {
72
77
  if (Number.isNaN(value) || Number.isNaN(Number(value))) {
73
78
  return new Intl.NumberFormat('en').format(Number(value));
74
79
  }
75
- const { format = 'number', multiplier = 1, prefix = '', postfix = '', unit, unitRate, labelMode, } = options;
80
+ const { format = 'number', multiplier = 1, prefix = '', postfix = '', unit, labelMode } = options;
76
81
  let changedMultiplier = multiplier;
77
82
  let prePostfix = '';
78
83
  if (format === 'percent') {
@@ -82,6 +87,6 @@ export const formatNumber = (value, options = {}) => {
82
87
  if (labelMode === 'percent') {
83
88
  prePostfix = '%';
84
89
  }
85
- const formattedValue = baseFormatNumber(Number(value) * changedMultiplier, Object.assign(Object.assign({}, options), { unitRate: unitRate !== null && unitRate !== void 0 ? unitRate : NUMBER_UNIT_RATE_BY_UNIT[unit !== null && unit !== void 0 ? unit : 'default'] }));
90
+ const formattedValue = baseFormatNumber(Number(value) * changedMultiplier, Object.assign(Object.assign({}, options), { unitRate: NUMBER_UNIT_RATE_BY_UNIT[unit !== null && unit !== void 0 ? unit : 'default'] }));
86
91
  return `${prefix}${formattedValue}${prePostfix}${postfix}`;
87
92
  };
@@ -1,6 +1,5 @@
1
1
  export type FormatOptions = {
2
2
  precision?: number | 'auto';
3
- unitRate?: number;
4
3
  showRankDelimiter?: boolean;
5
4
  lang?: string;
6
5
  labelMode?: string;
@@ -63,6 +63,7 @@ export interface TooltipDataChunkSankey<T = MeaningfulAny> {
63
63
  export interface TooltipDataChunkWaterfall<T = MeaningfulAny> {
64
64
  data: WaterfallSeriesData<T>;
65
65
  series: WaterfallSeries<T>;
66
+ subTotal?: number;
66
67
  }
67
68
  export interface TooltipDataChunkRadar<T = MeaningfulAny> {
68
69
  data: RadarSeriesData<T>;
@@ -1,6 +1,5 @@
1
1
  export interface FormatOptions {
2
2
  precision?: number | 'auto';
3
- unitRate?: number;
4
3
  showRankDelimiter?: boolean;
5
4
  lang?: string;
6
5
  labelMode?: string;
@@ -90,27 +90,15 @@ export async function axisBottom(args) {
90
90
  });
91
91
  }
92
92
  else {
93
- // remove overlapping labels
94
93
  let elementX = 0;
95
- selection
96
- .selectAll('.tick')
97
- .filter(function () {
98
- const node = this;
99
- const r = node.getBoundingClientRect();
100
- if (r.left < elementX) {
101
- return true;
102
- }
103
- elementX = r.right + labelsPaddings;
104
- return false;
105
- })
106
- .remove();
107
94
  // add an ellipsis to the labels that go beyond the boundaries of the chart
95
+ // and remove overlapping labels
108
96
  labels.each(function (_d, i, nodes) {
109
- var _a;
97
+ var _a, _b;
98
+ const currentElement = this;
99
+ const currentElementPosition = currentElement.getBoundingClientRect();
110
100
  if (i === 0) {
111
- const currentElement = this;
112
101
  const text = select(currentElement);
113
- const currentElementPosition = currentElement.getBoundingClientRect();
114
102
  const nextElement = nodes[i + 1];
115
103
  const nextElementPosition = nextElement === null || nextElement === void 0 ? void 0 : nextElement.getBoundingClientRect();
116
104
  if (currentElementPosition.left < leftmostLimit) {
@@ -123,18 +111,23 @@ export async function axisBottom(args) {
123
111
  setEllipsisForOverflowText(text, remainSpace);
124
112
  }
125
113
  }
126
- if (i === nodes.length - 1) {
127
- const currentElement = this;
128
- const prevElement = nodes[i - 1];
129
- const text = select(currentElement);
130
- const currentElementPosition = currentElement.getBoundingClientRect();
131
- const prevElementPosition = prevElement === null || prevElement === void 0 ? void 0 : prevElement.getBoundingClientRect();
132
- const lackingSpace = Math.max(0, currentElementPosition.right - right);
133
- if (lackingSpace) {
134
- const remainSpace = right - ((prevElementPosition === null || prevElementPosition === void 0 ? void 0 : prevElementPosition.right) || 0) - labelsPaddings;
135
- const translateX = -lackingSpace;
136
- text.style('transform', `translate(${translateX}px,${translateY}px)`);
137
- setEllipsisForOverflowText(text, remainSpace);
114
+ else {
115
+ if (currentElementPosition.left < elementX) {
116
+ (_b = currentElement.closest('.tick')) === null || _b === void 0 ? void 0 : _b.remove();
117
+ return;
118
+ }
119
+ elementX = currentElementPosition.right + labelsPaddings;
120
+ if (i === nodes.length - 1) {
121
+ const prevElement = nodes[i - 1];
122
+ const text = select(currentElement);
123
+ const prevElementPosition = prevElement === null || prevElement === void 0 ? void 0 : prevElement.getBoundingClientRect();
124
+ const lackingSpace = Math.max(0, currentElementPosition.right - right);
125
+ if (lackingSpace) {
126
+ const remainSpace = right - ((prevElementPosition === null || prevElementPosition === void 0 ? void 0 : prevElementPosition.right) || 0) - labelsPaddings;
127
+ const translateX = -lackingSpace;
128
+ text.style('transform', `translate(${translateX}px,${translateY}px)`);
129
+ setEllipsisForOverflowText(text, remainSpace);
130
+ }
138
131
  }
139
132
  }
140
133
  });
@@ -12,6 +12,7 @@ export type ShapePoint = {
12
12
  y1: number;
13
13
  data: ChartSeriesData;
14
14
  series: ChartSeries;
15
+ subTotal?: number;
15
16
  };
16
17
  export declare function getClosestPoints(args: GetClosestPointsArgs): TooltipDataChunk[];
17
18
  export {};
@@ -35,11 +35,7 @@ function getClosestPointsByXValue(x, y, points) {
35
35
  });
36
36
  const closestPoints = sort(groupedBySeries, (p) => p.y0);
37
37
  const closestYIndex = getClosestYIndex(closestPoints, y);
38
- return closestPoints.map((p, i) => ({
39
- data: p.data,
40
- series: p.series,
41
- closest: i === closestYIndex,
42
- }));
38
+ return closestPoints.map((p, i) => (Object.assign(Object.assign({}, p), { closest: i === closestYIndex })));
43
39
  }
44
40
  function getSeriesType(shapeData) {
45
41
  return (get(shapeData, 'series.type') ||
@@ -73,6 +69,7 @@ export function getClosestPoints(args) {
73
69
  x: d.x + d.width / 2,
74
70
  y0: d.y,
75
71
  y1: d.y + d.height,
72
+ subTotal: d.subTotal,
76
73
  }));
77
74
  result.push(...getClosestPointsByXValue(pointerX, pointerY, points));
78
75
  break;
@@ -11,6 +11,7 @@ export * from './legend';
11
11
  export * from './symbol';
12
12
  export * from './series';
13
13
  export * from './color';
14
+ export * from './zoom';
14
15
  export declare const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS: ChartSeries['type'][];
15
16
  export declare const CHART_SERIES_WITH_VOLUME_ON_X_AXIS: ChartSeries['type'][];
16
17
  type UnknownSeries = {
@@ -5,7 +5,7 @@ import isNil from 'lodash/isNil';
5
5
  import sortBy from 'lodash/sortBy';
6
6
  import { DEFAULT_AXIS_LABEL_FONT_SIZE } from '../../constants';
7
7
  import { getSeriesStackId } from '../../hooks/useSeries/utils';
8
- import { formatNumber, getNumberUnitRate } from '../../libs/format-number';
8
+ import { formatNumber, getDefaultUnit } from '../../libs/format-number';
9
9
  import { getWaterfallPointSubtotal } from './series/waterfall';
10
10
  import { getDefaultDateFormat } from './time';
11
11
  export * from './math';
@@ -17,6 +17,7 @@ export * from './legend';
17
17
  export * from './symbol';
18
18
  export * from './series';
19
19
  export * from './color';
20
+ export * from './zoom';
20
21
  const CHARTS_WITHOUT_AXIS = ['pie', 'treemap', 'sankey', 'radar'];
21
22
  export const CHART_SERIES_WITH_VOLUME_ON_Y_AXIS = [
22
23
  'bar-x',
@@ -184,7 +185,7 @@ export const formatAxisTickLabel = (args) => {
184
185
  }
185
186
  case 'linear':
186
187
  default: {
187
- const numberFormat = Object.assign({ unitRate: value && step ? getNumberUnitRate(step) : undefined }, axis.labels.numberFormat);
188
+ const numberFormat = Object.assign({ unit: value && step ? getDefaultUnit(step) : undefined }, axis.labels.numberFormat);
188
189
  return formatNumber(value, numberFormat);
189
190
  }
190
191
  }
@@ -1,2 +1,3 @@
1
1
  export * from './line';
2
+ export * from './sorting';
2
3
  export * from './waterfall';
@@ -1,2 +1,3 @@
1
1
  export * from './line';
2
+ export * from './sorting';
2
3
  export * from './waterfall';
@@ -0,0 +1,2 @@
1
+ import type { ChartSeries } from '../../../types';
2
+ export declare function getSortedSeriesData(seriesData: ChartSeries[]): ChartSeries[];
@@ -0,0 +1,12 @@
1
+ import { sort } from 'd3';
2
+ import { SeriesType } from '../../../constants';
3
+ export function getSortedSeriesData(seriesData) {
4
+ return seriesData.map((s) => {
5
+ switch (s.type) {
6
+ case SeriesType.Area: {
7
+ s.data = sort(s.data, (d) => d.x);
8
+ }
9
+ }
10
+ return s;
11
+ });
12
+ }
@@ -1,8 +1,11 @@
1
+ import type { ZoomState } from '../../hooks/useZoom/types';
1
2
  import type { ChartSeries, ChartXAxis, ChartYAxis } from '../../types';
2
- import type { ZoomState } from '../useZoom/types';
3
3
  export declare function getZoomedSeriesData(args: {
4
4
  seriesData: ChartSeries[];
5
5
  zoomState: Partial<ZoomState>;
6
6
  xAxis?: ChartXAxis;
7
7
  yAxes?: ChartYAxis[];
8
- }): ChartSeries[];
8
+ }): {
9
+ zoomedSeriesData: ChartSeries[];
10
+ zoomedShapesSeriesData: ChartSeries[];
11
+ };
@@ -1,3 +1,5 @@
1
+ import { SeriesType } from '../../constants';
2
+ const SERIES_TYPE_WITH_HIDDEN_POINTS = [SeriesType.Area, SeriesType.Line];
1
3
  // eslint-disable-next-line complexity
2
4
  function isValueInRange(args) {
3
5
  const { axis, max, min, value } = args;
@@ -41,13 +43,24 @@ function isValueInRange(args) {
41
43
  }
42
44
  export function getZoomedSeriesData(args) {
43
45
  const { seriesData, xAxis, yAxes, zoomState } = args;
44
- if (Object.keys(zoomState).length < 0) {
45
- return seriesData;
46
+ if (Object.keys(zoomState).length <= 0) {
47
+ return { zoomedSeriesData: seriesData, zoomedShapesSeriesData: seriesData };
46
48
  }
47
- return seriesData.map((seriesItem) => {
48
- const filteredData = seriesItem.data.reduce((acc, point) => {
49
+ const zoomedSeriesData = [];
50
+ const zoomedShapesSeriesData = [];
51
+ let prevPointInRange = false;
52
+ let currentPointInRange = false;
53
+ seriesData.forEach((seriesItem) => {
54
+ const filteredData = [];
55
+ const filteredShapesData = SERIES_TYPE_WITH_HIDDEN_POINTS.includes(seriesItem.type) && (xAxis === null || xAxis === void 0 ? void 0 : xAxis.type) !== 'category'
56
+ ? []
57
+ : undefined;
58
+ seriesItem.data.forEach((point, i) => {
59
+ const prevPoint = seriesItem.data[i - 1];
60
+ const isFirstPoint = i === 0;
49
61
  let inXRange = true;
50
62
  let inYRange = true;
63
+ prevPointInRange = currentPointInRange;
51
64
  if (zoomState.x) {
52
65
  const [xMin, xMax] = zoomState.x;
53
66
  const x = 'x' in point ? point.x : undefined;
@@ -71,11 +84,25 @@ export function getZoomedSeriesData(args) {
71
84
  max: yMax,
72
85
  });
73
86
  }
74
- if (inXRange && inYRange) {
75
- acc.push(point);
87
+ currentPointInRange = inXRange && inYRange;
88
+ if (currentPointInRange) {
89
+ filteredData.push(point);
76
90
  }
77
- return acc;
78
- }, []);
79
- return Object.assign(Object.assign({}, seriesItem), { data: filteredData });
91
+ if (filteredShapesData) {
92
+ if (prevPointInRange && !currentPointInRange) {
93
+ filteredShapesData.push(point);
94
+ }
95
+ else if (!isFirstPoint && !prevPointInRange && currentPointInRange) {
96
+ filteredShapesData.push(prevPoint, point);
97
+ }
98
+ else if ((isFirstPoint || (!isFirstPoint && prevPointInRange)) &&
99
+ currentPointInRange) {
100
+ filteredShapesData.push(point);
101
+ }
102
+ }
103
+ });
104
+ zoomedSeriesData.push(Object.assign(Object.assign({}, seriesItem), { data: filteredData }));
105
+ zoomedShapesSeriesData.push(Object.assign(Object.assign({}, seriesItem), { data: filteredShapesData || filteredData }));
80
106
  });
107
+ return { zoomedSeriesData, zoomedShapesSeriesData };
81
108
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.11.1",
3
+ "version": "1.11.3",
4
4
  "description": "React component used to render charts",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",
@@ -1 +0,0 @@
1
- export * from './zoom';
@@ -1 +0,0 @@
1
- export * from './zoom';
@@ -1 +0,0 @@
1
- export * from './zoom';
@@ -1 +0,0 @@
1
- export * from './zoom';