@gravity-ui/charts 1.31.0 → 1.32.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 (41) hide show
  1. package/dist/cjs/components/ChartInner/index.js +7 -1
  2. package/dist/cjs/components/ChartInner/types.d.ts +6 -0
  3. package/dist/cjs/components/index.d.ts +1 -0
  4. package/dist/cjs/components/index.js +4 -4
  5. package/dist/cjs/constants/line-styles.d.ts +6 -0
  6. package/dist/cjs/constants/line-styles.js +7 -0
  7. package/dist/cjs/hooks/useSeries/prepare-line.js +8 -1
  8. package/dist/cjs/hooks/useSeries/types.d.ts +2 -1
  9. package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +1 -0
  10. package/dist/cjs/hooks/useShapes/area/prepare-data.js +2 -2
  11. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.d.ts +1 -0
  12. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +15 -6
  13. package/dist/cjs/hooks/useShapes/index.js +2 -0
  14. package/dist/cjs/hooks/useShapes/line/index.js +1 -1
  15. package/dist/cjs/hooks/useShapes/line/prepare-data.js +2 -1
  16. package/dist/cjs/hooks/useShapes/line/types.d.ts +2 -1
  17. package/dist/cjs/types/chart/line.d.ts +3 -1
  18. package/dist/cjs/types/chart/series.d.ts +6 -1
  19. package/dist/cjs/utils/chart/index.d.ts +1 -1
  20. package/dist/cjs/utils/chart/index.js +23 -19
  21. package/dist/esm/components/ChartInner/index.js +7 -1
  22. package/dist/esm/components/ChartInner/types.d.ts +6 -0
  23. package/dist/esm/components/index.d.ts +1 -0
  24. package/dist/esm/components/index.js +4 -4
  25. package/dist/esm/constants/line-styles.d.ts +6 -0
  26. package/dist/esm/constants/line-styles.js +7 -0
  27. package/dist/esm/hooks/useSeries/prepare-line.js +8 -1
  28. package/dist/esm/hooks/useSeries/types.d.ts +2 -1
  29. package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +1 -0
  30. package/dist/esm/hooks/useShapes/area/prepare-data.js +2 -2
  31. package/dist/esm/hooks/useShapes/bar-x/prepare-data.d.ts +1 -0
  32. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +15 -6
  33. package/dist/esm/hooks/useShapes/index.js +2 -0
  34. package/dist/esm/hooks/useShapes/line/index.js +1 -1
  35. package/dist/esm/hooks/useShapes/line/prepare-data.js +2 -1
  36. package/dist/esm/hooks/useShapes/line/types.d.ts +2 -1
  37. package/dist/esm/types/chart/line.d.ts +3 -1
  38. package/dist/esm/types/chart/series.d.ts +6 -1
  39. package/dist/esm/utils/chart/index.d.ts +1 -1
  40. package/dist/esm/utils/chart/index.js +23 -19
  41. package/package.json +1 -1
@@ -26,7 +26,7 @@ const b = block('chart');
26
26
  const DEBOUNCED_VALUE_DELAY = 10;
27
27
  export const ChartInner = (props) => {
28
28
  var _a, _b, _c, _d, _e, _f;
29
- const { width, height, data } = props;
29
+ const { width, height, data, onReady } = props;
30
30
  const svgRef = React.useRef(null);
31
31
  const resetZoomButtonRef = React.useRef(null);
32
32
  const [htmlLayout, setHtmlLayout] = React.useState(null);
@@ -206,6 +206,12 @@ export const ChartInner = (props) => {
206
206
  updateRangeSliderState,
207
207
  xScale,
208
208
  ]);
209
+ const areShapesReady = shapes.length > 0;
210
+ React.useEffect(() => {
211
+ if (areShapesReady) {
212
+ onReady === null || onReady === void 0 ? void 0 : onReady({ dimensions: { width, height } });
213
+ }
214
+ }, [height, areShapesReady, onReady, width]);
209
215
  const chartContent = (React.createElement(React.Fragment, null,
210
216
  React.createElement("defs", null,
211
217
  React.createElement("clipPath", { id: clipPathId },
@@ -3,4 +3,10 @@ export type ChartInnerProps = {
3
3
  width: number;
4
4
  height: number;
5
5
  data: ChartData;
6
+ onReady?: (args: {
7
+ dimensions: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ }) => void;
6
12
  };
@@ -15,5 +15,6 @@ export interface ChartProps {
15
15
  data: ChartData;
16
16
  lang?: string;
17
17
  onResize?: ChartOnResize;
18
+ onReady?: ChartOnResize;
18
19
  }
19
20
  export declare const Chart: React.ForwardRefExoticComponent<ChartProps & React.RefAttributes<ChartRef>>;
@@ -7,7 +7,7 @@ import { validateData } from '../validation';
7
7
  import { ChartInner } from './ChartInner';
8
8
  export * from './Tooltip/ChartTooltipContent';
9
9
  export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
10
- const { data, lang, onResize } = props;
10
+ const { data, lang, onResize, onReady } = props;
11
11
  const validatedData = React.useRef();
12
12
  const ref = React.useRef(null);
13
13
  const debounced = React.useRef();
@@ -36,8 +36,8 @@ export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
36
36
  }), [debuncedHandleResize]);
37
37
  React.useEffect(() => {
38
38
  // dimensions initialize
39
- debuncedHandleResize();
40
- }, [debuncedHandleResize]);
39
+ handleResize();
40
+ }, [handleResize]);
41
41
  React.useEffect(() => {
42
42
  const selection = select(window);
43
43
  // https://github.com/d3/d3-selection/blob/main/README.md#handling-events
@@ -62,5 +62,5 @@ export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
62
62
  width: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) || '100%',
63
63
  height: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) || '100%',
64
64
  position: 'relative',
65
- } }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (React.createElement(ChartInner, { height: dimensions === null || dimensions === void 0 ? void 0 : dimensions.height, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, data: data }))));
65
+ } }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (React.createElement(ChartInner, { height: dimensions === null || dimensions === void 0 ? void 0 : dimensions.height, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, data: data, onReady: onReady }))));
66
66
  });
@@ -18,3 +18,9 @@ export declare enum LineCap {
18
18
  Square = "square",
19
19
  None = "none"
20
20
  }
21
+ export declare enum LineJoin {
22
+ Round = "round",
23
+ Bevel = "bevel",
24
+ Miter = "miter",
25
+ None = "unset"
26
+ }
@@ -18,3 +18,10 @@ export var LineCap;
18
18
  LineCap["Square"] = "square";
19
19
  LineCap["None"] = "none";
20
20
  })(LineCap || (LineCap = {}));
21
+ export var LineJoin;
22
+ (function (LineJoin) {
23
+ LineJoin["Round"] = "round";
24
+ LineJoin["Bevel"] = "bevel";
25
+ LineJoin["Miter"] = "miter";
26
+ LineJoin["None"] = "unset";
27
+ })(LineJoin || (LineJoin = {}));
@@ -1,6 +1,6 @@
1
1
  import get from 'lodash/get';
2
2
  import merge from 'lodash/merge';
3
- import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap, seriesRangeSliderOptionsDefaults, } from '../../constants';
3
+ import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap, LineJoin, seriesRangeSliderOptionsDefaults, } from '../../constants';
4
4
  import { getUniqId } from '../../utils';
5
5
  import { DEFAULT_DATALABELS_PADDING, DEFAULT_HALO_OPTIONS, DEFAULT_LEGEND_SYMBOL_PADDING, DEFAULT_POINT_MARKER_OPTIONS, } from './constants';
6
6
  export const DEFAULT_LEGEND_SYMBOL_SIZE = 16;
@@ -12,6 +12,12 @@ function prepareLinecap(dashStyle, series, seriesOptions) {
12
12
  const lineCapFromSeriesOptions = get(seriesOptions, 'line.linecap', defaultLineCap);
13
13
  return get(series, 'linecap', lineCapFromSeriesOptions);
14
14
  }
15
+ function prepareLinejoin(dashStyle, series, seriesOptions) {
16
+ var _a, _b, _c;
17
+ const defaultLinejoin = dashStyle === DASH_STYLE.Solid ? LineJoin.Round : LineJoin.None;
18
+ const linejoinFromSeriesOptions = (_b = (_a = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.line) === null || _a === void 0 ? void 0 : _a.linejoin) !== null && _b !== void 0 ? _b : defaultLinejoin;
19
+ return ((_c = series === null || series === void 0 ? void 0 : series.linejoin) !== null && _c !== void 0 ? _c : linejoinFromSeriesOptions);
20
+ }
15
21
  function prepareLineLegendSymbol(series, seriesOptions) {
16
22
  var _a;
17
23
  const symbolOptions = ((_a = series.legend) === null || _a === void 0 ? void 0 : _a.symbol) || {};
@@ -90,6 +96,7 @@ export function prepareLineSeries(args) {
90
96
  marker: prepareMarker(series, seriesOptions),
91
97
  dashStyle: dashStyle,
92
98
  linecap: prepareLinecap(dashStyle, series, seriesOptions),
99
+ linejoin: prepareLinejoin(dashStyle, series, seriesOptions),
93
100
  opacity: get(series, 'opacity', null),
94
101
  cursor: get(series, 'cursor', null),
95
102
  yAxis: get(series, 'yAxis', 0),
@@ -1,4 +1,4 @@
1
- import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
1
+ import type { DashStyle, LayoutAlgorithm, LineCap, LineJoin, SeriesOptionsDefaults, SymbolType } from '../../constants';
2
2
  import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, LineSeriesLineBaseStyle, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
3
3
  export type RectLegendSymbol = {
4
4
  shape: 'rect';
@@ -222,6 +222,7 @@ export type PreparedLineSeries = {
222
222
  };
223
223
  dashStyle: DashStyle;
224
224
  linecap: LineCap;
225
+ linejoin: LineJoin;
225
226
  opacity: number | null;
226
227
  yAxis: number;
227
228
  } & BasePreparedSeries & BasePreparedAxisRelatedSeries;
@@ -12,4 +12,5 @@ export declare const prepareAreaData: (args: {
12
12
  boundsHeight: number;
13
13
  split: PreparedSplit;
14
14
  isOutsideBounds: (x: number, y: number) => boolean;
15
+ isRangeSlider?: boolean;
15
16
  }) => Promise<PreparedAreaData[]>;
@@ -74,7 +74,7 @@ async function prepareDataLabels({ series, points, xMax, yAxisTop, }) {
74
74
  }
75
75
  export const prepareAreaData = async (args) => {
76
76
  var _a, _b;
77
- const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isOutsideBounds, } = args;
77
+ const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isOutsideBounds, isRangeSlider, } = args;
78
78
  const [_xMin, xRangeMax] = xScale.range();
79
79
  const xMax = xRangeMax;
80
80
  const result = [];
@@ -147,7 +147,7 @@ export const prepareAreaData = async (args) => {
147
147
  }, []);
148
148
  const labels = [];
149
149
  const htmlElements = [];
150
- if (s.dataLabels.enabled) {
150
+ if (s.dataLabels.enabled && !isRangeSlider) {
151
151
  const labelsData = await prepareDataLabels({ series: s, points, xMax, yAxisTop });
152
152
  labels.push(...labelsData.svgLabels);
153
153
  htmlElements.push(...labelsData.htmlLabels);
@@ -12,4 +12,5 @@ export declare const prepareBarXData: (args: {
12
12
  yScale: (ChartScale | undefined)[];
13
13
  boundsHeight: number;
14
14
  split: PreparedSplit;
15
+ isRangeSlider?: boolean;
15
16
  }) => Promise<PreparedBarXData[]>;
@@ -35,7 +35,7 @@ async function getLabelData(d) {
35
35
  // eslint-disable-next-line complexity
36
36
  export const prepareBarXData = async (args) => {
37
37
  var _a, _b, _c, _d;
38
- const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, } = args;
38
+ const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isRangeSlider, } = args;
39
39
  const stackGap = seriesOptions['bar-x'].stackGap;
40
40
  const categories = (_a = xAxis === null || xAxis === void 0 ? void 0 : xAxis.categories) !== null && _a !== void 0 ? _a : [];
41
41
  const sortingOptions = get(seriesOptions, 'bar-x.dataSorting');
@@ -99,7 +99,8 @@ export const prepareBarXData = async (args) => {
99
99
  const currentGroupWidth = rectWidth * stacks.length + rectGap * (stacks.length - 1);
100
100
  for (let groupItemIndex = 0; groupItemIndex < stacks.length; groupItemIndex++) {
101
101
  const yValues = stacks[groupItemIndex];
102
- let stackHeight = 0;
102
+ let positiveStackHeight = 0;
103
+ let negativeStackHeight = 0;
103
104
  const stackItems = [];
104
105
  const sortedData = sortKey
105
106
  ? sort(yValues, (a, b) => comparator(get(a, sortKey), get(b, sortKey)))
@@ -117,6 +118,7 @@ export const prepareBarXData = async (args) => {
117
118
  if (xAxis.type === 'category') {
118
119
  const xBandScale = xScale;
119
120
  const xBandScaleDomain = xBandScale.domain();
121
+ // eslint-disable-next-line max-depth
120
122
  if (xBandScaleDomain.indexOf(xValue) === -1) {
121
123
  continue;
122
124
  }
@@ -141,7 +143,9 @@ export const prepareBarXData = async (args) => {
141
143
  }
142
144
  const barData = {
143
145
  x,
144
- y: yAxisTop + (yDataValue > 0 ? y - stackHeight : base),
146
+ y: yDataValue > 0
147
+ ? yAxisTop + y - positiveStackHeight
148
+ : yAxisTop + base + negativeStackHeight,
145
149
  width: rectWidth,
146
150
  height: shapeHeight,
147
151
  opacity: get(yValue.data, 'opacity', null),
@@ -151,11 +155,16 @@ export const prepareBarXData = async (args) => {
151
155
  isLastStackItem,
152
156
  };
153
157
  stackItems.push(barData);
154
- stackHeight += height;
158
+ if (yDataValue > 0) {
159
+ positiveStackHeight += height;
160
+ }
161
+ else {
162
+ negativeStackHeight += height;
163
+ }
155
164
  }
156
165
  if (series.some((s) => s.stacking === 'percent')) {
157
166
  let acc = 0;
158
- const ratio = plotHeight / (stackHeight - stackItems.length);
167
+ const ratio = plotHeight / (positiveStackHeight - stackItems.length);
159
168
  stackItems.forEach((item) => {
160
169
  item.height = item.height * ratio;
161
170
  item.y = plotHeight - item.height - acc;
@@ -168,7 +177,7 @@ export const prepareBarXData = async (args) => {
168
177
  }
169
178
  for (let i = 0; i < result.length; i++) {
170
179
  const barData = result[i];
171
- if (barData.series.dataLabels.enabled) {
180
+ if (barData.series.dataLabels.enabled && !isRangeSlider) {
172
181
  const label = await getLabelData(barData);
173
182
  if (barData.series.dataLabels.html && label) {
174
183
  barData.htmlElements.push({
@@ -58,6 +58,7 @@ export const useShapes = (args) => {
58
58
  yScale,
59
59
  boundsHeight,
60
60
  split,
61
+ isRangeSlider,
61
62
  });
62
63
  shapes.push(React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
63
64
  shapesData.push(...preparedData);
@@ -124,6 +125,7 @@ export const useShapes = (args) => {
124
125
  boundsHeight,
125
126
  split,
126
127
  isOutsideBounds,
128
+ isRangeSlider,
127
129
  });
128
130
  shapes.push(React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
129
131
  shapesData.push(...preparedData);
@@ -34,7 +34,7 @@ export const LineSeriesShapes = (args) => {
34
34
  .attr('fill', 'none')
35
35
  .attr('stroke', (d) => d.color)
36
36
  .attr('stroke-width', (d) => d.lineWidth)
37
- .attr('stroke-linejoin', (d) => d.linecap)
37
+ .attr('stroke-linejoin', (d) => d.linejoin)
38
38
  .attr('stroke-linecap', (d) => d.linecap)
39
39
  .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
40
40
  .attr('opacity', (d) => d.opacity)
@@ -44,7 +44,7 @@ export const prepareLineData = async (args) => {
44
44
  });
45
45
  const htmlElements = [];
46
46
  const labels = [];
47
- if (s.dataLabels.enabled) {
47
+ if (s.dataLabels.enabled && !isRangeSlider) {
48
48
  if (s.dataLabels.html) {
49
49
  const list = await Promise.all(points.reduce((result, p) => {
50
50
  if (p.y === null) {
@@ -108,6 +108,7 @@ export const prepareLineData = async (args) => {
108
108
  lineWidth: (_b = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _b !== void 0 ? _b : s.lineWidth,
109
109
  dashStyle: s.dashStyle,
110
110
  linecap: s.linecap,
111
+ linejoin: s.linejoin,
111
112
  opacity: (_c = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _c !== void 0 ? _c : s.opacity,
112
113
  };
113
114
  acc.push(result);
@@ -1,4 +1,4 @@
1
- import type { DashStyle, LineCap } from '../../../constants';
1
+ import type { DashStyle, LineCap, LineJoin } from '../../../constants';
2
2
  import type { HtmlItem, LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
3
3
  import type { PreparedLineSeries } from '../../useSeries/types';
4
4
  export type PointData = {
@@ -30,4 +30,5 @@ export type PreparedLineData = {
30
30
  color: string;
31
31
  dashStyle: DashStyle;
32
32
  linecap: LineCap;
33
+ linejoin: LineJoin;
33
34
  } & Required<LineSeriesLineBaseStyle>;
@@ -1,4 +1,4 @@
1
- import type { DashStyle, LineCap, SERIES_TYPE } from '../../constants';
1
+ import type { DashStyle, LineCap, LineJoin, SERIES_TYPE } from '../../constants';
2
2
  import type { MeaningfulAny } from '../misc';
3
3
  import type { BaseSeries, BaseSeriesData, BaseSeriesLegend } from './base';
4
4
  import type { RectLegendSymbolOptions } from './legend';
@@ -53,6 +53,8 @@ export interface LineSeries<T = MeaningfulAny> extends BaseSeries, LineSeriesLin
53
53
  dashStyle?: DashStyle;
54
54
  /** Option for line cap style */
55
55
  linecap?: `${LineCap}`;
56
+ /** Defines the shape to be used at the corners of the line */
57
+ linejoin?: `${LineJoin}`;
56
58
  /** Individual series legend options. Has higher priority than legend options in widget data */
57
59
  legend?: BaseSeriesLegend & {
58
60
  symbol?: RectLegendSymbolOptions;
@@ -1,5 +1,5 @@
1
1
  import type React from 'react';
2
- import type { DashStyle, LineCap } from '../../constants';
2
+ import type { DashStyle, LineCap, LineJoin } from '../../constants';
3
3
  import type { MeaningfulAny } from '../misc';
4
4
  import type { AreaSeries, AreaSeriesData } from './area';
5
5
  import type { BarXSeries, BarXSeriesData } from './bar-x';
@@ -211,6 +211,11 @@ export interface ChartSeriesOptions {
211
211
  * @default 'round' when dashStyle is not 'solid', 'none' when dashStyle is not 'solid'
212
212
  * */
213
213
  linecap?: `${LineCap}`;
214
+ /** Defines the shape to be used at the corners of the line
215
+ *
216
+ * @default 'round' when dashStyle is not 'solid', 'unset' when dashStyle is not 'solid'
217
+ * */
218
+ linejoin?: `${LineJoin}`;
214
219
  };
215
220
  area?: {
216
221
  /** Pixel width of the graph line.
@@ -46,8 +46,8 @@ export declare function isSeriesWithCategoryValues(series: UnknownSeries): serie
46
46
  export declare const getDomainDataXBySeries: (series: UnknownSeries[]) => ({} | undefined)[];
47
47
  export declare function getDefaultMaxXAxisValue(series: UnknownSeries[]): 0 | undefined;
48
48
  export declare function getDefaultMinXAxisValue(series: UnknownSeries[]): number | undefined;
49
- export declare function getDefaultMinYAxisValue(series?: UnknownSeries[]): number | undefined;
50
49
  export declare const getDomainDataYBySeries: (series: UnknownSeries[]) => unknown[];
50
+ export declare function getDefaultMinYAxisValue(series?: UnknownSeries[]): number | undefined;
51
51
  export declare const getSeriesNames: (series: ChartSeries[]) => string[];
52
52
  export declare const getOnlyVisibleSeries: <T extends {
53
53
  visible: boolean;
@@ -46,7 +46,8 @@ function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y
46
46
  const acc = [];
47
47
  const stackedSeries = group(seriesList, getSeriesStackId);
48
48
  Array.from(stackedSeries).forEach(([_stackId, seriesStack]) => {
49
- const values = {};
49
+ const positiveValues = {};
50
+ const negativeValues = {};
50
51
  seriesStack.forEach((singleSeries) => {
51
52
  const data = new Map();
52
53
  singleSeries.data.forEach((point) => {
@@ -65,10 +66,15 @@ function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y
65
66
  data.set(key, value);
66
67
  });
67
68
  Array.from(data).forEach(([key, value]) => {
68
- values[key] = (values[key] || 0) + value;
69
+ if (value >= 0) {
70
+ positiveValues[key] = (positiveValues[key] || 0) + value;
71
+ }
72
+ if (value < 0) {
73
+ negativeValues[key] = (negativeValues[key] || 0) + value;
74
+ }
69
75
  });
70
76
  });
71
- acc.push(...Object.values(values));
77
+ acc.push(...Object.values(negativeValues), ...Object.values(positiveValues));
72
78
  });
73
79
  return acc;
74
80
  }
@@ -107,22 +113,6 @@ export function getDefaultMinXAxisValue(series) {
107
113
  }
108
114
  return undefined;
109
115
  }
110
- export function getDefaultMinYAxisValue(series) {
111
- if (series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type))) {
112
- if (series.some((s) => s.type === SERIES_TYPE.Waterfall)) {
113
- const seriesData = series.map((s) => s.data).flat();
114
- const minSubTotal = seriesData.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, seriesData) || 0), 0);
115
- return Math.min(0, minSubTotal);
116
- }
117
- return series.reduce((minValue, s) => {
118
- // https://github.com/gravity-ui/charts/issues/160
119
- // @ts-expect-error
120
- const minYValue = s.data.reduce((res, d) => Math.min(res, get(d, 'y', 0)), 0);
121
- return Math.min(minValue, minYValue);
122
- }, 0);
123
- }
124
- return undefined;
125
- }
126
116
  export const getDomainDataYBySeries = (series) => {
127
117
  const groupedSeries = group(series, (item) => item.type);
128
118
  const items = Array.from(groupedSeries).reduce((acc, [type, seriesList]) => {
@@ -151,6 +141,20 @@ export const getDomainDataYBySeries = (series) => {
151
141
  }, []);
152
142
  return Array.from(new Set(items));
153
143
  };
144
+ export function getDefaultMinYAxisValue(series) {
145
+ if (series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type))) {
146
+ if (series.some((s) => s.type === SERIES_TYPE.Waterfall)) {
147
+ const seriesData = series.map((s) => s.data).flat();
148
+ const minSubTotal = seriesData.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, seriesData) || 0), 0);
149
+ return Math.min(0, minSubTotal);
150
+ }
151
+ const domainData = getDomainDataYBySeries(series);
152
+ return domainData.reduce((minValue, d) => {
153
+ return Math.min(minValue, d);
154
+ }, 0);
155
+ }
156
+ return undefined;
157
+ }
154
158
  // Uses to get all series names array (except `pie` charts)
155
159
  export const getSeriesNames = (series) => {
156
160
  return series.reduce((acc, s) => {
@@ -26,7 +26,7 @@ const b = block('chart');
26
26
  const DEBOUNCED_VALUE_DELAY = 10;
27
27
  export const ChartInner = (props) => {
28
28
  var _a, _b, _c, _d, _e, _f;
29
- const { width, height, data } = props;
29
+ const { width, height, data, onReady } = props;
30
30
  const svgRef = React.useRef(null);
31
31
  const resetZoomButtonRef = React.useRef(null);
32
32
  const [htmlLayout, setHtmlLayout] = React.useState(null);
@@ -206,6 +206,12 @@ export const ChartInner = (props) => {
206
206
  updateRangeSliderState,
207
207
  xScale,
208
208
  ]);
209
+ const areShapesReady = shapes.length > 0;
210
+ React.useEffect(() => {
211
+ if (areShapesReady) {
212
+ onReady === null || onReady === void 0 ? void 0 : onReady({ dimensions: { width, height } });
213
+ }
214
+ }, [height, areShapesReady, onReady, width]);
209
215
  const chartContent = (React.createElement(React.Fragment, null,
210
216
  React.createElement("defs", null,
211
217
  React.createElement("clipPath", { id: clipPathId },
@@ -3,4 +3,10 @@ export type ChartInnerProps = {
3
3
  width: number;
4
4
  height: number;
5
5
  data: ChartData;
6
+ onReady?: (args: {
7
+ dimensions: {
8
+ width: number;
9
+ height: number;
10
+ };
11
+ }) => void;
6
12
  };
@@ -15,5 +15,6 @@ export interface ChartProps {
15
15
  data: ChartData;
16
16
  lang?: string;
17
17
  onResize?: ChartOnResize;
18
+ onReady?: ChartOnResize;
18
19
  }
19
20
  export declare const Chart: React.ForwardRefExoticComponent<ChartProps & React.RefAttributes<ChartRef>>;
@@ -7,7 +7,7 @@ import { validateData } from '../validation';
7
7
  import { ChartInner } from './ChartInner';
8
8
  export * from './Tooltip/ChartTooltipContent';
9
9
  export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
10
- const { data, lang, onResize } = props;
10
+ const { data, lang, onResize, onReady } = props;
11
11
  const validatedData = React.useRef();
12
12
  const ref = React.useRef(null);
13
13
  const debounced = React.useRef();
@@ -36,8 +36,8 @@ export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
36
36
  }), [debuncedHandleResize]);
37
37
  React.useEffect(() => {
38
38
  // dimensions initialize
39
- debuncedHandleResize();
40
- }, [debuncedHandleResize]);
39
+ handleResize();
40
+ }, [handleResize]);
41
41
  React.useEffect(() => {
42
42
  const selection = select(window);
43
43
  // https://github.com/d3/d3-selection/blob/main/README.md#handling-events
@@ -62,5 +62,5 @@ export const Chart = React.forwardRef(function Chart(props, forwardedRef) {
62
62
  width: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) || '100%',
63
63
  height: (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) || '100%',
64
64
  position: 'relative',
65
- } }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (React.createElement(ChartInner, { height: dimensions === null || dimensions === void 0 ? void 0 : dimensions.height, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, data: data }))));
65
+ } }, (dimensions === null || dimensions === void 0 ? void 0 : dimensions.height) && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) && (React.createElement(ChartInner, { height: dimensions === null || dimensions === void 0 ? void 0 : dimensions.height, width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, data: data, onReady: onReady }))));
66
66
  });
@@ -18,3 +18,9 @@ export declare enum LineCap {
18
18
  Square = "square",
19
19
  None = "none"
20
20
  }
21
+ export declare enum LineJoin {
22
+ Round = "round",
23
+ Bevel = "bevel",
24
+ Miter = "miter",
25
+ None = "unset"
26
+ }
@@ -18,3 +18,10 @@ export var LineCap;
18
18
  LineCap["Square"] = "square";
19
19
  LineCap["None"] = "none";
20
20
  })(LineCap || (LineCap = {}));
21
+ export var LineJoin;
22
+ (function (LineJoin) {
23
+ LineJoin["Round"] = "round";
24
+ LineJoin["Bevel"] = "bevel";
25
+ LineJoin["Miter"] = "miter";
26
+ LineJoin["None"] = "unset";
27
+ })(LineJoin || (LineJoin = {}));
@@ -1,6 +1,6 @@
1
1
  import get from 'lodash/get';
2
2
  import merge from 'lodash/merge';
3
- import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap, seriesRangeSliderOptionsDefaults, } from '../../constants';
3
+ import { DASH_STYLE, DEFAULT_DATALABELS_STYLE, LineCap, LineJoin, seriesRangeSliderOptionsDefaults, } from '../../constants';
4
4
  import { getUniqId } from '../../utils';
5
5
  import { DEFAULT_DATALABELS_PADDING, DEFAULT_HALO_OPTIONS, DEFAULT_LEGEND_SYMBOL_PADDING, DEFAULT_POINT_MARKER_OPTIONS, } from './constants';
6
6
  export const DEFAULT_LEGEND_SYMBOL_SIZE = 16;
@@ -12,6 +12,12 @@ function prepareLinecap(dashStyle, series, seriesOptions) {
12
12
  const lineCapFromSeriesOptions = get(seriesOptions, 'line.linecap', defaultLineCap);
13
13
  return get(series, 'linecap', lineCapFromSeriesOptions);
14
14
  }
15
+ function prepareLinejoin(dashStyle, series, seriesOptions) {
16
+ var _a, _b, _c;
17
+ const defaultLinejoin = dashStyle === DASH_STYLE.Solid ? LineJoin.Round : LineJoin.None;
18
+ const linejoinFromSeriesOptions = (_b = (_a = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions.line) === null || _a === void 0 ? void 0 : _a.linejoin) !== null && _b !== void 0 ? _b : defaultLinejoin;
19
+ return ((_c = series === null || series === void 0 ? void 0 : series.linejoin) !== null && _c !== void 0 ? _c : linejoinFromSeriesOptions);
20
+ }
15
21
  function prepareLineLegendSymbol(series, seriesOptions) {
16
22
  var _a;
17
23
  const symbolOptions = ((_a = series.legend) === null || _a === void 0 ? void 0 : _a.symbol) || {};
@@ -90,6 +96,7 @@ export function prepareLineSeries(args) {
90
96
  marker: prepareMarker(series, seriesOptions),
91
97
  dashStyle: dashStyle,
92
98
  linecap: prepareLinecap(dashStyle, series, seriesOptions),
99
+ linejoin: prepareLinejoin(dashStyle, series, seriesOptions),
93
100
  opacity: get(series, 'opacity', null),
94
101
  cursor: get(series, 'cursor', null),
95
102
  yAxis: get(series, 'yAxis', 0),
@@ -1,4 +1,4 @@
1
- import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
1
+ import type { DashStyle, LayoutAlgorithm, LineCap, LineJoin, SeriesOptionsDefaults, SymbolType } from '../../constants';
2
2
  import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ChartSeriesRangeSliderOptions, ConnectorCurve, ConnectorShape, FunnelSeries, FunnelSeriesData, HeatmapSeries, HeatmapSeriesData, LineSeries, LineSeriesData, LineSeriesLineBaseStyle, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
3
3
  export type RectLegendSymbol = {
4
4
  shape: 'rect';
@@ -222,6 +222,7 @@ export type PreparedLineSeries = {
222
222
  };
223
223
  dashStyle: DashStyle;
224
224
  linecap: LineCap;
225
+ linejoin: LineJoin;
225
226
  opacity: number | null;
226
227
  yAxis: number;
227
228
  } & BasePreparedSeries & BasePreparedAxisRelatedSeries;
@@ -12,4 +12,5 @@ export declare const prepareAreaData: (args: {
12
12
  boundsHeight: number;
13
13
  split: PreparedSplit;
14
14
  isOutsideBounds: (x: number, y: number) => boolean;
15
+ isRangeSlider?: boolean;
15
16
  }) => Promise<PreparedAreaData[]>;
@@ -74,7 +74,7 @@ async function prepareDataLabels({ series, points, xMax, yAxisTop, }) {
74
74
  }
75
75
  export const prepareAreaData = async (args) => {
76
76
  var _a, _b;
77
- const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isOutsideBounds, } = args;
77
+ const { series, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isOutsideBounds, isRangeSlider, } = args;
78
78
  const [_xMin, xRangeMax] = xScale.range();
79
79
  const xMax = xRangeMax;
80
80
  const result = [];
@@ -147,7 +147,7 @@ export const prepareAreaData = async (args) => {
147
147
  }, []);
148
148
  const labels = [];
149
149
  const htmlElements = [];
150
- if (s.dataLabels.enabled) {
150
+ if (s.dataLabels.enabled && !isRangeSlider) {
151
151
  const labelsData = await prepareDataLabels({ series: s, points, xMax, yAxisTop });
152
152
  labels.push(...labelsData.svgLabels);
153
153
  htmlElements.push(...labelsData.htmlLabels);
@@ -12,4 +12,5 @@ export declare const prepareBarXData: (args: {
12
12
  yScale: (ChartScale | undefined)[];
13
13
  boundsHeight: number;
14
14
  split: PreparedSplit;
15
+ isRangeSlider?: boolean;
15
16
  }) => Promise<PreparedBarXData[]>;
@@ -35,7 +35,7 @@ async function getLabelData(d) {
35
35
  // eslint-disable-next-line complexity
36
36
  export const prepareBarXData = async (args) => {
37
37
  var _a, _b, _c, _d;
38
- const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, } = args;
38
+ const { series, seriesOptions, xAxis, xScale, yAxis, yScale, boundsHeight: plotHeight, split, isRangeSlider, } = args;
39
39
  const stackGap = seriesOptions['bar-x'].stackGap;
40
40
  const categories = (_a = xAxis === null || xAxis === void 0 ? void 0 : xAxis.categories) !== null && _a !== void 0 ? _a : [];
41
41
  const sortingOptions = get(seriesOptions, 'bar-x.dataSorting');
@@ -99,7 +99,8 @@ export const prepareBarXData = async (args) => {
99
99
  const currentGroupWidth = rectWidth * stacks.length + rectGap * (stacks.length - 1);
100
100
  for (let groupItemIndex = 0; groupItemIndex < stacks.length; groupItemIndex++) {
101
101
  const yValues = stacks[groupItemIndex];
102
- let stackHeight = 0;
102
+ let positiveStackHeight = 0;
103
+ let negativeStackHeight = 0;
103
104
  const stackItems = [];
104
105
  const sortedData = sortKey
105
106
  ? sort(yValues, (a, b) => comparator(get(a, sortKey), get(b, sortKey)))
@@ -117,6 +118,7 @@ export const prepareBarXData = async (args) => {
117
118
  if (xAxis.type === 'category') {
118
119
  const xBandScale = xScale;
119
120
  const xBandScaleDomain = xBandScale.domain();
121
+ // eslint-disable-next-line max-depth
120
122
  if (xBandScaleDomain.indexOf(xValue) === -1) {
121
123
  continue;
122
124
  }
@@ -141,7 +143,9 @@ export const prepareBarXData = async (args) => {
141
143
  }
142
144
  const barData = {
143
145
  x,
144
- y: yAxisTop + (yDataValue > 0 ? y - stackHeight : base),
146
+ y: yDataValue > 0
147
+ ? yAxisTop + y - positiveStackHeight
148
+ : yAxisTop + base + negativeStackHeight,
145
149
  width: rectWidth,
146
150
  height: shapeHeight,
147
151
  opacity: get(yValue.data, 'opacity', null),
@@ -151,11 +155,16 @@ export const prepareBarXData = async (args) => {
151
155
  isLastStackItem,
152
156
  };
153
157
  stackItems.push(barData);
154
- stackHeight += height;
158
+ if (yDataValue > 0) {
159
+ positiveStackHeight += height;
160
+ }
161
+ else {
162
+ negativeStackHeight += height;
163
+ }
155
164
  }
156
165
  if (series.some((s) => s.stacking === 'percent')) {
157
166
  let acc = 0;
158
- const ratio = plotHeight / (stackHeight - stackItems.length);
167
+ const ratio = plotHeight / (positiveStackHeight - stackItems.length);
159
168
  stackItems.forEach((item) => {
160
169
  item.height = item.height * ratio;
161
170
  item.y = plotHeight - item.height - acc;
@@ -168,7 +177,7 @@ export const prepareBarXData = async (args) => {
168
177
  }
169
178
  for (let i = 0; i < result.length; i++) {
170
179
  const barData = result[i];
171
- if (barData.series.dataLabels.enabled) {
180
+ if (barData.series.dataLabels.enabled && !isRangeSlider) {
172
181
  const label = await getLabelData(barData);
173
182
  if (barData.series.dataLabels.html && label) {
174
183
  barData.htmlElements.push({
@@ -58,6 +58,7 @@ export const useShapes = (args) => {
58
58
  yScale,
59
59
  boundsHeight,
60
60
  split,
61
+ isRangeSlider,
61
62
  });
62
63
  shapes.push(React.createElement(BarXSeriesShapes, { key: SERIES_TYPE.BarX, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
63
64
  shapesData.push(...preparedData);
@@ -124,6 +125,7 @@ export const useShapes = (args) => {
124
125
  boundsHeight,
125
126
  split,
126
127
  isOutsideBounds,
128
+ isRangeSlider,
127
129
  });
128
130
  shapes.push(React.createElement(AreaSeriesShapes, { key: SERIES_TYPE.Area, dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
129
131
  shapesData.push(...preparedData);
@@ -34,7 +34,7 @@ export const LineSeriesShapes = (args) => {
34
34
  .attr('fill', 'none')
35
35
  .attr('stroke', (d) => d.color)
36
36
  .attr('stroke-width', (d) => d.lineWidth)
37
- .attr('stroke-linejoin', (d) => d.linecap)
37
+ .attr('stroke-linejoin', (d) => d.linejoin)
38
38
  .attr('stroke-linecap', (d) => d.linecap)
39
39
  .attr('stroke-dasharray', (d) => getLineDashArray(d.dashStyle, d.lineWidth))
40
40
  .attr('opacity', (d) => d.opacity)
@@ -44,7 +44,7 @@ export const prepareLineData = async (args) => {
44
44
  });
45
45
  const htmlElements = [];
46
46
  const labels = [];
47
- if (s.dataLabels.enabled) {
47
+ if (s.dataLabels.enabled && !isRangeSlider) {
48
48
  if (s.dataLabels.html) {
49
49
  const list = await Promise.all(points.reduce((result, p) => {
50
50
  if (p.y === null) {
@@ -108,6 +108,7 @@ export const prepareLineData = async (args) => {
108
108
  lineWidth: (_b = (isRangeSlider ? s.rangeSlider.lineWidth : undefined)) !== null && _b !== void 0 ? _b : s.lineWidth,
109
109
  dashStyle: s.dashStyle,
110
110
  linecap: s.linecap,
111
+ linejoin: s.linejoin,
111
112
  opacity: (_c = (isRangeSlider ? s.rangeSlider.opacity : undefined)) !== null && _c !== void 0 ? _c : s.opacity,
112
113
  };
113
114
  acc.push(result);
@@ -1,4 +1,4 @@
1
- import type { DashStyle, LineCap } from '../../../constants';
1
+ import type { DashStyle, LineCap, LineJoin } from '../../../constants';
2
2
  import type { HtmlItem, LabelData, LineSeriesData, LineSeriesLineBaseStyle } from '../../../types';
3
3
  import type { PreparedLineSeries } from '../../useSeries/types';
4
4
  export type PointData = {
@@ -30,4 +30,5 @@ export type PreparedLineData = {
30
30
  color: string;
31
31
  dashStyle: DashStyle;
32
32
  linecap: LineCap;
33
+ linejoin: LineJoin;
33
34
  } & Required<LineSeriesLineBaseStyle>;
@@ -1,4 +1,4 @@
1
- import type { DashStyle, LineCap, SERIES_TYPE } from '../../constants';
1
+ import type { DashStyle, LineCap, LineJoin, SERIES_TYPE } from '../../constants';
2
2
  import type { MeaningfulAny } from '../misc';
3
3
  import type { BaseSeries, BaseSeriesData, BaseSeriesLegend } from './base';
4
4
  import type { RectLegendSymbolOptions } from './legend';
@@ -53,6 +53,8 @@ export interface LineSeries<T = MeaningfulAny> extends BaseSeries, LineSeriesLin
53
53
  dashStyle?: DashStyle;
54
54
  /** Option for line cap style */
55
55
  linecap?: `${LineCap}`;
56
+ /** Defines the shape to be used at the corners of the line */
57
+ linejoin?: `${LineJoin}`;
56
58
  /** Individual series legend options. Has higher priority than legend options in widget data */
57
59
  legend?: BaseSeriesLegend & {
58
60
  symbol?: RectLegendSymbolOptions;
@@ -1,5 +1,5 @@
1
1
  import type React from 'react';
2
- import type { DashStyle, LineCap } from '../../constants';
2
+ import type { DashStyle, LineCap, LineJoin } from '../../constants';
3
3
  import type { MeaningfulAny } from '../misc';
4
4
  import type { AreaSeries, AreaSeriesData } from './area';
5
5
  import type { BarXSeries, BarXSeriesData } from './bar-x';
@@ -211,6 +211,11 @@ export interface ChartSeriesOptions {
211
211
  * @default 'round' when dashStyle is not 'solid', 'none' when dashStyle is not 'solid'
212
212
  * */
213
213
  linecap?: `${LineCap}`;
214
+ /** Defines the shape to be used at the corners of the line
215
+ *
216
+ * @default 'round' when dashStyle is not 'solid', 'unset' when dashStyle is not 'solid'
217
+ * */
218
+ linejoin?: `${LineJoin}`;
214
219
  };
215
220
  area?: {
216
221
  /** Pixel width of the graph line.
@@ -46,8 +46,8 @@ export declare function isSeriesWithCategoryValues(series: UnknownSeries): serie
46
46
  export declare const getDomainDataXBySeries: (series: UnknownSeries[]) => ({} | undefined)[];
47
47
  export declare function getDefaultMaxXAxisValue(series: UnknownSeries[]): 0 | undefined;
48
48
  export declare function getDefaultMinXAxisValue(series: UnknownSeries[]): number | undefined;
49
- export declare function getDefaultMinYAxisValue(series?: UnknownSeries[]): number | undefined;
50
49
  export declare const getDomainDataYBySeries: (series: UnknownSeries[]) => unknown[];
50
+ export declare function getDefaultMinYAxisValue(series?: UnknownSeries[]): number | undefined;
51
51
  export declare const getSeriesNames: (series: ChartSeries[]) => string[];
52
52
  export declare const getOnlyVisibleSeries: <T extends {
53
53
  visible: boolean;
@@ -46,7 +46,8 @@ function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y
46
46
  const acc = [];
47
47
  const stackedSeries = group(seriesList, getSeriesStackId);
48
48
  Array.from(stackedSeries).forEach(([_stackId, seriesStack]) => {
49
- const values = {};
49
+ const positiveValues = {};
50
+ const negativeValues = {};
50
51
  seriesStack.forEach((singleSeries) => {
51
52
  const data = new Map();
52
53
  singleSeries.data.forEach((point) => {
@@ -65,10 +66,15 @@ function getDomainDataForStackedSeries(seriesList, keyAttr = 'x', valueAttr = 'y
65
66
  data.set(key, value);
66
67
  });
67
68
  Array.from(data).forEach(([key, value]) => {
68
- values[key] = (values[key] || 0) + value;
69
+ if (value >= 0) {
70
+ positiveValues[key] = (positiveValues[key] || 0) + value;
71
+ }
72
+ if (value < 0) {
73
+ negativeValues[key] = (negativeValues[key] || 0) + value;
74
+ }
69
75
  });
70
76
  });
71
- acc.push(...Object.values(values));
77
+ acc.push(...Object.values(negativeValues), ...Object.values(positiveValues));
72
78
  });
73
79
  return acc;
74
80
  }
@@ -107,22 +113,6 @@ export function getDefaultMinXAxisValue(series) {
107
113
  }
108
114
  return undefined;
109
115
  }
110
- export function getDefaultMinYAxisValue(series) {
111
- if (series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type))) {
112
- if (series.some((s) => s.type === SERIES_TYPE.Waterfall)) {
113
- const seriesData = series.map((s) => s.data).flat();
114
- const minSubTotal = seriesData.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, seriesData) || 0), 0);
115
- return Math.min(0, minSubTotal);
116
- }
117
- return series.reduce((minValue, s) => {
118
- // https://github.com/gravity-ui/charts/issues/160
119
- // @ts-expect-error
120
- const minYValue = s.data.reduce((res, d) => Math.min(res, get(d, 'y', 0)), 0);
121
- return Math.min(minValue, minYValue);
122
- }, 0);
123
- }
124
- return undefined;
125
- }
126
116
  export const getDomainDataYBySeries = (series) => {
127
117
  const groupedSeries = group(series, (item) => item.type);
128
118
  const items = Array.from(groupedSeries).reduce((acc, [type, seriesList]) => {
@@ -151,6 +141,20 @@ export const getDomainDataYBySeries = (series) => {
151
141
  }, []);
152
142
  return Array.from(new Set(items));
153
143
  };
144
+ export function getDefaultMinYAxisValue(series) {
145
+ if (series === null || series === void 0 ? void 0 : series.some((s) => CHART_SERIES_WITH_VOLUME_ON_Y_AXIS.includes(s.type))) {
146
+ if (series.some((s) => s.type === SERIES_TYPE.Waterfall)) {
147
+ const seriesData = series.map((s) => s.data).flat();
148
+ const minSubTotal = seriesData.reduce((res, d) => Math.min(res, getWaterfallPointSubtotal(d, seriesData) || 0), 0);
149
+ return Math.min(0, minSubTotal);
150
+ }
151
+ const domainData = getDomainDataYBySeries(series);
152
+ return domainData.reduce((minValue, d) => {
153
+ return Math.min(minValue, d);
154
+ }, 0);
155
+ }
156
+ return undefined;
157
+ }
154
158
  // Uses to get all series names array (except `pie` charts)
155
159
  export const getSeriesNames = (series) => {
156
160
  return series.reduce((acc, s) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.31.0",
3
+ "version": "1.32.0",
4
4
  "description": "A flexible JavaScript library for data visualization and chart rendering using React",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",