@gravity-ui/charts 1.17.0 → 1.18.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 (93) hide show
  1. package/dist/cjs/components/AxisY/prepare-axis-data.d.ts +2 -1
  2. package/dist/cjs/components/AxisY/prepare-axis-data.js +7 -6
  3. package/dist/cjs/components/AxisY/utils.js +1 -10
  4. package/dist/cjs/components/ChartInner/index.js +10 -5
  5. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -1
  6. package/dist/cjs/components/ChartInner/useChartInnerProps.js +2 -0
  7. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  8. package/dist/cjs/components/Tooltip/ChartTooltipContent.js +2 -2
  9. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +2 -1
  10. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +3 -3
  11. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +4 -3
  12. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +6 -9
  13. package/dist/cjs/components/Tooltip/index.js +1 -1
  14. package/dist/cjs/hooks/useAxisScales/index.d.ts +3 -3
  15. package/dist/cjs/hooks/useAxisScales/index.js +40 -7
  16. package/dist/cjs/hooks/useChartOptions/index.d.ts +3 -1
  17. package/dist/cjs/hooks/useChartOptions/index.js +3 -3
  18. package/dist/cjs/hooks/useChartOptions/tooltip.d.ts +4 -1
  19. package/dist/cjs/hooks/useChartOptions/tooltip.js +18 -3
  20. package/dist/cjs/hooks/useChartOptions/x-axis.js +21 -9
  21. package/dist/cjs/hooks/useChartOptions/y-axis.js +20 -7
  22. package/dist/cjs/hooks/useCrosshair/index.d.ts +1 -1
  23. package/dist/cjs/hooks/useCrosshair/index.js +2 -1
  24. package/dist/cjs/hooks/useShapes/area/prepare-data.d.ts +1 -1
  25. package/dist/cjs/hooks/useShapes/area/prepare-data.js +3 -0
  26. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.d.ts +1 -1
  27. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +3 -0
  28. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.d.ts +1 -1
  29. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +8 -1
  30. package/dist/cjs/hooks/useShapes/index.d.ts +1 -1
  31. package/dist/cjs/hooks/useShapes/line/prepare-data.d.ts +1 -1
  32. package/dist/cjs/hooks/useShapes/line/prepare-data.js +3 -0
  33. package/dist/cjs/hooks/useShapes/scatter/prepare-data.d.ts +1 -1
  34. package/dist/cjs/hooks/useShapes/scatter/prepare-data.js +6 -0
  35. package/dist/cjs/hooks/useShapes/waterfall/prepare-data.d.ts +1 -1
  36. package/dist/cjs/hooks/useShapes/waterfall/prepare-data.js +6 -3
  37. package/dist/cjs/hooks/useZoom/index.d.ts +1 -1
  38. package/dist/cjs/hooks/useZoom/types.d.ts +1 -1
  39. package/dist/cjs/hooks/useZoom/utils.d.ts +1 -1
  40. package/dist/cjs/hooks/useZoom/utils.js +22 -10
  41. package/dist/cjs/types/chart/tooltip.d.ts +3 -0
  42. package/dist/cjs/utils/chart/array.d.ts +1 -0
  43. package/dist/cjs/utils/chart/array.js +9 -0
  44. package/dist/cjs/utils/chart/index.d.ts +1 -0
  45. package/dist/cjs/utils/chart/index.js +1 -0
  46. package/dist/cjs/utils/chart/zoom.js +14 -8
  47. package/dist/esm/components/AxisY/prepare-axis-data.d.ts +2 -1
  48. package/dist/esm/components/AxisY/prepare-axis-data.js +7 -6
  49. package/dist/esm/components/AxisY/utils.js +1 -10
  50. package/dist/esm/components/ChartInner/index.js +10 -5
  51. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -1
  52. package/dist/esm/components/ChartInner/useChartInnerProps.js +2 -0
  53. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  54. package/dist/esm/components/Tooltip/ChartTooltipContent.js +2 -2
  55. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +2 -1
  56. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +3 -3
  57. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +4 -3
  58. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +6 -9
  59. package/dist/esm/components/Tooltip/index.js +1 -1
  60. package/dist/esm/hooks/useAxisScales/index.d.ts +3 -3
  61. package/dist/esm/hooks/useAxisScales/index.js +40 -7
  62. package/dist/esm/hooks/useChartOptions/index.d.ts +3 -1
  63. package/dist/esm/hooks/useChartOptions/index.js +3 -3
  64. package/dist/esm/hooks/useChartOptions/tooltip.d.ts +4 -1
  65. package/dist/esm/hooks/useChartOptions/tooltip.js +18 -3
  66. package/dist/esm/hooks/useChartOptions/x-axis.js +21 -9
  67. package/dist/esm/hooks/useChartOptions/y-axis.js +20 -7
  68. package/dist/esm/hooks/useCrosshair/index.d.ts +1 -1
  69. package/dist/esm/hooks/useCrosshair/index.js +2 -1
  70. package/dist/esm/hooks/useShapes/area/prepare-data.d.ts +1 -1
  71. package/dist/esm/hooks/useShapes/area/prepare-data.js +3 -0
  72. package/dist/esm/hooks/useShapes/bar-x/prepare-data.d.ts +1 -1
  73. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +3 -0
  74. package/dist/esm/hooks/useShapes/bar-y/prepare-data.d.ts +1 -1
  75. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +8 -1
  76. package/dist/esm/hooks/useShapes/index.d.ts +1 -1
  77. package/dist/esm/hooks/useShapes/line/prepare-data.d.ts +1 -1
  78. package/dist/esm/hooks/useShapes/line/prepare-data.js +3 -0
  79. package/dist/esm/hooks/useShapes/scatter/prepare-data.d.ts +1 -1
  80. package/dist/esm/hooks/useShapes/scatter/prepare-data.js +6 -0
  81. package/dist/esm/hooks/useShapes/waterfall/prepare-data.d.ts +1 -1
  82. package/dist/esm/hooks/useShapes/waterfall/prepare-data.js +6 -3
  83. package/dist/esm/hooks/useZoom/index.d.ts +1 -1
  84. package/dist/esm/hooks/useZoom/types.d.ts +1 -1
  85. package/dist/esm/hooks/useZoom/utils.d.ts +1 -1
  86. package/dist/esm/hooks/useZoom/utils.js +22 -10
  87. package/dist/esm/types/chart/tooltip.d.ts +3 -0
  88. package/dist/esm/utils/chart/array.d.ts +1 -0
  89. package/dist/esm/utils/chart/array.js +9 -0
  90. package/dist/esm/utils/chart/index.d.ts +1 -0
  91. package/dist/esm/utils/chart/index.js +1 -0
  92. package/dist/esm/utils/chart/zoom.js +14 -8
  93. package/package.json +1 -1
@@ -17,21 +17,21 @@ type Args = {
17
17
  };
18
18
  type ReturnValue = {
19
19
  xScale?: ChartScale;
20
- yScale?: ChartScale[];
20
+ yScale?: (ChartScale | undefined)[];
21
21
  };
22
22
  export declare function createYScale(args: {
23
23
  axis: PreparedAxis;
24
24
  boundsHeight: number;
25
25
  series: (PreparedSeries | ChartSeries)[];
26
26
  seriesOptions: PreparedSeriesOptions;
27
- }): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
27
+ }): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never> | undefined;
28
28
  export declare function createXScale(args: {
29
29
  axis: PreparedAxis | ChartAxis;
30
30
  boundsWidth: number;
31
31
  series: (PreparedSeries | ChartSeries)[];
32
32
  seriesOptions: PreparedSeriesOptions;
33
33
  hasZoomX?: boolean;
34
- }): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never>;
34
+ }): ScaleBand<string> | ScaleLinear<number, number, never> | ScaleTime<number, number, never> | undefined;
35
35
  /**
36
36
  * Uses to create scales for axis related series
37
37
  */
@@ -6,8 +6,23 @@ import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, getAxisHeight, getDataCategoryValue
6
6
  import { getBarYLayoutForNumericScale, groupBarYDataByYValue } from '../utils';
7
7
  import { getBarXLayoutForNumericScale, groupBarXDataByXValue } from '../utils/bar-x';
8
8
  const X_AXIS_ZOOM_PADDING = 0.02;
9
- function isNumericalArrayData(data) {
10
- return data.every((d) => typeof d === 'number' || d === null);
9
+ function validateArrayData(data) {
10
+ let hasNumberAndNullValues;
11
+ let hasOnlyNullValues;
12
+ for (const d of data) {
13
+ const isNumber = typeof d === 'number';
14
+ const isNull = d === null;
15
+ hasNumberAndNullValues =
16
+ typeof hasNumberAndNullValues === 'undefined'
17
+ ? isNumber || isNull
18
+ : hasNumberAndNullValues && (isNumber || isNull);
19
+ hasOnlyNullValues =
20
+ typeof hasOnlyNullValues === 'undefined' ? isNull : hasOnlyNullValues && isNull;
21
+ if (!hasNumberAndNullValues) {
22
+ break;
23
+ }
24
+ }
25
+ return { hasNumberAndNullValues, hasOnlyNullValues };
11
26
  }
12
27
  function filterCategoriesByVisibleSeries(args) {
13
28
  const { axisDirection, categories, series } = args;
@@ -19,7 +34,8 @@ function filterCategoriesByVisibleSeries(args) {
19
34
  });
20
35
  }
21
36
  });
22
- return categories.filter((c) => visibleCategories.has(c));
37
+ const filteredCategories = categories.filter((c) => visibleCategories.has(c));
38
+ return filteredCategories.length > 0 ? filteredCategories : categories;
23
39
  }
24
40
  // axis is validated in `validation/index.ts`, so the value of `axis.type` is definitely valid.
25
41
  // eslint-disable-next-line consistent-return
@@ -56,6 +72,7 @@ function getYScaleRange(args) {
56
72
  }
57
73
  }
58
74
  }
75
+ // eslint-disable-next-line complexity
59
76
  export function createYScale(args) {
60
77
  const { axis, boundsHeight, series, seriesOptions } = args;
61
78
  const yMinProps = get(axis, 'min');
@@ -67,7 +84,11 @@ export function createYScale(args) {
67
84
  case 'linear':
68
85
  case 'logarithmic': {
69
86
  const domain = getDomainDataYBySeries(series);
70
- if (isNumericalArrayData(domain)) {
87
+ const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domain);
88
+ if (hasOnlyNullValues || domain.length === 0) {
89
+ return undefined;
90
+ }
91
+ if (hasNumberAndNullValues) {
71
92
  const [yMinDomain, yMaxDomain] = extent(domain);
72
93
  const yMin = typeof yMinProps === 'number' ? yMinProps : yMinDomain;
73
94
  let yMax;
@@ -103,7 +124,11 @@ export function createYScale(args) {
103
124
  }
104
125
  else {
105
126
  const domain = getDomainDataYBySeries(series);
106
- if (isNumericalArrayData(domain)) {
127
+ const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domain);
128
+ if (hasOnlyNullValues || domain.length === 0) {
129
+ return undefined;
130
+ }
131
+ if (hasNumberAndNullValues) {
107
132
  const [yMinTimestamp, yMaxTimestamp] = extent(domain);
108
133
  const yMin = typeof yMinProps === 'number' ? yMinProps : yMinTimestamp;
109
134
  const yMax = typeof yMaxProps === 'number' ? yMaxProps : yMaxTimestamp;
@@ -178,7 +203,11 @@ export function createXScale(args) {
178
203
  case 'linear':
179
204
  case 'logarithmic': {
180
205
  const domainData = getDomainDataXBySeries(series);
181
- if (isNumericalArrayData(domainData)) {
206
+ const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domainData);
207
+ if (hasOnlyNullValues || domainData.length === 0) {
208
+ return undefined;
209
+ }
210
+ if (hasNumberAndNullValues) {
182
211
  const [xMinDomain, xMaxDomain] = extent(domainData);
183
212
  let xMin;
184
213
  let xMax;
@@ -227,7 +256,11 @@ export function createXScale(args) {
227
256
  case 'datetime': {
228
257
  let domain = null;
229
258
  const domainData = get(axis, 'timestamps') || getDomainDataXBySeries(series);
230
- if (isNumericalArrayData(domainData)) {
259
+ const { hasNumberAndNullValues, hasOnlyNullValues } = validateArrayData(domainData);
260
+ if (hasOnlyNullValues || domainData.length === 0) {
261
+ return undefined;
262
+ }
263
+ if (hasNumberAndNullValues) {
231
264
  const [xMinTimestamp, xMaxTimestamp] = extent(domainData);
232
265
  const xMin = typeof xMinProps === 'number' ? xMinProps : xMinTimestamp;
233
266
  const xMax = typeof xMaxProps === 'number' ? xMaxProps : xMaxTimestamp;
@@ -1,4 +1,4 @@
1
- import type { ChartSeries, ChartTitle, ChartTooltip, ChartOptions as GeneralChartOptions } from '../../types';
1
+ import type { ChartSeries, ChartTitle, ChartTooltip, ChartXAxis, ChartYAxis, ChartOptions as GeneralChartOptions } from '../../types';
2
2
  import type { ChartOptions } from './types';
3
3
  type Args = {
4
4
  seriesData: ChartSeries[];
@@ -6,6 +6,8 @@ type Args = {
6
6
  colors?: string[];
7
7
  title?: ChartTitle;
8
8
  tooltip?: ChartTooltip;
9
+ yAxes?: ChartYAxis[];
10
+ xAxis?: ChartXAxis;
9
11
  };
10
12
  export declare const useChartOptions: (args: Args) => ChartOptions;
11
13
  export {};
@@ -4,10 +4,10 @@ import { getPreparedChart } from './chart';
4
4
  import { getPreparedTitle } from './title';
5
5
  import { getPreparedTooltip } from './tooltip';
6
6
  export const useChartOptions = (args) => {
7
- const { chart, colors, seriesData, title, tooltip } = args;
7
+ const { chart, colors, seriesData, title, tooltip, yAxes, xAxis } = args;
8
8
  const options = React.useMemo(() => {
9
9
  const preparedTitle = getPreparedTitle({ title });
10
- const preparedTooltip = getPreparedTooltip({ tooltip });
10
+ const preparedTooltip = getPreparedTooltip({ tooltip, seriesData, yAxes, xAxis });
11
11
  const preparedChart = getPreparedChart({
12
12
  chart,
13
13
  preparedTitle,
@@ -19,6 +19,6 @@ export const useChartOptions = (args) => {
19
19
  title: preparedTitle,
20
20
  tooltip: preparedTooltip,
21
21
  };
22
- }, [chart, colors, seriesData, title, tooltip]);
22
+ }, [chart, colors, seriesData, title, tooltip, xAxis, yAxes]);
23
23
  return options;
24
24
  };
@@ -1,5 +1,8 @@
1
- import type { ChartData } from '../../types';
1
+ import type { ChartData, ChartSeries, ChartXAxis, ChartYAxis } from '../../types';
2
2
  import type { PreparedTooltip } from './types';
3
3
  export declare const getPreparedTooltip: (args: {
4
4
  tooltip: ChartData["tooltip"];
5
+ seriesData: ChartSeries[];
6
+ yAxes?: ChartYAxis[];
7
+ xAxis?: ChartXAxis;
5
8
  }) => PreparedTooltip;
@@ -1,6 +1,21 @@
1
1
  import get from 'lodash/get';
2
+ import { getDefaultValueFormat } from '../../components/Tooltip/DefaultTooltipContent/utils';
3
+ import { getDomainDataXBySeries, getDomainDataYBySeries, getMinSpaceBetween } from '../../utils';
4
+ function getDefaultHeaderFormat({ seriesData, yAxes, xAxis, }) {
5
+ if (seriesData.every((item) => ['pie', 'treemap', 'waterfall', 'sankey', 'radar'].includes(item.type))) {
6
+ return undefined;
7
+ }
8
+ if (seriesData.some((item) => item.type === 'bar-y')) {
9
+ const domainData = getDomainDataYBySeries(seriesData);
10
+ const closestPointsRange = getMinSpaceBetween(domainData, (d) => d);
11
+ return getDefaultValueFormat({ axis: yAxes === null || yAxes === void 0 ? void 0 : yAxes[0], closestPointsRange });
12
+ }
13
+ const domainData = getDomainDataXBySeries(seriesData);
14
+ const closestPointsRange = getMinSpaceBetween(domainData, (d) => d);
15
+ return getDefaultValueFormat({ axis: xAxis, closestPointsRange });
16
+ }
2
17
  export const getPreparedTooltip = (args) => {
3
- var _a;
4
- const { tooltip } = args;
5
- return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0 });
18
+ var _a, _b;
19
+ const { tooltip, seriesData, yAxes, xAxis } = args;
20
+ return Object.assign(Object.assign({}, tooltip), { enabled: get(tooltip, 'enabled', true), throttle: (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.throttle) !== null && _a !== void 0 ? _a : 0, headerFormat: (_b = tooltip === null || tooltip === void 0 ? void 0 : tooltip.headerFormat) !== null && _b !== void 0 ? _b : getDefaultHeaderFormat({ seriesData, yAxes, xAxis }) });
6
21
  };
@@ -1,10 +1,15 @@
1
1
  import get from 'lodash/get';
2
2
  import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, axisCrosshairDefaults, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
3
- import { calculateCos, calculateNumericProperty, formatAxisTickLabel, getAxisItems, getClosestPointsRange, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, hasOverlappingLabels, wrapText, } from '../../utils';
3
+ import { calculateCos, calculateNumericProperty, formatAxisTickLabel, getAxisItems, getClosestPointsRange, getDefaultDateFormat, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, hasOverlappingLabels, wrapText, } from '../../utils';
4
4
  import { createXScale } from '../useAxisScales';
5
5
  import { getAxisCategories, prepareAxisPlotLabel } from './utils';
6
- async function getLabelSettings({ axis, seriesData, seriesOptions, width, autoRotation = true, }) {
6
+ async function setLabelSettings({ axis, seriesData, seriesOptions, width, autoRotation = true, }) {
7
7
  const scale = createXScale({ axis, series: seriesData, seriesOptions, boundsWidth: width });
8
+ if (!scale) {
9
+ axis.labels.height = 0;
10
+ axis.labels.rotation = 0;
11
+ return;
12
+ }
8
13
  const tickCount = getTicksCount({ axis, range: width });
9
14
  const ticks = getAxisItems({
10
15
  scale: scale,
@@ -12,6 +17,9 @@ async function getLabelSettings({ axis, seriesData, seriesOptions, width, autoRo
12
17
  maxCount: getMaxTickCount({ width, axis }),
13
18
  });
14
19
  const step = getClosestPointsRange(axis, ticks);
20
+ if (axis.type === 'datetime' && !axis.labels.dateFormat) {
21
+ axis.labels.dateFormat = getDefaultDateFormat(step);
22
+ }
15
23
  const labels = ticks.map((value) => {
16
24
  return formatAxisTickLabel({
17
25
  axis,
@@ -38,10 +46,11 @@ async function getLabelSettings({ axis, seriesData, seriesOptions, width, autoRo
38
46
  })).maxHeight
39
47
  : axis.labels.lineHeight;
40
48
  const maxHeight = rotation ? calculateCos(rotation) * axis.labels.maxWidth : labelsHeight;
41
- return { height: Math.min(maxHeight, labelsHeight), rotation };
49
+ axis.labels.height = Math.min(maxHeight, labelsHeight);
50
+ axis.labels.rotation = rotation;
42
51
  }
43
52
  export const getPreparedXAxis = async ({ xAxis, seriesData, seriesOptions, width, }) => {
44
- var _a, _b, _c;
53
+ var _a, _b, _c, _d, _e;
45
54
  const titleText = get(xAxis, 'title.text', '');
46
55
  const titleStyle = Object.assign(Object.assign({}, xAxisTitleDefaults.style), get(xAxis, 'title.style'));
47
56
  const titleMaxRowsCount = get(xAxis, 'title.maxRowCount', xAxisTitleDefaults.maxRowCount);
@@ -96,7 +105,12 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, seriesOptions, width
96
105
  enabled: get(xAxis, 'grid.enabled', true),
97
106
  },
98
107
  ticks: {
99
- pixelInterval: get(xAxis, 'ticks.pixelInterval'),
108
+ pixelInterval: ((_c = xAxis === null || xAxis === void 0 ? void 0 : xAxis.ticks) === null || _c === void 0 ? void 0 : _c.interval)
109
+ ? calculateNumericProperty({
110
+ base: width,
111
+ value: xAxis.ticks.interval,
112
+ })
113
+ : (_d = xAxis === null || xAxis === void 0 ? void 0 : xAxis.ticks) === null || _d === void 0 ? void 0 : _d.pixelInterval,
100
114
  },
101
115
  position: 'bottom',
102
116
  plotIndex: 0,
@@ -129,14 +143,12 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, seriesOptions, width
129
143
  visible: get(xAxis, 'visible', true),
130
144
  order: xAxis === null || xAxis === void 0 ? void 0 : xAxis.order,
131
145
  };
132
- const { height, rotation } = await getLabelSettings({
146
+ await setLabelSettings({
133
147
  axis: preparedXAxis,
134
148
  seriesData,
135
149
  seriesOptions,
136
150
  width,
137
- autoRotation: (_c = xAxis === null || xAxis === void 0 ? void 0 : xAxis.labels) === null || _c === void 0 ? void 0 : _c.autoRotation,
151
+ autoRotation: (_e = xAxis === null || xAxis === void 0 ? void 0 : xAxis.labels) === null || _e === void 0 ? void 0 : _e.autoRotation,
138
152
  });
139
- preparedXAxis.labels.height = height;
140
- preparedXAxis.labels.rotation = rotation;
141
153
  return preparedXAxis;
142
154
  };
@@ -1,7 +1,7 @@
1
1
  import get from 'lodash/get';
2
2
  import { getTickValues } from '../../components/AxisY/utils';
3
3
  import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, axisCrosshairDefaults, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
4
- import { calculateNumericProperty, getDefaultMinYAxisValue, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelFormatter, getLabelsSize, getTextSizeFn, isAxisRelatedSeries, wrapText, } from '../../utils';
4
+ import { calculateNumericProperty, formatAxisTickLabel, getClosestPointsRange, getDefaultDateFormat, getDefaultMinYAxisValue, getHorizontalHtmlTextHeight, getHorizontalSvgTextHeight, getLabelsSize, getScaleTicks, getTextSizeFn, isAxisRelatedSeries, wrapText, } from '../../utils';
5
5
  import { createYScale } from '../useAxisScales';
6
6
  import { getAxisCategories, prepareAxisPlotLabel } from './utils';
7
7
  const getAxisLabelMaxWidth = async (args) => {
@@ -15,11 +15,22 @@ const getAxisLabelMaxWidth = async (args) => {
15
15
  series: seriesData,
16
16
  seriesOptions,
17
17
  });
18
+ if (!scale) {
19
+ return { height: 0, width: 0 };
20
+ }
18
21
  const getTextSize = getTextSizeFn({ style: axis.labels.style });
19
22
  const labelLineHeight = (await getTextSize('Tmp')).height;
20
23
  const tickValues = getTickValues({ axis, scale, labelLineHeight });
21
- const labelFormatter = getLabelFormatter({ axis, scale });
22
- const labels = tickValues.map((tick) => labelFormatter(tick.value));
24
+ const ticks = getScaleTicks(scale);
25
+ const tickStep = getClosestPointsRange(axis, ticks);
26
+ if (axis.type === 'datetime' && !axis.labels.dateFormat) {
27
+ axis.labels.dateFormat = getDefaultDateFormat(tickStep);
28
+ }
29
+ const labels = tickValues.map((tick) => formatAxisTickLabel({
30
+ axis,
31
+ value: tick.value,
32
+ step: tickStep,
33
+ }));
23
34
  const size = await getLabelsSize({
24
35
  labels,
25
36
  style: axis.labels.style,
@@ -100,10 +111,12 @@ export const getPreparedYAxis = ({ height, boundsHeight, width, seriesData, seri
100
111
  (!firstPlotAxis && !((_d = axisByPlot[plotIndex][0].visible) !== null && _d !== void 0 ? _d : true))),
101
112
  },
102
113
  ticks: {
103
- pixelInterval: (_f = (_e = axisItem.ticks) === null || _e === void 0 ? void 0 : _e.pixelInterval) !== null && _f !== void 0 ? _f : calculateNumericProperty({
104
- base: height,
105
- value: (_g = axisItem.ticks) === null || _g === void 0 ? void 0 : _g.interval,
106
- }),
114
+ pixelInterval: ((_e = axisItem.ticks) === null || _e === void 0 ? void 0 : _e.interval)
115
+ ? calculateNumericProperty({
116
+ base: height,
117
+ value: (_f = axisItem.ticks) === null || _f === void 0 ? void 0 : _f.interval,
118
+ })
119
+ : (_g = axisItem.ticks) === null || _g === void 0 ? void 0 : _g.pixelInterval,
107
120
  },
108
121
  position: get(axisItem, 'position', defaultAxisPosition),
109
122
  plotIndex: get(axisItem, 'plotIndex', 0),
@@ -6,7 +6,7 @@ type Props = {
6
6
  width: number;
7
7
  height: number;
8
8
  xScale?: ChartScale;
9
- yScale?: ChartScale[];
9
+ yScale?: (ChartScale | undefined)[];
10
10
  split: PreparedSplit;
11
11
  plotElement: SVGGElement | null;
12
12
  dispatcher: Dispatch<object>;
@@ -63,7 +63,8 @@ export const useCrosshair = (props) => {
63
63
  }
64
64
  yAxes.forEach((yAxis, index, currentArr) => {
65
65
  const yAxisScale = yScale[index];
66
- if (index !== 0 && !yAxis.crosshair.snap && !currentArr[0].crosshair.snap) {
66
+ if (!yAxisScale ||
67
+ (index !== 0 && !yAxis.crosshair.snap && !currentArr[0].crosshair.snap)) {
67
68
  return;
68
69
  }
69
70
  if (yAxis.crosshair.enabled && (hovered === null || hovered === void 0 ? void 0 : hovered.length)) {
@@ -7,7 +7,7 @@ export declare const prepareAreaData: (args: {
7
7
  xAxis: PreparedAxis;
8
8
  xScale: ChartScale;
9
9
  yAxis: PreparedAxis[];
10
- yScale: ChartScale[];
10
+ yScale: (ChartScale | undefined)[];
11
11
  boundsHeight: number;
12
12
  isOutsideBounds: (x: number, y: number) => boolean;
13
13
  }) => Promise<PreparedAreaData[]>;
@@ -71,6 +71,9 @@ export const prepareAreaData = async (args) => {
71
71
  const yAxisIndex = s.yAxis;
72
72
  const seriesYAxis = yAxis[yAxisIndex];
73
73
  const seriesYScale = yScale[yAxisIndex];
74
+ if (!seriesYScale) {
75
+ continue;
76
+ }
74
77
  const yMin = getYValue({
75
78
  point: { y: 0 },
76
79
  points: s.data,
@@ -8,6 +8,6 @@ export declare const prepareBarXData: (args: {
8
8
  xAxis: PreparedAxis;
9
9
  xScale: ChartScale;
10
10
  yAxis: PreparedAxis[];
11
- yScale: ChartScale[];
11
+ yScale: (ChartScale | undefined)[];
12
12
  boundsHeight: number;
13
13
  }) => Promise<PreparedBarXData[]>;
@@ -112,6 +112,9 @@ export const prepareBarXData = async (args) => {
112
112
  const yValue = sortedData[yValueIndex];
113
113
  const yAxisIndex = yValue.series.yAxis;
114
114
  const seriesYScale = yScale[yAxisIndex];
115
+ if (!seriesYScale) {
116
+ continue;
117
+ }
115
118
  let xCenter;
116
119
  if (xAxis.type === 'category') {
117
120
  const xBandScale = xScale;
@@ -8,5 +8,5 @@ export declare const prepareBarYData: (args: {
8
8
  xAxis: PreparedAxis;
9
9
  xScale: ChartScale;
10
10
  yAxis: PreparedAxis[];
11
- yScale: ChartScale[];
11
+ yScale: (ChartScale | undefined)[];
12
12
  }) => Promise<BarYShapesArgs>;
@@ -10,6 +10,13 @@ export const prepareBarYData = async (args) => {
10
10
  const stackGap = seriesOptions['bar-y'].stackGap;
11
11
  const xLinearScale = xScale;
12
12
  const yLinearScale = yScale;
13
+ if (!yLinearScale) {
14
+ return {
15
+ shapes: [],
16
+ labels: [],
17
+ htmlElements: [],
18
+ };
19
+ }
13
20
  const yScaleRange = yLinearScale.range();
14
21
  const plotHeight = Math.abs(yScaleRange[0] - yScaleRange[1]);
15
22
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
@@ -29,7 +36,7 @@ export const prepareBarYData = async (args) => {
29
36
  })();
30
37
  const groupedData = groupBarYDataByYValue(series, yAxis);
31
38
  const { bandSize, barGap, barSize } = yAxis[0].type === 'category'
32
- ? getBarYLayoutForCategoryScale({ groupedData, seriesOptions, yScale })
39
+ ? getBarYLayoutForCategoryScale({ groupedData, seriesOptions, yScale: yLinearScale })
33
40
  : getBarYLayoutForNumericScale({
34
41
  groupedData,
35
42
  seriesOptions,
@@ -25,7 +25,7 @@ type Args = {
25
25
  xAxis: PreparedAxis | null;
26
26
  yAxis: PreparedAxis[];
27
27
  xScale?: ChartScale;
28
- yScale?: ChartScale[];
28
+ yScale?: (ChartScale | undefined)[];
29
29
  split: PreparedSplit;
30
30
  htmlLayout: HTMLElement | null;
31
31
  clipPathId: string;
@@ -8,7 +8,7 @@ export declare const prepareLineData: (args: {
8
8
  xAxis: PreparedAxis;
9
9
  xScale: ChartScale;
10
10
  yAxis: PreparedAxis[];
11
- yScale: ChartScale[];
11
+ yScale: (ChartScale | undefined)[];
12
12
  split: PreparedSplit;
13
13
  isOutsideBounds: (x: number, y: number) => boolean;
14
14
  }) => Promise<PreparedLineData[]>;
@@ -50,6 +50,9 @@ export const prepareLineData = async (args) => {
50
50
  const seriesYAxis = yAxis[yAxisIndex];
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
+ if (!seriesYScale) {
54
+ continue;
55
+ }
53
56
  const points = s.data.map((d) => ({
54
57
  x: getXValue({ point: d, points: s.data, xAxis, xScale }),
55
58
  y: yAxisTop +
@@ -7,6 +7,6 @@ export declare const prepareScatterData: (args: {
7
7
  xAxis: PreparedAxis;
8
8
  xScale: ChartScale;
9
9
  yAxis: PreparedAxis[];
10
- yScale: ChartScale[];
10
+ yScale: (ChartScale | undefined)[];
11
11
  isOutsideBounds: (x: number, y: number) => boolean;
12
12
  }) => PreparedScatterData[];
@@ -9,6 +9,9 @@ export const prepareScatterData = (args) => {
9
9
  const yAxisIndex = get(s, 'yAxis', 0);
10
10
  const seriesYAxis = yAxis[yAxisIndex];
11
11
  const seriesYScale = yScale[yAxisIndex];
12
+ if (!seriesYScale) {
13
+ return acc;
14
+ }
12
15
  const filteredData = xAxis.type === 'category' || seriesYAxis.type === 'category'
13
16
  ? s.data
14
17
  : getFilteredLinearScatterData(s.data);
@@ -16,6 +19,9 @@ export const prepareScatterData = (args) => {
16
19
  var _a;
17
20
  const x = getXValue({ point: d, xAxis, xScale });
18
21
  const y = getYValue({ point: d, yAxis: seriesYAxis, yScale: seriesYScale });
22
+ if (typeof x === 'undefined' || typeof y === 'undefined') {
23
+ return;
24
+ }
19
25
  acc.push({
20
26
  point: {
21
27
  data: d,
@@ -8,5 +8,5 @@ export declare const prepareWaterfallData: (args: {
8
8
  xAxis: PreparedAxis;
9
9
  xScale: ChartScale;
10
10
  yAxis: PreparedAxis[];
11
- yScale: ChartScale[];
11
+ yScale: (ChartScale | undefined)[];
12
12
  }) => Promise<PreparedWaterfallData[]>;
@@ -55,6 +55,9 @@ function getBandWidth(args) {
55
55
  export const prepareWaterfallData = async (args) => {
56
56
  const { series, seriesOptions, xAxis, xScale, yAxis: [yAxis], yScale: [yScale], } = args;
57
57
  const yLinearScale = yScale;
58
+ if (!yLinearScale) {
59
+ return [];
60
+ }
58
61
  const plotHeight = yLinearScale(yLinearScale.domain()[0]);
59
62
  const barMaxWidth = get(seriesOptions, 'waterfall.barMaxWidth');
60
63
  const barPadding = get(seriesOptions, 'waterfall.barPadding');
@@ -72,7 +75,7 @@ export const prepareWaterfallData = async (args) => {
72
75
  const rectWidth = Math.max(MIN_BAR_WIDTH, Math.min(bandWidth - rectGap, barMaxWidth));
73
76
  const yZero = getYValue({
74
77
  point: { y: 0 },
75
- yScale,
78
+ yScale: yLinearScale,
76
79
  yAxis,
77
80
  });
78
81
  let totalValue = 0;
@@ -92,7 +95,7 @@ export const prepareWaterfallData = async (args) => {
92
95
  const height = yZero -
93
96
  getYValue({
94
97
  point: { y: Math.abs(yValue) },
95
- yScale,
98
+ yScale: yLinearScale,
96
99
  yAxis,
97
100
  });
98
101
  let y;
@@ -101,7 +104,7 @@ export const prepareWaterfallData = async (args) => {
101
104
  point: {
102
105
  y: yValue > 0 ? yValue : 0,
103
106
  },
104
- yScale,
107
+ yScale: yLinearScale,
105
108
  yAxis,
106
109
  });
107
110
  }
@@ -12,7 +12,7 @@ interface UseZoomProps {
12
12
  xAxis: PreparedAxis | null;
13
13
  xScale?: ChartScale;
14
14
  yAxis: PreparedAxis[];
15
- yScale?: ChartScale[];
15
+ yScale?: (ChartScale | undefined)[];
16
16
  }
17
17
  export declare function useZoom(props: UseZoomProps): void;
18
18
  export {};
@@ -15,5 +15,5 @@ export interface ZoomState {
15
15
  * or the category index from the categories array specified in the axis settings (if the axis type is `category`).
16
16
  * The second element is the corresponding maximum value.
17
17
  */
18
- y: [number, number][];
18
+ y: ([number, number] | undefined)[];
19
19
  }
@@ -7,6 +7,6 @@ export declare function selectionToZoomBounds(args: {
7
7
  xAxis: PreparedAxis;
8
8
  xScale: ChartScale;
9
9
  yAxes: PreparedAxis[];
10
- yScales: ChartScale[];
10
+ yScales: (ChartScale | undefined)[];
11
11
  zoomType: PreparedZoom['type'];
12
12
  }): Partial<ZoomState>;
@@ -13,11 +13,17 @@ export function selectionToZoomBounds(args) {
13
13
  if (!Array.isArray(zoomState.y)) {
14
14
  zoomState.y = [];
15
15
  }
16
- zoomState.y.push(selectionYToZoomBounds({
17
- yAxis,
18
- yScale: yScales[index],
19
- selection: [y1, y0],
20
- }));
16
+ const yScale = yScales[index];
17
+ if (yScale) {
18
+ zoomState.y.push(selectionYToZoomBounds({
19
+ yAxis,
20
+ yScale,
21
+ selection: [y1, y0],
22
+ }));
23
+ }
24
+ else {
25
+ zoomState.y.push(undefined);
26
+ }
21
27
  });
22
28
  break;
23
29
  }
@@ -29,11 +35,17 @@ export function selectionToZoomBounds(args) {
29
35
  if (!Array.isArray(zoomState.y)) {
30
36
  zoomState.y = [];
31
37
  }
32
- zoomState.y.push(selectionYToZoomBounds({
33
- yAxis,
34
- yScale: yScales[index],
35
- selection: [y0, y1],
36
- }));
38
+ const yScale = yScales[index];
39
+ if (yScale) {
40
+ zoomState.y.push(selectionYToZoomBounds({
41
+ yAxis,
42
+ yScale,
43
+ selection: [y0, y1],
44
+ }));
45
+ }
46
+ else {
47
+ zoomState.y.push(undefined);
48
+ }
37
49
  });
38
50
  break;
39
51
  }
@@ -130,4 +130,7 @@ export interface ChartTooltip<T = MeaningfulAny> {
130
130
  /** Formatting settings for totals tooltip value. */
131
131
  valueFormat?: ValueFormat;
132
132
  };
133
+ /** Can be used for the UI automated test.
134
+ * It is assigned as a data-qa attribute to an element. */
135
+ qa?: string;
133
136
  }
@@ -0,0 +1 @@
1
+ export declare function getMinSpaceBetween<T>(arr: T[], iterator: (item: T) => number): number;
@@ -0,0 +1,9 @@
1
+ export function getMinSpaceBetween(arr, iterator) {
2
+ return arr.reduce((acc, item, index) => {
3
+ const prev = arr[index - 1];
4
+ if (prev) {
5
+ return Math.min(acc, Math.abs(iterator(prev) - iterator(item)));
6
+ }
7
+ return acc;
8
+ }, Infinity);
9
+ }
@@ -1,6 +1,7 @@
1
1
  import type { BaseTextStyle, ChartSeries, ChartSeriesData } from '../../types';
2
2
  import type { AxisDirection } from './types';
3
3
  export * from './axis';
4
+ export * from './array';
4
5
  export * from './color';
5
6
  export * from './format';
6
7
  export * from './labels';
@@ -6,6 +6,7 @@ import { DEFAULT_AXIS_LABEL_FONT_SIZE } from '../../constants';
6
6
  import { getSeriesStackId } from '../../hooks/useSeries/utils';
7
7
  import { getWaterfallPointSubtotal } from './series/waterfall';
8
8
  export * from './axis';
9
+ export * from './array';
9
10
  export * from './color';
10
11
  export * from './format';
11
12
  export * from './labels';