@gravity-ui/charts 1.11.1 → 1.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/dist/cjs/components/ChartInner/useChartInnerProps.js +35 -11
  2. package/dist/cjs/components/Tooltip/DefaultContent.js +4 -4
  3. package/dist/cjs/hooks/useAxisScales/index.js +15 -6
  4. package/dist/cjs/hooks/useSeries/index.d.ts +1 -19
  5. package/dist/cjs/hooks/useSeries/index.js +7 -25
  6. package/dist/cjs/hooks/useSeries/prepare-area.js +1 -2
  7. package/dist/cjs/hooks/useShapes/area/prepare-data.js +2 -1
  8. package/dist/cjs/hooks/useShapes/line/prepare-data.js +3 -2
  9. package/dist/cjs/hooks/useShapes/utils.d.ts +6 -0
  10. package/dist/cjs/hooks/useShapes/utils.js +29 -4
  11. package/dist/cjs/hooks/useShapes/waterfall/index.js +1 -1
  12. package/dist/cjs/libs/format-number/index.d.ts +7 -3
  13. package/dist/cjs/libs/format-number/index.js +8 -3
  14. package/dist/cjs/libs/format-number/types.d.ts +0 -1
  15. package/dist/cjs/types/chart/tooltip.d.ts +1 -0
  16. package/dist/cjs/types/formatter.d.ts +0 -1
  17. package/dist/cjs/utils/chart/get-closest-data.d.ts +1 -0
  18. package/dist/cjs/utils/chart/get-closest-data.js +2 -5
  19. package/dist/cjs/utils/chart/index.d.ts +1 -0
  20. package/dist/cjs/utils/chart/index.js +3 -2
  21. package/dist/cjs/utils/chart/series/index.d.ts +1 -0
  22. package/dist/cjs/utils/chart/series/index.js +1 -0
  23. package/dist/cjs/utils/chart/series/sorting.d.ts +2 -0
  24. package/dist/cjs/utils/chart/series/sorting.js +12 -0
  25. package/dist/{esm/hooks/hooks-utils → cjs/utils/chart}/zoom.d.ts +5 -2
  26. package/dist/{esm/hooks/hooks-utils → cjs/utils/chart}/zoom.js +36 -9
  27. package/dist/esm/components/ChartInner/useChartInnerProps.js +35 -11
  28. package/dist/esm/components/Tooltip/DefaultContent.js +4 -4
  29. package/dist/esm/hooks/useAxisScales/index.js +15 -6
  30. package/dist/esm/hooks/useSeries/index.d.ts +1 -19
  31. package/dist/esm/hooks/useSeries/index.js +7 -25
  32. package/dist/esm/hooks/useSeries/prepare-area.js +1 -2
  33. package/dist/esm/hooks/useShapes/area/prepare-data.js +2 -1
  34. package/dist/esm/hooks/useShapes/line/prepare-data.js +3 -2
  35. package/dist/esm/hooks/useShapes/utils.d.ts +6 -0
  36. package/dist/esm/hooks/useShapes/utils.js +29 -4
  37. package/dist/esm/hooks/useShapes/waterfall/index.js +1 -1
  38. package/dist/esm/libs/format-number/index.d.ts +7 -3
  39. package/dist/esm/libs/format-number/index.js +8 -3
  40. package/dist/esm/libs/format-number/types.d.ts +0 -1
  41. package/dist/esm/types/chart/tooltip.d.ts +1 -0
  42. package/dist/esm/types/formatter.d.ts +0 -1
  43. package/dist/esm/utils/chart/get-closest-data.d.ts +1 -0
  44. package/dist/esm/utils/chart/get-closest-data.js +2 -5
  45. package/dist/esm/utils/chart/index.d.ts +1 -0
  46. package/dist/esm/utils/chart/index.js +3 -2
  47. package/dist/esm/utils/chart/series/index.d.ts +1 -0
  48. package/dist/esm/utils/chart/series/index.js +1 -0
  49. package/dist/esm/utils/chart/series/sorting.d.ts +2 -0
  50. package/dist/esm/utils/chart/series/sorting.js +12 -0
  51. package/dist/{cjs/hooks/hooks-utils → esm/utils/chart}/zoom.d.ts +5 -2
  52. package/dist/{cjs/hooks/hooks-utils → esm/utils/chart}/zoom.js +36 -9
  53. package/package.json +1 -1
  54. package/dist/cjs/hooks/hooks-utils/index.d.ts +0 -1
  55. package/dist/cjs/hooks/hooks-utils/index.js +0 -1
  56. package/dist/esm/hooks/hooks-utils/index.d.ts +0 -1
  57. package/dist/esm/hooks/hooks-utils/index.js +0 -1
@@ -1,10 +1,12 @@
1
1
  import React from 'react';
2
2
  import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapes, useSplit, } from '../../hooks';
3
- import { getZoomedSeriesData } from '../../hooks/hooks-utils';
4
3
  import { getYAxisWidth } from '../../hooks/useChartDimensions/utils';
5
4
  import { getPreparedXAxis } from '../../hooks/useChartOptions/x-axis';
6
5
  import { getPreparedYAxis } from '../../hooks/useChartOptions/y-axis';
6
+ import { getLegendComponents } from '../../hooks/useSeries/prepare-legend';
7
+ import { getPreparedOptions } from '../../hooks/useSeries/prepare-options';
7
8
  import { useZoom } from '../../hooks/useZoom';
9
+ import { getSortedSeriesData, getZoomedSeriesData } from '../../utils';
8
10
  import { hasAtLeastOneSeriesDataPerPlot } from './utils';
9
11
  export function useChartInnerProps(props) {
10
12
  var _a;
@@ -13,14 +15,17 @@ export function useChartInnerProps(props) {
13
15
  const prevHeight = usePrevious(height);
14
16
  const [zoomState, setZoomState] = React.useState({});
15
17
  const { chart, title, tooltip, colors } = useChartOptions({ data });
16
- const zoomedSeriesData = React.useMemo(() => {
18
+ const sortedSeriesData = React.useMemo(() => {
19
+ return getSortedSeriesData(data.series.data);
20
+ }, [data.series.data]);
21
+ const { zoomedSeriesData, zoomedShapesSeriesData } = React.useMemo(() => {
17
22
  return getZoomedSeriesData({
18
- seriesData: data.series.data,
23
+ seriesData: sortedSeriesData,
19
24
  xAxis: data.xAxis,
20
25
  yAxes: data.yAxis,
21
26
  zoomState,
22
27
  });
23
- }, [data.series.data, data.xAxis, data.yAxis, zoomState]);
28
+ }, [data.xAxis, data.yAxis, sortedSeriesData, zoomState]);
24
29
  const [xAxis, setXAxis] = React.useState(null);
25
30
  React.useEffect(() => {
26
31
  setXAxis(null);
@@ -31,17 +36,36 @@ export function useChartInnerProps(props) {
31
36
  setYAxis([]);
32
37
  getPreparedYAxis({ yAxis: data.yAxis, height, seriesData: zoomedSeriesData }).then((val) => setYAxis(val));
33
38
  }, [data.yAxis, height, zoomedSeriesData]);
34
- const { legendItems, legendConfig, preparedSeries, preparedSeriesOptions, preparedLegend, handleLegendItemClick, } = useSeries({
35
- chartWidth: width,
36
- chartHeight: height,
37
- chartMargin: chart.margin,
39
+ const preparedSeriesOptions = React.useMemo(() => {
40
+ return getPreparedOptions(data.series.options);
41
+ }, [data.series.options]);
42
+ const { preparedSeries, preparedLegend, handleLegendItemClick } = useSeries({
38
43
  colors,
39
44
  legend: data.legend,
40
45
  originalSeriesData: data.series.data,
41
46
  seriesData: zoomedSeriesData,
42
47
  seriesOptions: data.series.options,
43
- preparedYAxis: yAxis,
44
48
  });
49
+ const { preparedSeries: preparedShapesSeries } = useSeries({
50
+ colors,
51
+ legend: data.legend,
52
+ originalSeriesData: data.series.data,
53
+ seriesData: zoomedShapesSeriesData,
54
+ seriesOptions: data.series.options,
55
+ });
56
+ const { legendConfig, legendItems } = React.useMemo(() => {
57
+ if (!preparedLegend) {
58
+ return { legendConfig: undefined, legendItems: [] };
59
+ }
60
+ return getLegendComponents({
61
+ chartWidth: width,
62
+ chartHeight: height,
63
+ chartMargin: chart.margin,
64
+ series: preparedSeries,
65
+ preparedLegend,
66
+ preparedYAxis: yAxis,
67
+ });
68
+ }, [width, height, chart.margin, preparedSeries, preparedLegend, yAxis]);
45
69
  const { boundsWidth, boundsHeight } = useChartDimensions({
46
70
  width,
47
71
  height,
@@ -69,7 +93,7 @@ export function useChartInnerProps(props) {
69
93
  boundsWidth,
70
94
  boundsHeight,
71
95
  dispatcher,
72
- series: preparedSeries,
96
+ series: preparedShapesSeries,
73
97
  seriesOptions: preparedSeriesOptions,
74
98
  xAxis,
75
99
  xScale,
@@ -81,7 +105,7 @@ export function useChartInnerProps(props) {
81
105
  isOutsideBounds,
82
106
  });
83
107
  const handleAttemptToSetZoomState = React.useCallback((nextZoomState) => {
84
- const nextZoomedSeriesData = getZoomedSeriesData({
108
+ const { zoomedSeriesData: nextZoomedSeriesData } = getZoomedSeriesData({
85
109
  seriesData: zoomedSeriesData,
86
110
  xAxis: data.xAxis,
87
111
  yAxes: data.yAxis,
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import get from 'lodash/get';
3
- import { block, getDataCategoryValue, getWaterfallPointSubtotal } from '../../utils';
3
+ import { block, getDataCategoryValue } from '../../utils';
4
4
  import { getFormattedValue } from '../../utils/chart/format';
5
5
  const b = block('tooltip');
6
6
  const DEFAULT_DATE_FORMAT = 'DD.MM.YY';
@@ -62,7 +62,7 @@ export const DefaultContent = ({ hovered, xAxis, yAxis, valueFormat }) => {
62
62
  measureValue && React.createElement("div", { className: b('series-name') }, measureValue),
63
63
  // eslint-disable-next-line complexity
64
64
  hovered.map((seriesItem, i) => {
65
- var _a;
65
+ var _a, _b;
66
66
  const { data, series, closest } = seriesItem;
67
67
  const id = `${get(series, 'id')}_${i}`;
68
68
  const color = get(series, 'color');
@@ -87,7 +87,7 @@ export const DefaultContent = ({ hovered, xAxis, yAxis, valueFormat }) => {
87
87
  }
88
88
  case 'waterfall': {
89
89
  const isTotal = get(data, 'total', false);
90
- const subTotalValue = getWaterfallPointSubtotal(data, series);
90
+ const subTotalValue = (_a = seriesItem.subTotal) !== null && _a !== void 0 ? _a : 0;
91
91
  const format = valueFormat !== null && valueFormat !== void 0 ? valueFormat : getDefaultValueFormat({ axis: yAxis });
92
92
  const subTotal = getFormattedValue({
93
93
  value: subTotalValue,
@@ -145,7 +145,7 @@ export const DefaultContent = ({ hovered, xAxis, yAxis, valueFormat }) => {
145
145
  }
146
146
  case 'sankey': {
147
147
  const { target, data: source } = seriesItem;
148
- const value = (_a = source.links.find((d) => d.name === (target === null || target === void 0 ? void 0 : target.name))) === null || _a === void 0 ? void 0 : _a.value;
148
+ const value = (_b = source.links.find((d) => d.name === (target === null || target === void 0 ? void 0 : target.name))) === null || _b === void 0 ? void 0 : _b.value;
149
149
  const formattedValue = getFormattedValue({
150
150
  value,
151
151
  format: valueFormat !== null && valueFormat !== void 0 ? valueFormat : { type: 'number' },
@@ -3,6 +3,7 @@ import { extent, scaleBand, scaleLinear, scaleLog, scaleUtc } from 'd3';
3
3
  import get from 'lodash/get';
4
4
  import { DEFAULT_AXIS_TYPE } from '../../constants';
5
5
  import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisHeight, getDataCategoryValue, getDefaultMaxXAxisValue, getDefaultMinXAxisValue, getDomainDataXBySeries, getDomainDataYBySeries, getOnlyVisibleSeries, isAxisRelatedSeries, isSeriesWithCategoryValues, } from '../../utils';
6
+ const X_AXIS_ZOOM_PADDING = 0.02;
6
7
  const isNumericalArrayData = (data) => {
7
8
  return data.every((d) => typeof d === 'number' || d === null);
8
9
  };
@@ -103,8 +104,10 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
103
104
  const xCategories = get(axis, 'categories');
104
105
  const xTimestamps = get(axis, 'timestamps');
105
106
  const maxPadding = get(axis, 'maxPadding', 0);
106
- const xAxisMinPadding = boundsWidth * maxPadding + calculateXAxisPadding(series);
107
- const xRange = [0, boundsWidth - xAxisMinPadding];
107
+ const xAxisMaxPadding = boundsWidth * maxPadding + calculateXAxisPadding(series);
108
+ const xAxisZoomPadding = boundsWidth * X_AXIS_ZOOM_PADDING;
109
+ const xRange = [0, boundsWidth - xAxisMaxPadding];
110
+ const xRangeZoom = [0 + xAxisZoomPadding, boundsWidth - xAxisZoomPadding];
108
111
  switch (xType) {
109
112
  case 'linear':
110
113
  case 'logarithmic': {
@@ -131,7 +134,9 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
131
134
  : xMaxDomain;
132
135
  }
133
136
  const scaleFn = xType === 'logarithmic' ? scaleLog : scaleLinear;
134
- const scale = scaleFn().domain([xMin, xMax]).range(xRange);
137
+ const scale = scaleFn()
138
+ .domain([xMin, xMax])
139
+ .range(hasZoomX ? xRangeZoom : xRange);
135
140
  if (!hasZoomX) {
136
141
  scale.nice();
137
142
  }
@@ -147,7 +152,7 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
147
152
  series: series,
148
153
  });
149
154
  const xScale = scaleBand().domain(filteredCategories).range([0, boundsWidth]);
150
- if (xScale.step() / 2 < xAxisMinPadding) {
155
+ if (xScale.step() / 2 < xAxisMaxPadding) {
151
156
  xScale.range(xRange);
152
157
  }
153
158
  return xScale;
@@ -159,7 +164,9 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
159
164
  const [xMinTimestamp, xMaxTimestamp] = extent(xTimestamps);
160
165
  const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
161
166
  const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
162
- const scale = scaleUtc().domain([xMin, xMax]).range(xRange);
167
+ const scale = scaleUtc()
168
+ .domain([xMin, xMax])
169
+ .range(hasZoomX ? xRangeZoom : xRange);
163
170
  if (!hasZoomX) {
164
171
  scale.nice();
165
172
  }
@@ -171,7 +178,9 @@ export function createXScale(axis, series, boundsWidth, hasZoomX) {
171
178
  const [xMinTimestamp, xMaxTimestamp] = extent(domain);
172
179
  const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
173
180
  const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
174
- const scale = scaleUtc().domain([xMin, xMax]).range(xRange);
181
+ const scale = scaleUtc()
182
+ .domain([xMin, xMax])
183
+ .range(hasZoomX ? xRangeZoom : xRange);
175
184
  if (!hasZoomX) {
176
185
  scale.nice();
177
186
  }
@@ -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: {
@@ -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;
@@ -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
+ };