@gravity-ui/charts 1.28.0 → 1.28.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.
@@ -244,11 +244,15 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
244
244
  const labelSize = plotBand.label.text
245
245
  ? await getPlotLabelSize(plotBand.label.text)
246
246
  : null;
247
+ const plotBandWidth = Math.min(endPos, axisWidth);
248
+ if (plotBandWidth < 0) {
249
+ continue;
250
+ }
247
251
  plotBands.push({
248
252
  layerPlacement: plotBand.layerPlacement,
249
253
  x: Math.max(0, startPos),
250
254
  y: 0,
251
- width: Math.min(endPos, axisWidth),
255
+ width: plotBandWidth,
252
256
  height: axisHeight,
253
257
  color: plotBand.color,
254
258
  opacity: plotBand.opacity,
@@ -268,6 +272,9 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
268
272
  const plotLine = axis.plotLines[i];
269
273
  const axisScale = scale;
270
274
  const plotLineValue = Number(axisScale(plotLine.value));
275
+ if (plotLineValue < 0 || plotLineValue > boundsWidth) {
276
+ continue;
277
+ }
271
278
  const points = [
272
279
  [plotLineValue, 0],
273
280
  [plotLineValue, axisHeight],
@@ -211,12 +211,16 @@ export async function prepareYAxisData({ axis, split, scale, top: topOffset, wid
211
211
  const startPos = halfBandwidth + Math.min(from, to);
212
212
  const endPos = Math.min(Math.abs(to - from), axisHeight - Math.min(from, to));
213
213
  const top = Math.max(0, startPos);
214
+ const plotBandHeight = Math.min(endPos, axisHeight);
215
+ if (plotBandHeight < 0) {
216
+ return;
217
+ }
214
218
  plotBands.push({
215
219
  layerPlacement: plotBand.layerPlacement,
216
220
  x: 0,
217
221
  y: axisPlotTopPosition + top,
218
222
  width,
219
- height: Math.min(endPos, axisHeight),
223
+ height: plotBandHeight,
220
224
  color: plotBand.color,
221
225
  opacity: plotBand.opacity,
222
226
  label: plotBand.label.text
@@ -234,6 +238,9 @@ export async function prepareYAxisData({ axis, split, scale, top: topOffset, wid
234
238
  const plotLine = axis.plotLines[i];
235
239
  const axisScale = scale;
236
240
  const plotLineValue = Number(axisScale(plotLine.value));
241
+ if (plotLineValue < 0 || plotLineValue > axisHeight) {
242
+ continue;
243
+ }
237
244
  const points = [
238
245
  [0, plotLineValue],
239
246
  [width, plotLineValue],
@@ -275,6 +275,9 @@ export function createXScale(args) {
275
275
  if (typeof xMinPropsOrState === 'number' && !isPointDomain) {
276
276
  xMin = xMinPropsOrState;
277
277
  }
278
+ else if (xType === 'logarithmic') {
279
+ xMin = xMinDomain;
280
+ }
278
281
  else {
279
282
  const xMinDefault = getDefaultMinXAxisValue(series);
280
283
  xMin = xMinDefault !== null && xMinDefault !== void 0 ? xMinDefault : xMinDomain;
@@ -5,7 +5,7 @@ import { getFormattedValue } from '../../../utils/chart/format';
5
5
  import { getBarYLayout, groupBarYDataByYValue } from '../../utils';
6
6
  export async function prepareBarYData(args) {
7
7
  var _a;
8
- const { boundsHeight, boundsWidth, series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
8
+ const { boundsHeight, boundsWidth, series, seriesOptions, xAxis, yAxis, xScale, yScale: [yScale], } = args;
9
9
  const stackGap = seriesOptions['bar-y'].stackGap;
10
10
  const xLinearScale = xScale;
11
11
  const yLinearScale = yScale;
@@ -43,7 +43,8 @@ export async function prepareBarYData(args) {
43
43
  const stacks = Object.values(val);
44
44
  const currentBarHeight = barSize * stacks.length + barGap * (stacks.length - 1);
45
45
  stacks.forEach((measureValues, groupItemIndex) => {
46
- const base = xLinearScale(0) - measureValues[0].series.borderWidth;
46
+ const baseValue = xAxis.type === 'logarithmic' ? 0 : xLinearScale(0);
47
+ const base = baseValue - measureValues[0].series.borderWidth;
47
48
  let stackSum = base;
48
49
  const stackItems = [];
49
50
  const sortedData = sortKey
@@ -19,7 +19,8 @@
19
19
  "label_invalid-axis-type": "It seems you are trying to use inappropriate type for \"{{key}}\" axis. Available types: [{{values}}].",
20
20
  "label_invalid-axis-labels-html-type": "It seems you are trying to use inappropriate type for \"labels.html\" property. Only boolean is allowed.",
21
21
  "label_invalid-axis-labels-html-not-supported-axis-type": "It seems you are trying to use \"labels.html\" property for an axis with an unsupported type. This property is supported only for \"category\" axis.",
22
- "label_duplicate-axis-categories": "It seems you have duplicate value \"{{duplicate}}\" found in {{key}}[{{axisIndex}}]."
22
+ "label_duplicate-axis-categories": "It seems you have duplicate value \"{{duplicate}}\" found in {{key}}[{{axisIndex}}].",
23
+ "label_invalid-axis-categories": "It seems you are trying to use inappropriate value for \"categories\", or defined it incorrectly. Categories must be a non-empty array for an axis with \"category\" type."
23
24
  },
24
25
  "tooltip": {
25
26
  "label_totals_sum": "Sum",
@@ -19,7 +19,8 @@
19
19
  "label_invalid-axis-type": "Похоже, что вы пытаетесь использовать некорректный тип для оси \"{{key}}\". Доступные типы: [{{values}}].",
20
20
  "label_invalid-axis-labels-html-type": "Похоже, что вы пытаетесь использовать некорректный тип для свойства \"labels.html\". Допускается только использование булевых значений.",
21
21
  "label_invalid-axis-labels-html-not-supported-axis-type": "Похоже, что вы пытаетесь использовать свойство \"labels.html\" для оси с неподдерживаемым типом. Это свойство поддерживается только для оси типа \"category\".",
22
- "label_duplicate-axis-categories": "Похоже, что у вас есть дублирующееся значение категории \"{{duplicate}}\" в оси {{key}}[{{axisIndex}}]."
22
+ "label_duplicate-axis-categories": "Похоже, что у вас есть дублирующееся значение категории \"{{duplicate}}\" в оси {{key}}[{{axisIndex}}].",
23
+ "label_invalid-axis-categories": "Похоже, что вы пытаетесь использовать недопустимое значение для \"categories\", или указали его неверно. Категории для оси типа \"category\" должны быть непустым массивом."
23
24
  },
24
25
  "tooltip": {
25
26
  "label_totals_sum": "Сумма",
@@ -215,18 +215,18 @@ export interface AxisPlotBand extends AxisPlot {
215
215
  * Can be a number, a string (e.g., a category), or a timestamp if representing a date.
216
216
  * When representing a date, the value **must be a timestamp** (number of milliseconds since Unix epoch).
217
217
  *
218
- * If the value is `-Infinity`, it will be treated as the start of the axis.
218
+ * If the value is `-Infinity` or `null`, it will be treated as the start of the axis.
219
219
  */
220
- from: number | string;
220
+ from: number | string | null;
221
221
  /**
222
222
  * The end position of the plot band in axis units.
223
223
  *
224
224
  * Can be a number, a string (e.g., a category), or a timestamp if representing a date.
225
225
  * When representing a date, the value **must be a timestamp** (number of milliseconds since Unix epoch).
226
226
  *
227
- * If the value is `Infinity`, it will be treated as the end of the axis.
227
+ * If the value is `Infinity` or `null`, it will be treated as the end of the axis.
228
228
  */
229
- to: number | string;
229
+ to: number | string | null;
230
230
  }
231
231
  export interface AxisCrosshair extends Omit<AxisPlotLine, 'value' | 'label'> {
232
232
  /** Whether the crosshair should snap to the point or follow the pointer independent of points.
@@ -68,8 +68,8 @@ export function getBandsPosition(args) {
68
68
  var _a, _b, _c;
69
69
  const { band, axisScale } = args;
70
70
  const range = axisScale.range();
71
- const scalePosFrom = band.from === -Infinity ? range[0] : axisScale(band.from);
72
- const scalePosTo = band.to === Infinity ? range[1] : axisScale(band.to);
71
+ const scalePosFrom = band.from === -Infinity || band.from === null ? range[0] : axisScale(band.from);
72
+ const scalePosTo = band.to === Infinity || band.to === null ? range[1] : axisScale(band.to);
73
73
  const isX = args.axis === 'x';
74
74
  if (scalePosTo !== undefined && scalePosFrom !== undefined) {
75
75
  return {
@@ -2,7 +2,15 @@ import { AXIS_TYPE } from '../constants';
2
2
  import { i18n } from '../i18n';
3
3
  import { CHART_ERROR_CODE, ChartError } from '../libs';
4
4
  const AVAILABLE_AXIS_TYPES = Object.values(AXIS_TYPE);
5
- function validateDuplicateCategories({ categories, key, axisIndex, }) {
5
+ function validateCategories(axis) {
6
+ if (!axis.categories || !Array.isArray(axis.categories) || axis.categories.length === 0) {
7
+ throw new ChartError({
8
+ code: CHART_ERROR_CODE.INVALID_DATA,
9
+ message: i18n('error', 'label_invalid-axis-categories'),
10
+ });
11
+ }
12
+ }
13
+ function validateDuplicateCategories({ axisIndex, key, categories = [], }) {
6
14
  const seen = new Set();
7
15
  categories.forEach((category) => {
8
16
  if (seen.has(category)) {
@@ -54,7 +62,8 @@ export function validateAxes(args) {
54
62
  if (xAxis) {
55
63
  validateAxisType({ axis: xAxis, key: 'x' });
56
64
  validateLabelsHtmlOptions({ axis: xAxis });
57
- if ((xAxis === null || xAxis === void 0 ? void 0 : xAxis.type) === 'category' && xAxis.categories) {
65
+ if ((xAxis === null || xAxis === void 0 ? void 0 : xAxis.type) === 'category') {
66
+ validateCategories(xAxis);
58
67
  validateDuplicateCategories({
59
68
  categories: xAxis.categories,
60
69
  key: 'x',
@@ -64,7 +73,8 @@ export function validateAxes(args) {
64
73
  }
65
74
  yAxis.forEach((axis, axisIndex) => {
66
75
  validateAxisType({ axis, key: 'y' });
67
- if (axis.type === 'category' && axis.categories) {
76
+ if (axis.type === 'category') {
77
+ validateCategories(axis);
68
78
  validateDuplicateCategories({
69
79
  categories: axis.categories,
70
80
  key: 'y',
@@ -244,11 +244,15 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
244
244
  const labelSize = plotBand.label.text
245
245
  ? await getPlotLabelSize(plotBand.label.text)
246
246
  : null;
247
+ const plotBandWidth = Math.min(endPos, axisWidth);
248
+ if (plotBandWidth < 0) {
249
+ continue;
250
+ }
247
251
  plotBands.push({
248
252
  layerPlacement: plotBand.layerPlacement,
249
253
  x: Math.max(0, startPos),
250
254
  y: 0,
251
- width: Math.min(endPos, axisWidth),
255
+ width: plotBandWidth,
252
256
  height: axisHeight,
253
257
  color: plotBand.color,
254
258
  opacity: plotBand.opacity,
@@ -268,6 +272,9 @@ export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, bounds
268
272
  const plotLine = axis.plotLines[i];
269
273
  const axisScale = scale;
270
274
  const plotLineValue = Number(axisScale(plotLine.value));
275
+ if (plotLineValue < 0 || plotLineValue > boundsWidth) {
276
+ continue;
277
+ }
271
278
  const points = [
272
279
  [plotLineValue, 0],
273
280
  [plotLineValue, axisHeight],
@@ -211,12 +211,16 @@ export async function prepareYAxisData({ axis, split, scale, top: topOffset, wid
211
211
  const startPos = halfBandwidth + Math.min(from, to);
212
212
  const endPos = Math.min(Math.abs(to - from), axisHeight - Math.min(from, to));
213
213
  const top = Math.max(0, startPos);
214
+ const plotBandHeight = Math.min(endPos, axisHeight);
215
+ if (plotBandHeight < 0) {
216
+ return;
217
+ }
214
218
  plotBands.push({
215
219
  layerPlacement: plotBand.layerPlacement,
216
220
  x: 0,
217
221
  y: axisPlotTopPosition + top,
218
222
  width,
219
- height: Math.min(endPos, axisHeight),
223
+ height: plotBandHeight,
220
224
  color: plotBand.color,
221
225
  opacity: plotBand.opacity,
222
226
  label: plotBand.label.text
@@ -234,6 +238,9 @@ export async function prepareYAxisData({ axis, split, scale, top: topOffset, wid
234
238
  const plotLine = axis.plotLines[i];
235
239
  const axisScale = scale;
236
240
  const plotLineValue = Number(axisScale(plotLine.value));
241
+ if (plotLineValue < 0 || plotLineValue > axisHeight) {
242
+ continue;
243
+ }
237
244
  const points = [
238
245
  [0, plotLineValue],
239
246
  [width, plotLineValue],
@@ -275,6 +275,9 @@ export function createXScale(args) {
275
275
  if (typeof xMinPropsOrState === 'number' && !isPointDomain) {
276
276
  xMin = xMinPropsOrState;
277
277
  }
278
+ else if (xType === 'logarithmic') {
279
+ xMin = xMinDomain;
280
+ }
278
281
  else {
279
282
  const xMinDefault = getDefaultMinXAxisValue(series);
280
283
  xMin = xMinDefault !== null && xMinDefault !== void 0 ? xMinDefault : xMinDomain;
@@ -5,7 +5,7 @@ import { getFormattedValue } from '../../../utils/chart/format';
5
5
  import { getBarYLayout, groupBarYDataByYValue } from '../../utils';
6
6
  export async function prepareBarYData(args) {
7
7
  var _a;
8
- const { boundsHeight, boundsWidth, series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
8
+ const { boundsHeight, boundsWidth, series, seriesOptions, xAxis, yAxis, xScale, yScale: [yScale], } = args;
9
9
  const stackGap = seriesOptions['bar-y'].stackGap;
10
10
  const xLinearScale = xScale;
11
11
  const yLinearScale = yScale;
@@ -43,7 +43,8 @@ export async function prepareBarYData(args) {
43
43
  const stacks = Object.values(val);
44
44
  const currentBarHeight = barSize * stacks.length + barGap * (stacks.length - 1);
45
45
  stacks.forEach((measureValues, groupItemIndex) => {
46
- const base = xLinearScale(0) - measureValues[0].series.borderWidth;
46
+ const baseValue = xAxis.type === 'logarithmic' ? 0 : xLinearScale(0);
47
+ const base = baseValue - measureValues[0].series.borderWidth;
47
48
  let stackSum = base;
48
49
  const stackItems = [];
49
50
  const sortedData = sortKey
@@ -19,7 +19,8 @@
19
19
  "label_invalid-axis-type": "It seems you are trying to use inappropriate type for \"{{key}}\" axis. Available types: [{{values}}].",
20
20
  "label_invalid-axis-labels-html-type": "It seems you are trying to use inappropriate type for \"labels.html\" property. Only boolean is allowed.",
21
21
  "label_invalid-axis-labels-html-not-supported-axis-type": "It seems you are trying to use \"labels.html\" property for an axis with an unsupported type. This property is supported only for \"category\" axis.",
22
- "label_duplicate-axis-categories": "It seems you have duplicate value \"{{duplicate}}\" found in {{key}}[{{axisIndex}}]."
22
+ "label_duplicate-axis-categories": "It seems you have duplicate value \"{{duplicate}}\" found in {{key}}[{{axisIndex}}].",
23
+ "label_invalid-axis-categories": "It seems you are trying to use inappropriate value for \"categories\", or defined it incorrectly. Categories must be a non-empty array for an axis with \"category\" type."
23
24
  },
24
25
  "tooltip": {
25
26
  "label_totals_sum": "Sum",
@@ -19,7 +19,8 @@
19
19
  "label_invalid-axis-type": "Похоже, что вы пытаетесь использовать некорректный тип для оси \"{{key}}\". Доступные типы: [{{values}}].",
20
20
  "label_invalid-axis-labels-html-type": "Похоже, что вы пытаетесь использовать некорректный тип для свойства \"labels.html\". Допускается только использование булевых значений.",
21
21
  "label_invalid-axis-labels-html-not-supported-axis-type": "Похоже, что вы пытаетесь использовать свойство \"labels.html\" для оси с неподдерживаемым типом. Это свойство поддерживается только для оси типа \"category\".",
22
- "label_duplicate-axis-categories": "Похоже, что у вас есть дублирующееся значение категории \"{{duplicate}}\" в оси {{key}}[{{axisIndex}}]."
22
+ "label_duplicate-axis-categories": "Похоже, что у вас есть дублирующееся значение категории \"{{duplicate}}\" в оси {{key}}[{{axisIndex}}].",
23
+ "label_invalid-axis-categories": "Похоже, что вы пытаетесь использовать недопустимое значение для \"categories\", или указали его неверно. Категории для оси типа \"category\" должны быть непустым массивом."
23
24
  },
24
25
  "tooltip": {
25
26
  "label_totals_sum": "Сумма",
@@ -215,18 +215,18 @@ export interface AxisPlotBand extends AxisPlot {
215
215
  * Can be a number, a string (e.g., a category), or a timestamp if representing a date.
216
216
  * When representing a date, the value **must be a timestamp** (number of milliseconds since Unix epoch).
217
217
  *
218
- * If the value is `-Infinity`, it will be treated as the start of the axis.
218
+ * If the value is `-Infinity` or `null`, it will be treated as the start of the axis.
219
219
  */
220
- from: number | string;
220
+ from: number | string | null;
221
221
  /**
222
222
  * The end position of the plot band in axis units.
223
223
  *
224
224
  * Can be a number, a string (e.g., a category), or a timestamp if representing a date.
225
225
  * When representing a date, the value **must be a timestamp** (number of milliseconds since Unix epoch).
226
226
  *
227
- * If the value is `Infinity`, it will be treated as the end of the axis.
227
+ * If the value is `Infinity` or `null`, it will be treated as the end of the axis.
228
228
  */
229
- to: number | string;
229
+ to: number | string | null;
230
230
  }
231
231
  export interface AxisCrosshair extends Omit<AxisPlotLine, 'value' | 'label'> {
232
232
  /** Whether the crosshair should snap to the point or follow the pointer independent of points.
@@ -68,8 +68,8 @@ export function getBandsPosition(args) {
68
68
  var _a, _b, _c;
69
69
  const { band, axisScale } = args;
70
70
  const range = axisScale.range();
71
- const scalePosFrom = band.from === -Infinity ? range[0] : axisScale(band.from);
72
- const scalePosTo = band.to === Infinity ? range[1] : axisScale(band.to);
71
+ const scalePosFrom = band.from === -Infinity || band.from === null ? range[0] : axisScale(band.from);
72
+ const scalePosTo = band.to === Infinity || band.to === null ? range[1] : axisScale(band.to);
73
73
  const isX = args.axis === 'x';
74
74
  if (scalePosTo !== undefined && scalePosFrom !== undefined) {
75
75
  return {
@@ -2,7 +2,15 @@ import { AXIS_TYPE } from '../constants';
2
2
  import { i18n } from '../i18n';
3
3
  import { CHART_ERROR_CODE, ChartError } from '../libs';
4
4
  const AVAILABLE_AXIS_TYPES = Object.values(AXIS_TYPE);
5
- function validateDuplicateCategories({ categories, key, axisIndex, }) {
5
+ function validateCategories(axis) {
6
+ if (!axis.categories || !Array.isArray(axis.categories) || axis.categories.length === 0) {
7
+ throw new ChartError({
8
+ code: CHART_ERROR_CODE.INVALID_DATA,
9
+ message: i18n('error', 'label_invalid-axis-categories'),
10
+ });
11
+ }
12
+ }
13
+ function validateDuplicateCategories({ axisIndex, key, categories = [], }) {
6
14
  const seen = new Set();
7
15
  categories.forEach((category) => {
8
16
  if (seen.has(category)) {
@@ -54,7 +62,8 @@ export function validateAxes(args) {
54
62
  if (xAxis) {
55
63
  validateAxisType({ axis: xAxis, key: 'x' });
56
64
  validateLabelsHtmlOptions({ axis: xAxis });
57
- if ((xAxis === null || xAxis === void 0 ? void 0 : xAxis.type) === 'category' && xAxis.categories) {
65
+ if ((xAxis === null || xAxis === void 0 ? void 0 : xAxis.type) === 'category') {
66
+ validateCategories(xAxis);
58
67
  validateDuplicateCategories({
59
68
  categories: xAxis.categories,
60
69
  key: 'x',
@@ -64,7 +73,8 @@ export function validateAxes(args) {
64
73
  }
65
74
  yAxis.forEach((axis, axisIndex) => {
66
75
  validateAxisType({ axis, key: 'y' });
67
- if (axis.type === 'category' && axis.categories) {
76
+ if (axis.type === 'category') {
77
+ validateCategories(axis);
68
78
  validateDuplicateCategories({
69
79
  categories: axis.categories,
70
80
  key: 'y',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.28.0",
3
+ "version": "1.28.2",
4
4
  "description": "React component used to render charts",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",