@gravity-ui/charts 1.18.0 → 1.18.1

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 (49) hide show
  1. package/dist/cjs/components/AxisY/prepare-axis-data.d.ts +3 -2
  2. package/dist/cjs/components/AxisY/prepare-axis-data.js +5 -5
  3. package/dist/cjs/components/AxisY/utils.d.ts +4 -2
  4. package/dist/cjs/components/AxisY/utils.js +47 -14
  5. package/dist/cjs/components/ChartInner/index.js +2 -1
  6. package/dist/cjs/components/ChartInner/useChartInnerProps.js +1 -2
  7. package/dist/cjs/hooks/useAxisScales/index.d.ts +0 -1
  8. package/dist/cjs/hooks/useAxisScales/index.js +42 -21
  9. package/dist/cjs/hooks/useChartOptions/utils.d.ts +5 -2
  10. package/dist/cjs/hooks/useChartOptions/utils.js +2 -3
  11. package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +1 -3
  12. package/dist/cjs/hooks/useChartOptions/y-axis.js +3 -5
  13. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +3 -1
  14. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.d.ts +4 -2
  15. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +39 -20
  16. package/dist/cjs/hooks/useShapes/index.js +2 -0
  17. package/dist/cjs/hooks/useZoom/utils.js +24 -8
  18. package/dist/cjs/hooks/utils/bar-y.d.ts +7 -10
  19. package/dist/cjs/hooks/utils/bar-y.js +33 -18
  20. package/dist/cjs/utils/chart/array.js +3 -0
  21. package/dist/cjs/utils/chart/format.js +2 -2
  22. package/dist/cjs/utils/chart/index.js +2 -1
  23. package/dist/cjs/utils/chart/labels.d.ts +27 -5
  24. package/dist/cjs/utils/chart/labels.js +39 -3
  25. package/dist/esm/components/AxisY/prepare-axis-data.d.ts +3 -2
  26. package/dist/esm/components/AxisY/prepare-axis-data.js +5 -5
  27. package/dist/esm/components/AxisY/utils.d.ts +4 -2
  28. package/dist/esm/components/AxisY/utils.js +47 -14
  29. package/dist/esm/components/ChartInner/index.js +2 -1
  30. package/dist/esm/components/ChartInner/useChartInnerProps.js +1 -2
  31. package/dist/esm/hooks/useAxisScales/index.d.ts +0 -1
  32. package/dist/esm/hooks/useAxisScales/index.js +42 -21
  33. package/dist/esm/hooks/useChartOptions/utils.d.ts +5 -2
  34. package/dist/esm/hooks/useChartOptions/utils.js +2 -3
  35. package/dist/esm/hooks/useChartOptions/y-axis.d.ts +1 -3
  36. package/dist/esm/hooks/useChartOptions/y-axis.js +3 -5
  37. package/dist/esm/hooks/useSeries/prepare-bar-y.js +3 -1
  38. package/dist/esm/hooks/useShapes/bar-y/prepare-data.d.ts +4 -2
  39. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +39 -20
  40. package/dist/esm/hooks/useShapes/index.js +2 -0
  41. package/dist/esm/hooks/useZoom/utils.js +24 -8
  42. package/dist/esm/hooks/utils/bar-y.d.ts +7 -10
  43. package/dist/esm/hooks/utils/bar-y.js +33 -18
  44. package/dist/esm/utils/chart/array.js +3 -0
  45. package/dist/esm/utils/chart/format.js +2 -2
  46. package/dist/esm/utils/chart/index.js +2 -1
  47. package/dist/esm/utils/chart/labels.d.ts +27 -5
  48. package/dist/esm/utils/chart/labels.js +39 -3
  49. package/package.json +1 -1
@@ -9,7 +9,9 @@ async function prepareDataLabels(series) {
9
9
  const style = Object.assign({}, DEFAULT_DATALABELS_STYLE, (_a = series.dataLabels) === null || _a === void 0 ? void 0 : _a.style);
10
10
  const html = get(series, 'dataLabels.html', false);
11
11
  const labels = enabled
12
- ? series.data.map((d) => getFormattedValue(Object.assign({ value: d.x || d.label }, series.dataLabels)))
12
+ ? series.data
13
+ .filter((d) => Boolean(d.x || d.label))
14
+ .map((d) => getFormattedValue(Object.assign({ value: d.x || d.label }, series.dataLabels)))
13
15
  : [];
14
16
  const { maxHeight = 0, maxWidth = 0 } = await getLabelsSize({
15
17
  labels,
@@ -2,11 +2,13 @@ import type { ChartScale } from '../../useAxisScales';
2
2
  import type { PreparedAxis } from '../../useChartOptions/types';
3
3
  import type { PreparedBarYSeries, PreparedSeriesOptions } from '../../useSeries/types';
4
4
  import type { BarYShapesArgs } from './types';
5
- export declare const prepareBarYData: (args: {
5
+ export declare function prepareBarYData(args: {
6
+ boundsHeight: number;
7
+ boundsWidth: number;
6
8
  series: PreparedBarYSeries[];
7
9
  seriesOptions: PreparedSeriesOptions;
8
10
  xAxis: PreparedAxis;
9
11
  xScale: ChartScale;
10
12
  yAxis: PreparedAxis[];
11
13
  yScale: (ChartScale | undefined)[];
12
- }) => Promise<BarYShapesArgs>;
14
+ }): Promise<BarYShapesArgs>;
@@ -1,12 +1,12 @@
1
1
  import { ascending, descending, sort } from 'd3';
2
2
  import get from 'lodash/get';
3
- import { filterOverlappingLabels, getLabelsSize, getTextSizeFn } from '../../../utils';
3
+ import { filterOverlappingLabels, getHtmlLabelConstraintedPosition, getLabelsSize, getSvgLabelConstraintedPosition, getTextSizeFn, } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { getBarYLayoutForCategoryScale, getBarYLayoutForNumericScale, groupBarYDataByYValue, } from '../../utils';
5
+ import { getBarYLayout, groupBarYDataByYValue } from '../../utils';
6
6
  const DEFAULT_LABEL_PADDING = 7;
7
- export const prepareBarYData = async (args) => {
7
+ export async function prepareBarYData(args) {
8
8
  var _a;
9
- const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
9
+ const { boundsHeight, boundsWidth, series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
10
10
  const stackGap = seriesOptions['bar-y'].stackGap;
11
11
  const xLinearScale = xScale;
12
12
  const yLinearScale = yScale;
@@ -18,7 +18,6 @@ export const prepareBarYData = async (args) => {
18
18
  };
19
19
  }
20
20
  const yScaleRange = yLinearScale.range();
21
- const plotHeight = Math.abs(yScaleRange[0] - yScaleRange[1]);
22
21
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
23
22
  const comparator = (sortingOptions === null || sortingOptions === void 0 ? void 0 : sortingOptions.direction) === 'desc' ? descending : ascending;
24
23
  const sortKey = (() => {
@@ -35,13 +34,13 @@ export const prepareBarYData = async (args) => {
35
34
  }
36
35
  })();
37
36
  const groupedData = groupBarYDataByYValue(series, yAxis);
38
- const { bandSize, barGap, barSize } = yAxis[0].type === 'category'
39
- ? getBarYLayoutForCategoryScale({ groupedData, seriesOptions, yScale: yLinearScale })
40
- : getBarYLayoutForNumericScale({
41
- groupedData,
42
- seriesOptions,
43
- plotHeight: plotHeight - plotHeight * yAxis[0].maxPadding,
44
- });
37
+ const plotHeight = Math.abs(yScaleRange[0] - yScaleRange[1]);
38
+ const { bandSize, barGap, barSize } = getBarYLayout({
39
+ groupedData,
40
+ seriesOptions,
41
+ plotHeight,
42
+ scale: yScale,
43
+ });
45
44
  const result = [];
46
45
  const baseRangeValue = xLinearScale.range()[0];
47
46
  Object.entries(groupedData).forEach(([yValue, val]) => {
@@ -106,7 +105,7 @@ export const prepareBarYData = async (args) => {
106
105
  });
107
106
  });
108
107
  let labels = [];
109
- const htmlElements = [];
108
+ let htmlElements = [];
110
109
  const map = new Map();
111
110
  for (let i = 0; i < result.length; i++) {
112
111
  const prepared = result[i];
@@ -124,12 +123,20 @@ export const prepareBarYData = async (args) => {
124
123
  style: dataLabels.style,
125
124
  html: dataLabels.html,
126
125
  });
127
- htmlElements.push({
126
+ const constrainedPosition = getHtmlLabelConstraintedPosition({
127
+ boundsHeight,
128
+ boundsWidth,
129
+ height,
130
+ width,
128
131
  x,
129
132
  y: y - height / 2,
133
+ });
134
+ htmlElements.push({
130
135
  content,
131
136
  size: { width, height },
132
137
  style: dataLabels.style,
138
+ x: constrainedPosition.x,
139
+ y: constrainedPosition.y,
133
140
  });
134
141
  }
135
142
  else {
@@ -138,24 +145,36 @@ export const prepareBarYData = async (args) => {
138
145
  }
139
146
  const getTextSize = map.get(dataLabels.style);
140
147
  const { width, height } = await getTextSize(content);
141
- labels.push({
148
+ const constrainedPosition = getSvgLabelConstraintedPosition({
149
+ boundsHeight,
150
+ boundsWidth,
151
+ height,
152
+ width,
142
153
  x,
143
154
  y: y + height / 2,
155
+ });
156
+ labels.push({
157
+ size: { width, height },
158
+ series: prepared.series,
159
+ style: dataLabels.style,
144
160
  text: content,
145
161
  textAnchor: dataLabels.inside ? 'middle' : 'right',
146
- style: dataLabels.style,
147
- series: prepared.series,
148
- size: { width, height },
162
+ x: constrainedPosition.x,
163
+ y: constrainedPosition.y,
149
164
  });
150
165
  }
151
166
  }
152
167
  }
153
- if (!((_a = result[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
168
+ const allowOverlap = (_a = result[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap;
169
+ if (labels.length && !allowOverlap) {
154
170
  labels = filterOverlappingLabels(labels);
155
171
  }
172
+ else if (htmlElements.length && !allowOverlap) {
173
+ htmlElements = filterOverlappingLabels(htmlElements);
174
+ }
156
175
  return {
157
176
  shapes: result,
158
177
  labels,
159
178
  htmlElements,
160
179
  };
161
- };
180
+ }
@@ -56,6 +56,8 @@ export const useShapes = (args) => {
56
56
  case 'bar-y': {
57
57
  if (xAxis && xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length)) {
58
58
  const preparedData = await prepareBarYData({
59
+ boundsHeight,
60
+ boundsWidth,
59
61
  series: chartSeries,
60
62
  seriesOptions,
61
63
  xAxis,
@@ -95,6 +95,22 @@ function selectionXToZoomBounds(args) {
95
95
  }
96
96
  }
97
97
  }
98
+ function getYMinMaxFromSelection(args) {
99
+ const { selection, yAxis } = args;
100
+ let yMin;
101
+ let yMax;
102
+ switch (yAxis.order) {
103
+ case 'reverse':
104
+ case 'sortDesc': {
105
+ [yMin, yMax] = selection;
106
+ break;
107
+ }
108
+ default: {
109
+ [yMax, yMin] = selection;
110
+ }
111
+ }
112
+ return [yMin, yMax];
113
+ }
98
114
  function selectionYToZoomBounds(args) {
99
115
  const { yAxis, yScale, selection } = args;
100
116
  switch (yAxis.type) {
@@ -104,8 +120,8 @@ function selectionYToZoomBounds(args) {
104
120
  const categories = yAxis.categories || [];
105
121
  const currentDomain = bandScale.domain();
106
122
  const step = bandScale.step();
107
- let startIndex = currentDomain.length - 1 - Math.floor(y0 / step);
108
- let endIndex = currentDomain.length - 1 - Math.floor(y1 / step);
123
+ let startIndex = Math.max(0, currentDomain.length - 1 - Math.floor(y0 / step));
124
+ let endIndex = Math.min(currentDomain.length - 1, currentDomain.length - 1 - Math.floor(y1 / step));
109
125
  const startCategory = currentDomain[startIndex];
110
126
  const endCategory = currentDomain[endIndex];
111
127
  startIndex = categories.indexOf(startCategory);
@@ -119,18 +135,18 @@ function selectionYToZoomBounds(args) {
119
135
  return [startIndex, endIndex];
120
136
  }
121
137
  case 'datetime': {
122
- const [y1, y0] = selection;
138
+ const [yMin, yMax] = getYMinMaxFromSelection({ selection, yAxis });
123
139
  const timeScale = yScale;
124
- const minTimestamp = timeScale.invert(y0).getTime();
125
- const maxTimestamp = timeScale.invert(y1).getTime();
140
+ const minTimestamp = timeScale.invert(yMin).getTime();
141
+ const maxTimestamp = timeScale.invert(yMax).getTime();
126
142
  return [minTimestamp, maxTimestamp];
127
143
  }
128
144
  case 'linear':
129
145
  case 'logarithmic': {
130
- const [y1, y0] = selection;
146
+ const [yMin, yMax] = getYMinMaxFromSelection({ selection, yAxis });
131
147
  const linearScale = yScale;
132
- const minValue = linearScale.invert(y0);
133
- const maxValue = linearScale.invert(y1);
148
+ const minValue = linearScale.invert(yMin);
149
+ const maxValue = linearScale.invert(yMax);
134
150
  return [minValue, maxValue];
135
151
  }
136
152
  default: {
@@ -1,3 +1,4 @@
1
+ import type { AxisDomain, AxisScale } from 'd3';
1
2
  import type { BarYSeries, BarYSeriesData } from '../../types';
2
3
  import type { ChartScale } from '../useAxisScales';
3
4
  import type { PreparedAxis } from '../useChartOptions/types';
@@ -6,19 +7,15 @@ export declare function groupBarYDataByYValue<T extends BarYSeries | PreparedBar
6
7
  data: BarYSeriesData;
7
8
  series: T;
8
9
  }[]>>;
9
- export declare function getBarYLayoutForNumericScale(args: {
10
+ export declare function getBandSize({ domain, scale, }: {
11
+ domain: AxisDomain[];
12
+ scale: AxisScale<AxisDomain> | undefined;
13
+ }): number;
14
+ export declare function getBarYLayout(args: {
10
15
  plotHeight: number;
11
16
  seriesOptions: PreparedSeriesOptions;
12
17
  groupedData: ReturnType<typeof groupBarYDataByYValue>;
13
- }): {
14
- bandSize: number;
15
- barGap: number;
16
- barSize: number;
17
- };
18
- export declare function getBarYLayoutForCategoryScale(args: {
19
- groupedData: ReturnType<typeof groupBarYDataByYValue>;
20
- seriesOptions: PreparedSeriesOptions;
21
- yScale: ChartScale;
18
+ scale: ChartScale | undefined;
22
19
  }): {
23
20
  bandSize: number;
24
21
  barGap: number;
@@ -1,6 +1,6 @@
1
1
  import { max } from 'd3';
2
2
  import get from 'lodash/get';
3
- import { getDataCategoryValue } from '../../utils';
3
+ import { getDataCategoryValue, isBandScale } from '../../utils';
4
4
  import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
5
  import { getSeriesStackId } from '../useSeries/utils';
6
6
  export function groupBarYDataByYValue(series, yAxis) {
@@ -27,28 +27,43 @@ export function groupBarYDataByYValue(series, yAxis) {
27
27
  });
28
28
  return data;
29
29
  }
30
- export function getBarYLayoutForNumericScale(args) {
31
- const { plotHeight, groupedData, seriesOptions } = args;
32
- const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
33
- const barPadding = get(seriesOptions, 'bar-y.barPadding');
34
- const groupPadding = get(seriesOptions, 'bar-y.groupPadding');
35
- const groups = Object.values(groupedData);
36
- const maxGroupItemCount = groups.reduce((acc, items) => Math.max(acc, Object.keys(items).length), 0);
37
- const bandSize = plotHeight / groups.length;
38
- const groupGap = Math.max(bandSize * groupPadding, MIN_BAR_GROUP_GAP);
39
- const groupSize = bandSize - groupGap;
40
- const barGap = Math.max(bandSize * barPadding, MIN_BAR_GAP);
41
- const barSize = Math.max(MIN_BAR_WIDTH, Math.min((groupSize - barGap) / maxGroupItemCount, barMaxWidth));
42
- return { bandSize, barGap, barSize };
30
+ export function getBandSize({ domain, scale, }) {
31
+ if (!scale || !domain.length) {
32
+ return 0;
33
+ }
34
+ if (isBandScale(scale)) {
35
+ return scale.bandwidth();
36
+ }
37
+ const range = scale.range();
38
+ const plotHeight = Math.abs(range[0] - range[1]);
39
+ if (domain.length === 1) {
40
+ return plotHeight;
41
+ }
42
+ // for the numeric or datetime axes, you first need to count domain.length + 1,
43
+ // since the extreme points are located not in the center of the bar, but along the edges of the axes
44
+ let bandWidth = plotHeight / (domain.length - 1);
45
+ domain.forEach((current, index) => {
46
+ if (index > 0) {
47
+ const prev = domain[index - 1];
48
+ const prevY = scale(prev);
49
+ const currentY = scale(current);
50
+ if (typeof prevY === 'number' && typeof currentY === 'number') {
51
+ const distance = Math.abs(prevY - currentY);
52
+ bandWidth = Math.min(bandWidth, distance);
53
+ }
54
+ }
55
+ });
56
+ return bandWidth;
43
57
  }
44
- export function getBarYLayoutForCategoryScale(args) {
45
- const { groupedData, seriesOptions, yScale } = args;
58
+ export function getBarYLayout(args) {
59
+ const { groupedData, seriesOptions, scale } = args;
46
60
  const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
47
61
  const barPadding = get(seriesOptions, 'bar-y.barPadding');
48
62
  const groupPadding = get(seriesOptions, 'bar-y.groupPadding');
49
- const bandSize = yScale.bandwidth();
50
- const maxGroupSize = max(Object.values(groupedData), (d) => Object.values(d).length) || 1;
63
+ const domain = Object.keys(groupedData);
64
+ const bandSize = getBandSize({ domain, scale: scale });
51
65
  const groupGap = Math.max(bandSize * groupPadding, MIN_BAR_GROUP_GAP);
66
+ const maxGroupSize = max(Object.values(groupedData), (d) => Object.values(d).length) || 1;
52
67
  const groupSize = bandSize - groupGap;
53
68
  const barGap = Math.max(bandSize * barPadding, MIN_BAR_GAP);
54
69
  const barSize = Math.max(MIN_BAR_WIDTH, Math.min(groupSize / maxGroupSize - barGap, barMaxWidth));
@@ -1,4 +1,7 @@
1
1
  export function getMinSpaceBetween(arr, iterator) {
2
+ if (arr.length < 2) {
3
+ return 0;
4
+ }
2
5
  return arr.reduce((acc, item, index) => {
3
6
  const prev = arr[index - 1];
4
7
  if (prev) {
@@ -1,4 +1,4 @@
1
- import { dateTime } from '@gravity-ui/date-utils';
1
+ import { dateTimeUtc } from '@gravity-ui/date-utils';
2
2
  import capitalize from 'lodash/capitalize';
3
3
  import { DEFAULT_DATE_FORMAT } from '../../constants';
4
4
  import { formatNumber, getDefaultUnit } from '../../libs';
@@ -6,7 +6,7 @@ import { getDefaultDateFormat } from './time';
6
6
  const LETTER_MOUNTH_AT_START_FORMAT_REGEXP = /^M{3,}/;
7
7
  function getFormattedDate(args) {
8
8
  const { value, format = DEFAULT_DATE_FORMAT } = args;
9
- const date = dateTime({ input: value });
9
+ const date = dateTimeUtc({ input: value });
10
10
  if (date === null || date === void 0 ? void 0 : date.isValid()) {
11
11
  const formattedDate = date.format(format);
12
12
  if (LETTER_MOUNTH_AT_START_FORMAT_REGEXP.test(format)) {
@@ -128,7 +128,7 @@ export function getDefaultMinYAxisValue(series) {
128
128
  }
129
129
  export const getDomainDataYBySeries = (series) => {
130
130
  const groupedSeries = group(series, (item) => item.type);
131
- return Array.from(groupedSeries).reduce((acc, [type, seriesList]) => {
131
+ const items = Array.from(groupedSeries).reduce((acc, [type, seriesList]) => {
132
132
  switch (type) {
133
133
  case 'area':
134
134
  case 'bar-x': {
@@ -152,6 +152,7 @@ export const getDomainDataYBySeries = (series) => {
152
152
  }
153
153
  return acc;
154
154
  }, []);
155
+ return Array.from(new Set(items));
155
156
  };
156
157
  // Uses to get all series names array (except `pie` charts)
157
158
  export const getSeriesNames = (series) => {
@@ -1,6 +1,28 @@
1
- import type { LabelData } from '../../types';
1
+ import type { HtmlItem, LabelData } from '../../types';
2
2
  export declare function getLeftPosition(label: LabelData): number;
3
- export declare function getOverlappingByX(rect1: LabelData, rect2: LabelData, gap?: number): number;
4
- export declare function getOverlappingByY(rect1: LabelData, rect2: LabelData, gap?: number): number;
5
- export declare function isLabelsOverlapping<T extends LabelData>(label1: T, label2: T, padding?: number): boolean;
6
- export declare function filterOverlappingLabels<T extends LabelData>(labels: T[]): T[];
3
+ export declare function getOverlappingByX(rect1: LabelData | HtmlItem, rect2: LabelData | HtmlItem, gap?: number): number;
4
+ export declare function getOverlappingByY(rect1: LabelData | HtmlItem, rect2: LabelData | HtmlItem, gap?: number): number;
5
+ export declare function isLabelsOverlapping<T extends LabelData | HtmlItem>(label1: T, label2: T, padding?: number): boolean;
6
+ export declare function filterOverlappingLabels<T extends LabelData | HtmlItem>(labels: T[]): T[];
7
+ export declare function getSvgLabelConstraintedPosition(args: {
8
+ boundsHeight: number;
9
+ boundsWidth: number;
10
+ height: number;
11
+ width: number;
12
+ x: number;
13
+ y: number;
14
+ }): {
15
+ x: number;
16
+ y: number;
17
+ };
18
+ export declare function getHtmlLabelConstraintedPosition(args: {
19
+ boundsHeight: number;
20
+ boundsWidth: number;
21
+ height: number;
22
+ width: number;
23
+ x: number;
24
+ y: number;
25
+ }): {
26
+ x: number;
27
+ y: number;
28
+ };
@@ -16,9 +16,9 @@ export function getLeftPosition(label) {
16
16
  }
17
17
  }
18
18
  export function getOverlappingByX(rect1, rect2, gap = 0) {
19
- const left1 = getLeftPosition(rect1);
19
+ const left1 = 'textAnchor' in rect1 ? getLeftPosition(rect1) : rect1.x;
20
20
  const right1 = left1 + rect1.size.width;
21
- const left2 = getLeftPosition(rect2);
21
+ const left2 = 'textAnchor' in rect2 ? getLeftPosition(rect2) : rect2.x;
22
22
  const right2 = left2 + rect2.size.width;
23
23
  return Math.max(0, Math.min(right1, right2) - Math.max(left1, left2) + gap);
24
24
  }
@@ -34,7 +34,7 @@ export function isLabelsOverlapping(label1, label2, padding = 0) {
34
34
  }
35
35
  export function filterOverlappingLabels(labels) {
36
36
  const result = [];
37
- const sorted = sortBy(labels, (d) => d.y, getLeftPosition);
37
+ const sorted = sortBy(labels, (d) => d.y, (d) => ('textAnchor' in d ? getLeftPosition(d) : d.x));
38
38
  sorted.forEach((label) => {
39
39
  if (!result.some((l) => isLabelsOverlapping(label, l))) {
40
40
  result.push(label);
@@ -42,3 +42,39 @@ export function filterOverlappingLabels(labels) {
42
42
  });
43
43
  return result;
44
44
  }
45
+ export function getSvgLabelConstraintedPosition(args) {
46
+ const { boundsHeight, boundsWidth, height, width, x, y } = args;
47
+ let resultX = x;
48
+ let resultY = y;
49
+ if (x < 0) {
50
+ resultX = 0;
51
+ }
52
+ if (x + width > boundsWidth) {
53
+ resultX = boundsWidth - width;
54
+ }
55
+ if (y - height < 0) {
56
+ resultY = 0;
57
+ }
58
+ if (y > boundsHeight) {
59
+ resultY = boundsHeight;
60
+ }
61
+ return { x: resultX, y: resultY };
62
+ }
63
+ export function getHtmlLabelConstraintedPosition(args) {
64
+ const { boundsHeight, boundsWidth, height, width, x, y } = args;
65
+ let resultX = x;
66
+ let resultY = y;
67
+ if (x < 0) {
68
+ resultX = 0;
69
+ }
70
+ if (x + width > boundsWidth) {
71
+ resultX = boundsWidth - width;
72
+ }
73
+ if (y < 0) {
74
+ resultY = 0;
75
+ }
76
+ if (y + height > boundsHeight) {
77
+ resultY = boundsHeight - height;
78
+ }
79
+ return { x: resultX, y: resultY };
80
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.18.0",
3
+ "version": "1.18.1",
4
4
  "description": "React component used to render charts",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",