@gravity-ui/charts 1.11.4 → 1.13.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 (135) hide show
  1. package/dist/cjs/components/Axis/AxisX.js +62 -36
  2. package/dist/cjs/components/Axis/AxisY.js +67 -31
  3. package/dist/cjs/components/ChartInner/styles.css +1 -0
  4. package/dist/cjs/components/ChartInner/useChartInnerProps.js +15 -9
  5. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  6. package/dist/cjs/components/Tooltip/ChartTooltipContent.js +3 -3
  7. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
  8. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
  9. package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
  10. package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
  11. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
  12. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +102 -0
  13. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
  14. package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
  15. package/dist/cjs/components/Tooltip/index.js +1 -1
  16. package/dist/cjs/components/Tooltip/styles.css +14 -2
  17. package/dist/cjs/components/Tooltip/utils.d.ts +30 -0
  18. package/dist/cjs/components/Tooltip/utils.js +126 -0
  19. package/dist/cjs/constants/axis.d.ts +6 -0
  20. package/dist/cjs/constants/axis.js +6 -0
  21. package/dist/cjs/constants/index.d.ts +6 -4
  22. package/dist/cjs/constants/index.js +6 -4
  23. package/dist/cjs/constants/tooltip.d.ts +3 -0
  24. package/dist/cjs/constants/tooltip.js +3 -0
  25. package/dist/cjs/hooks/useAxisScales/index.d.ts +14 -3
  26. package/dist/cjs/hooks/useAxisScales/index.js +86 -22
  27. package/dist/cjs/hooks/useChartOptions/types.d.ts +5 -0
  28. package/dist/cjs/hooks/useChartOptions/utils.d.ts +11 -0
  29. package/dist/cjs/hooks/useChartOptions/utils.js +27 -0
  30. package/dist/cjs/hooks/useChartOptions/x-axis.js +6 -2
  31. package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +4 -2
  32. package/dist/cjs/hooks/useChartOptions/y-axis.js +14 -4
  33. package/dist/cjs/hooks/useSeries/prepare-area.d.ts +1 -1
  34. package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +3 -0
  35. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +5 -2
  36. package/dist/cjs/hooks/useSeries/prepare-line.d.ts +1 -1
  37. package/dist/cjs/hooks/useSeries/prepare-radar.d.ts +1 -1
  38. package/dist/cjs/hooks/useSeries/types.d.ts +3 -0
  39. package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +16 -13
  40. package/dist/cjs/hooks/useShapes/bar-y/index.d.ts +2 -2
  41. package/dist/cjs/hooks/useShapes/bar-y/index.js +5 -9
  42. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.d.ts +2 -2
  43. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +80 -107
  44. package/dist/cjs/hooks/useShapes/bar-y/types.d.ts +7 -2
  45. package/dist/cjs/hooks/useShapes/index.js +1 -1
  46. package/dist/cjs/hooks/useShapes/waterfall/prepare-data.js +1 -1
  47. package/dist/cjs/hooks/utils/bar-y.d.ts +27 -0
  48. package/dist/cjs/hooks/utils/bar-y.js +55 -0
  49. package/dist/cjs/hooks/utils/index.d.ts +1 -0
  50. package/dist/cjs/hooks/utils/index.js +1 -0
  51. package/dist/cjs/i18n/keysets/en.json +7 -1
  52. package/dist/cjs/i18n/keysets/ru.json +7 -1
  53. package/dist/cjs/types/chart/axis.d.ts +15 -3
  54. package/dist/cjs/types/chart/bar-y.d.ts +10 -0
  55. package/dist/cjs/types/chart/series.d.ts +10 -0
  56. package/dist/cjs/types/chart/tooltip.d.ts +21 -0
  57. package/dist/cjs/utils/chart/axis-generators/bottom.js +26 -13
  58. package/dist/cjs/utils/chart/get-closest-data.js +13 -12
  59. package/dist/cjs/utils/chart/index.js +1 -1
  60. package/dist/cjs/utils/chart/series/sorting.d.ts +6 -2
  61. package/dist/cjs/utils/chart/series/sorting.js +29 -4
  62. package/dist/cjs/utils/chart/zoom.js +2 -1
  63. package/dist/cjs/validation/index.js +55 -1
  64. package/dist/esm/components/Axis/AxisX.js +62 -36
  65. package/dist/esm/components/Axis/AxisY.js +67 -31
  66. package/dist/esm/components/ChartInner/styles.css +1 -0
  67. package/dist/esm/components/ChartInner/useChartInnerProps.js +15 -9
  68. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -0
  69. package/dist/esm/components/Tooltip/ChartTooltipContent.js +3 -3
  70. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
  71. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
  72. package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
  73. package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
  74. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
  75. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +102 -0
  76. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
  77. package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
  78. package/dist/esm/components/Tooltip/index.js +1 -1
  79. package/dist/esm/components/Tooltip/styles.css +14 -2
  80. package/dist/esm/components/Tooltip/utils.d.ts +30 -0
  81. package/dist/esm/components/Tooltip/utils.js +126 -0
  82. package/dist/esm/constants/axis.d.ts +6 -0
  83. package/dist/esm/constants/axis.js +6 -0
  84. package/dist/esm/constants/index.d.ts +6 -4
  85. package/dist/esm/constants/index.js +6 -4
  86. package/dist/esm/constants/tooltip.d.ts +3 -0
  87. package/dist/esm/constants/tooltip.js +3 -0
  88. package/dist/esm/hooks/useAxisScales/index.d.ts +14 -3
  89. package/dist/esm/hooks/useAxisScales/index.js +86 -22
  90. package/dist/esm/hooks/useChartOptions/types.d.ts +5 -0
  91. package/dist/esm/hooks/useChartOptions/utils.d.ts +11 -0
  92. package/dist/esm/hooks/useChartOptions/utils.js +27 -0
  93. package/dist/esm/hooks/useChartOptions/x-axis.js +6 -2
  94. package/dist/esm/hooks/useChartOptions/y-axis.d.ts +4 -2
  95. package/dist/esm/hooks/useChartOptions/y-axis.js +14 -4
  96. package/dist/esm/hooks/useSeries/prepare-area.d.ts +1 -1
  97. package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +3 -0
  98. package/dist/esm/hooks/useSeries/prepare-bar-y.js +5 -2
  99. package/dist/esm/hooks/useSeries/prepare-line.d.ts +1 -1
  100. package/dist/esm/hooks/useSeries/prepare-radar.d.ts +1 -1
  101. package/dist/esm/hooks/useSeries/types.d.ts +3 -0
  102. package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +16 -13
  103. package/dist/esm/hooks/useShapes/bar-y/index.d.ts +2 -2
  104. package/dist/esm/hooks/useShapes/bar-y/index.js +5 -9
  105. package/dist/esm/hooks/useShapes/bar-y/prepare-data.d.ts +2 -2
  106. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +80 -107
  107. package/dist/esm/hooks/useShapes/bar-y/types.d.ts +7 -2
  108. package/dist/esm/hooks/useShapes/index.js +1 -1
  109. package/dist/esm/hooks/useShapes/waterfall/prepare-data.js +1 -1
  110. package/dist/esm/hooks/utils/bar-y.d.ts +27 -0
  111. package/dist/esm/hooks/utils/bar-y.js +55 -0
  112. package/dist/esm/hooks/utils/index.d.ts +1 -0
  113. package/dist/esm/hooks/utils/index.js +1 -0
  114. package/dist/esm/i18n/keysets/en.json +7 -1
  115. package/dist/esm/i18n/keysets/ru.json +7 -1
  116. package/dist/esm/types/chart/axis.d.ts +15 -3
  117. package/dist/esm/types/chart/bar-y.d.ts +10 -0
  118. package/dist/esm/types/chart/series.d.ts +10 -0
  119. package/dist/esm/types/chart/tooltip.d.ts +21 -0
  120. package/dist/esm/utils/chart/axis-generators/bottom.js +26 -13
  121. package/dist/esm/utils/chart/get-closest-data.js +13 -12
  122. package/dist/esm/utils/chart/index.js +1 -1
  123. package/dist/esm/utils/chart/series/sorting.d.ts +6 -2
  124. package/dist/esm/utils/chart/series/sorting.js +29 -4
  125. package/dist/esm/utils/chart/zoom.js +2 -1
  126. package/dist/esm/validation/index.js +55 -1
  127. package/package.json +1 -1
  128. package/dist/cjs/components/Tooltip/DefaultContent.d.ts +0 -10
  129. package/dist/cjs/components/Tooltip/DefaultContent.js +0 -187
  130. package/dist/esm/components/Tooltip/DefaultContent.d.ts +0 -10
  131. package/dist/esm/components/Tooltip/DefaultContent.js +0 -187
  132. /package/dist/cjs/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
  133. /package/dist/cjs/hooks/{useShapes/constants.js → constants.js} +0 -0
  134. /package/dist/esm/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
  135. /package/dist/esm/hooks/{useShapes/constants.js → constants.js} +0 -0
@@ -0,0 +1,27 @@
1
+ import { ascending, descending, reverse, sort } from 'd3';
2
+ import { DEFAULT_AXIS_LABEL_FONT_SIZE } from '../../constants';
3
+ export function prepareAxisPlotLabel(d) {
4
+ var _a, _b, _c, _d, _e;
5
+ return {
6
+ text: (_b = (_a = d.label) === null || _a === void 0 ? void 0 : _a.text) !== null && _b !== void 0 ? _b : '',
7
+ style: Object.assign({ fontSize: DEFAULT_AXIS_LABEL_FONT_SIZE, fontColor: 'var(--g-color-text-secondary)' }, (_c = d.label) === null || _c === void 0 ? void 0 : _c.style),
8
+ padding: (_e = (_d = d.label) === null || _d === void 0 ? void 0 : _d.padding) !== null && _e !== void 0 ? _e : 5,
9
+ };
10
+ }
11
+ export function getAxisCategories(axis) {
12
+ const categories = axis === null || axis === void 0 ? void 0 : axis.categories;
13
+ if (categories) {
14
+ switch (axis.order) {
15
+ case 'reverse': {
16
+ return reverse(categories);
17
+ }
18
+ case 'sortAsc': {
19
+ return sort(categories, (a, b) => ascending(a, b));
20
+ }
21
+ case 'sortDesc': {
22
+ return sort(categories, (a, b) => descending(a, b));
23
+ }
24
+ }
25
+ }
26
+ return categories;
27
+ }
@@ -2,8 +2,9 @@ import get from 'lodash/get';
2
2
  import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, axisCrosshairDefaults, axisLabelsDefaults, xAxisTitleDefaults, } from '../../constants';
3
3
  import { calculateCos, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getMaxTickCount, getTicksCount, getXAxisItems, hasOverlappingLabels, wrapText, } from '../../utils';
4
4
  import { createXScale } from '../useAxisScales';
5
+ import { getAxisCategories, prepareAxisPlotLabel } from './utils';
5
6
  async function getLabelSettings({ axis, seriesData, width, autoRotation = true, }) {
6
- const scale = createXScale(axis, seriesData, width);
7
+ const scale = createXScale({ axis, series: seriesData, boundsWidth: width });
7
8
  const tickCount = getTicksCount({ axis, range: width });
8
9
  const ticks = getXAxisItems({
9
10
  scale: scale,
@@ -69,7 +70,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, }) => {
69
70
  maxWidth: get(xAxis, 'labels.maxWidth', axisLabelsDefaults.maxWidth),
70
71
  },
71
72
  lineColor: get(xAxis, 'lineColor'),
72
- categories: get(xAxis, 'categories'),
73
+ categories: getAxisCategories(xAxis),
73
74
  timestamps: get(xAxis, 'timestamps'),
74
75
  title: {
75
76
  text: titleText,
@@ -98,6 +99,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, }) => {
98
99
  dashStyle: get(d, 'dashStyle', DASH_STYLE.Solid),
99
100
  opacity: get(d, 'opacity', 1),
100
101
  layerPlacement: get(d, 'layerPlacement', 'before'),
102
+ label: prepareAxisPlotLabel(d),
101
103
  })),
102
104
  plotBands: get(xAxis, 'plotBands', []).map((d) => ({
103
105
  color: get(d, 'color', 'var(--g-color-base-brand)'),
@@ -105,6 +107,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, }) => {
105
107
  from: get(d, 'from', 0),
106
108
  to: get(d, 'to', 0),
107
109
  layerPlacement: get(d, 'layerPlacement', 'before'),
110
+ label: prepareAxisPlotLabel(d),
108
111
  })),
109
112
  crosshair: {
110
113
  enabled: get(xAxis, 'crosshair.enabled', axisCrosshairDefaults.enabled),
@@ -116,6 +119,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, }) => {
116
119
  opacity: get(xAxis, 'crosshair.opacity', axisCrosshairDefaults.opacity),
117
120
  },
118
121
  visible: get(xAxis, 'visible', true),
122
+ order: xAxis === null || xAxis === void 0 ? void 0 : xAxis.order,
119
123
  };
120
124
  const { height, rotation } = await getLabelSettings({
121
125
  axis: preparedXAxis,
@@ -1,7 +1,9 @@
1
1
  import type { ChartSeries, ChartYAxis } from '../../types';
2
+ import type { PreparedSeriesOptions } from '../useSeries/types';
2
3
  import type { PreparedAxis } from './types';
3
- export declare const getPreparedYAxis: ({ seriesData, yAxis, height, }: {
4
+ export declare const getPreparedYAxis: ({ height, seriesData, seriesOptions, yAxis, }: {
5
+ height: number;
4
6
  seriesData: ChartSeries[];
7
+ seriesOptions: PreparedSeriesOptions;
5
8
  yAxis: ChartYAxis[] | undefined;
6
- height: number;
7
9
  }) => Promise<PreparedAxis[]>;
@@ -2,12 +2,18 @@ import get from 'lodash/get';
2
2
  import { DASH_STYLE, DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, axisCrosshairDefaults, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
3
3
  import { formatAxisTickLabel, getClosestPointsRange, getDefaultMinYAxisValue, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, isAxisRelatedSeries, wrapText, } from '../../utils';
4
4
  import { createYScale } from '../useAxisScales';
5
+ import { getAxisCategories, prepareAxisPlotLabel } from './utils';
5
6
  const getAxisLabelMaxWidth = async (args) => {
6
- const { axis, seriesData } = args;
7
+ const { axis, seriesData, seriesOptions } = args;
7
8
  if (!axis.labels.enabled) {
8
9
  return 0;
9
10
  }
10
- const scale = createYScale(axis, seriesData, 1);
11
+ const scale = createYScale({
12
+ axis,
13
+ boundsHeight: 1,
14
+ series: seriesData,
15
+ seriesOptions,
16
+ });
11
17
  const ticks = getScaleTicks(scale);
12
18
  // FIXME: it is necessary to filter data, since we do not draw overlapping ticks
13
19
  const step = getClosestPointsRange(axis, ticks);
@@ -23,7 +29,7 @@ const getAxisLabelMaxWidth = async (args) => {
23
29
  });
24
30
  return size.maxWidth;
25
31
  };
26
- export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
32
+ export const getPreparedYAxis = ({ height, seriesData, seriesOptions, yAxis, }) => {
27
33
  const axisByPlot = [];
28
34
  const axisItems = yAxis || [{}];
29
35
  const hasAxisRelatedSeries = seriesData.some(isAxisRelatedSeries);
@@ -73,7 +79,7 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
73
79
  maxWidth: get(axisItem, 'labels.maxWidth', axisLabelsDefaults.maxWidth),
74
80
  },
75
81
  lineColor: get(axisItem, 'lineColor'),
76
- categories: get(axisItem, 'categories'),
82
+ categories: getAxisCategories(axisItem),
77
83
  timestamps: get(axisItem, 'timestamps'),
78
84
  title: {
79
85
  text: titleText,
@@ -103,6 +109,7 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
103
109
  dashStyle: get(d, 'dashStyle', DASH_STYLE.Solid),
104
110
  opacity: get(d, 'opacity', 1),
105
111
  layerPlacement: get(d, 'layerPlacement', 'before'),
112
+ label: prepareAxisPlotLabel(d),
106
113
  })),
107
114
  plotBands: get(axisItem, 'plotBands', []).map((d) => ({
108
115
  color: get(d, 'color', 'var(--g-color-base-brand)'),
@@ -110,6 +117,7 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
110
117
  from: get(d, 'from', 0),
111
118
  to: get(d, 'to', 0),
112
119
  layerPlacement: get(d, 'layerPlacement', 'before'),
120
+ label: prepareAxisPlotLabel(d),
113
121
  })),
114
122
  crosshair: {
115
123
  enabled: get(axisItem, 'crosshair.enabled', axisCrosshairDefaults.enabled),
@@ -121,11 +129,13 @@ export const getPreparedYAxis = ({ seriesData, yAxis, height, }) => {
121
129
  opacity: get(axisItem, 'crosshair.opacity', axisCrosshairDefaults.opacity),
122
130
  },
123
131
  visible: get(axisItem, 'visible', true),
132
+ order: axisItem.order,
124
133
  };
125
134
  if (labelsEnabled) {
126
135
  preparedAxis.labels.width = await getAxisLabelMaxWidth({
127
136
  axis: preparedAxis,
128
137
  seriesData,
138
+ seriesOptions,
129
139
  });
130
140
  }
131
141
  return preparedAxis;
@@ -6,8 +6,8 @@ export declare const DEFAULT_MARKER: {
6
6
  enabled: boolean;
7
7
  symbol: `${import("../../constants").SymbolType}`;
8
8
  radius: number;
9
- borderColor: string;
10
9
  borderWidth: number;
10
+ borderColor: string;
11
11
  };
12
12
  type PrepareAreaSeriesArgs = {
13
13
  colorScale: ScaleOrdinal<string, string>;
@@ -20,8 +20,11 @@ export declare function prepareBarYSeries(args: PrepareBarYSeriesArgs): Promise<
20
20
  maxWidth: number;
21
21
  html: boolean;
22
22
  format?: import("../..").ValueFormat;
23
+ allowOverlap: boolean;
23
24
  };
24
25
  borderRadius: number;
26
+ borderWidth: number;
27
+ borderColor: string;
25
28
  } & {
26
29
  color: string;
27
30
  name: string;
@@ -4,7 +4,7 @@ import { getLabelsSize, getUniqId } from '../../utils';
4
4
  import { getFormattedValue } from '../../utils/chart/format';
5
5
  import { getSeriesStackId, prepareLegendSymbol } from './utils';
6
6
  async function prepareDataLabels(series) {
7
- var _a, _b;
7
+ var _a, _b, _c, _d;
8
8
  const enabled = get(series, 'dataLabels.enabled', false);
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);
@@ -25,12 +25,13 @@ async function prepareDataLabels(series) {
25
25
  maxWidth,
26
26
  html,
27
27
  format: (_b = series.dataLabels) === null || _b === void 0 ? void 0 : _b.format,
28
+ allowOverlap: (_d = (_c = series.dataLabels) === null || _c === void 0 ? void 0 : _c.allowOverlap) !== null && _d !== void 0 ? _d : false,
28
29
  };
29
30
  }
30
31
  export function prepareBarYSeries(args) {
31
32
  const { colorScale, series: seriesList, seriesOptions, legend } = args;
32
33
  return Promise.all(seriesList.map(async (series) => {
33
- var _a, _b, _c;
34
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
34
35
  const name = series.name || '';
35
36
  const color = series.color || colorScale(name);
36
37
  return {
@@ -49,6 +50,8 @@ export function prepareBarYSeries(args) {
49
50
  dataLabels: await prepareDataLabels(series),
50
51
  cursor: get(series, 'cursor', null),
51
52
  borderRadius: (_c = (_a = series.borderRadius) !== null && _a !== void 0 ? _a : (_b = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _b === void 0 ? void 0 : _b.borderRadius) !== null && _c !== void 0 ? _c : 0,
53
+ borderWidth: (_f = (_d = series.borderWidth) !== null && _d !== void 0 ? _d : (_e = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _e === void 0 ? void 0 : _e.borderWidth) !== null && _f !== void 0 ? _f : 0,
54
+ borderColor: (_j = (_g = series.borderColor) !== null && _g !== void 0 ? _g : (_h = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _h === void 0 ? void 0 : _h.borderColor) !== null && _j !== void 0 ? _j : 'var(--gcharts-shape-border-color)',
52
55
  };
53
56
  }));
54
57
  }
@@ -8,8 +8,8 @@ export declare const DEFAULT_MARKER: {
8
8
  enabled: boolean;
9
9
  symbol: `${import("../../constants").SymbolType}`;
10
10
  radius: number;
11
- borderColor: string;
12
11
  borderWidth: number;
12
+ borderColor: string;
13
13
  };
14
14
  type PrepareLineSeriesArgs = {
15
15
  colorScale: ScaleOrdinal<string, string>;
@@ -10,8 +10,8 @@ export declare const DEFAULT_MARKER: {
10
10
  enabled: boolean;
11
11
  radius: number;
12
12
  symbol: `${import("../../constants").SymbolType}`;
13
- borderColor: string;
14
13
  borderWidth: number;
14
+ borderColor: string;
15
15
  };
16
16
  export declare function prepareRadarSeries(args: PrepareRadarSeriesArgs): PreparedRadarSeries[];
17
17
  export {};
@@ -130,8 +130,11 @@ export type PreparedBarYSeries = {
130
130
  maxWidth: number;
131
131
  html: boolean;
132
132
  format?: ValueFormat;
133
+ allowOverlap: boolean;
133
134
  };
134
135
  borderRadius: number;
136
+ borderWidth: number;
137
+ borderColor: string;
135
138
  } & BasePreparedSeries;
136
139
  export type PreparedPieSeries = {
137
140
  type: PieSeries['type'];
@@ -2,7 +2,7 @@ import { ascending, descending, max, sort } from 'd3';
2
2
  import get from 'lodash/get';
3
3
  import { getDataCategoryValue, getLabelsSize } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../../constants';
6
6
  async function getLabelData(d) {
7
7
  if (!d.series.dataLabels.enabled) {
8
8
  return undefined;
@@ -95,36 +95,39 @@ export const prepareBarXData = async (args) => {
95
95
  const rectGap = Math.max(bandWidth * barPadding, MIN_BAR_GAP);
96
96
  const rectWidth = Math.max(MIN_BAR_WIDTH, Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth));
97
97
  const result = [];
98
- await Promise.all(Object.entries(data).map(async ([xValue, val]) => {
98
+ const groupedData = Object.entries(data);
99
+ for (let groupedDataIndex = 0; groupedDataIndex < groupedData.length; groupedDataIndex++) {
100
+ const [xValue, val] = groupedData[groupedDataIndex];
99
101
  const stacks = Object.values(val);
100
102
  const currentGroupWidth = rectWidth * stacks.length + rectGap * (stacks.length - 1);
101
- await Promise.all(stacks.map(async (yValues, groupItemIndex) => {
103
+ for (let groupItemIndex = 0; groupItemIndex < stacks.length; groupItemIndex++) {
104
+ const yValues = stacks[groupItemIndex];
102
105
  let stackHeight = 0;
103
106
  const stackItems = [];
104
107
  const sortedData = sortKey
105
108
  ? sort(yValues, (a, b) => comparator(get(a, sortKey), get(b, sortKey)))
106
109
  : yValues;
107
- await Promise.all(sortedData.map(async (yValue, yValueIndex) => {
110
+ for (let yValueIndex = 0; yValueIndex < sortedData.length; yValueIndex++) {
111
+ const yValue = sortedData[yValueIndex];
108
112
  const yAxisIndex = yValue.series.yAxis;
109
113
  const seriesYScale = yScale[yAxisIndex];
110
114
  let xCenter;
111
115
  if (xAxis.type === 'category') {
112
116
  const xBandScale = xScale;
113
- xCenter =
114
- (xBandScale(xValue) || 0) +
115
- xBandScale.bandwidth() / 2;
117
+ xCenter = (xBandScale(xValue) || 0) + xBandScale.bandwidth() / 2;
116
118
  }
117
119
  else {
118
120
  const xLinearScale = xScale;
119
121
  xCenter = xLinearScale(Number(xValue));
120
122
  }
121
- const x = xCenter -
122
- currentGroupWidth / 2 +
123
- (rectWidth + rectGap) * groupItemIndex;
123
+ const x = xCenter - currentGroupWidth / 2 + (rectWidth + rectGap) * groupItemIndex;
124
124
  const yDataValue = yValue.data.y;
125
125
  const y = seriesYScale(yDataValue);
126
126
  const base = seriesYScale(0);
127
127
  const height = yDataValue > 0 ? base - y : y - base;
128
+ if (height <= 0) {
129
+ continue;
130
+ }
128
131
  const barData = {
129
132
  x,
130
133
  y: yDataValue > 0 ? y - stackHeight : seriesYScale(0),
@@ -151,7 +154,7 @@ export const prepareBarXData = async (args) => {
151
154
  }
152
155
  stackItems.push(barData);
153
156
  stackHeight += height + 1;
154
- }));
157
+ }
155
158
  if (series.some((s) => s.stacking === 'percent')) {
156
159
  let acc = 0;
157
160
  const ratio = plotHeight / (stackHeight - stackItems.length);
@@ -162,7 +165,7 @@ export const prepareBarXData = async (args) => {
162
165
  });
163
166
  }
164
167
  result.push(...stackItems);
165
- }));
166
- }));
168
+ }
169
+ }
167
170
  return result;
168
171
  };
@@ -1,11 +1,11 @@
1
1
  import React from 'react';
2
2
  import type { Dispatch } from 'd3';
3
3
  import type { PreparedSeriesOptions } from '../../useSeries/types';
4
- import type { PreparedBarYData } from './types';
4
+ import type { BarYShapesArgs } from './types';
5
5
  export { prepareBarYData } from './prepare-data';
6
6
  type Args = {
7
7
  dispatcher: Dispatch<object>;
8
- preparedData: PreparedBarYData[];
8
+ preparedData: BarYShapesArgs;
9
9
  seriesOptions: PreparedSeriesOptions;
10
10
  htmlLayout: HTMLElement | null;
11
11
  clipPathId: string;
@@ -7,7 +7,7 @@ import { getRectPath } from '../utils';
7
7
  export { prepareBarYData } from './prepare-data';
8
8
  const b = block('bar-y');
9
9
  export const BarYSeriesShapes = (args) => {
10
- const { dispatcher, preparedData, seriesOptions, htmlLayout, clipPathId } = args;
10
+ const { dispatcher, preparedData: { shapes: preparedData, labels: dataLabels, htmlElements }, seriesOptions, htmlLayout, clipPathId, } = args;
11
11
  const hoveredDataRef = React.useRef(null);
12
12
  const ref = React.useRef(null);
13
13
  React.useEffect(() => {
@@ -39,14 +39,10 @@ export const BarYSeriesShapes = (args) => {
39
39
  .attr('height', (d) => d.height)
40
40
  .attr('width', (d) => d.width)
41
41
  .attr('fill', (d) => d.color)
42
+ .attr('stroke', (d) => d.borderColor)
43
+ .attr('stroke-width', (d) => d.borderWidth)
42
44
  .attr('opacity', (d) => d.data.opacity || null)
43
45
  .attr('cursor', (d) => d.series.cursor);
44
- const dataLabels = preparedData.reduce((acc, d) => {
45
- if (d.label) {
46
- acc.push(d.label);
47
- }
48
- return acc;
49
- }, []);
50
46
  const labelSelection = svgElement
51
47
  .selectAll('text')
52
48
  .data(dataLabels)
@@ -97,8 +93,8 @@ export const BarYSeriesShapes = (args) => {
97
93
  return () => {
98
94
  dispatcher.on('hover-shape.bar-y', null);
99
95
  };
100
- }, [dispatcher, preparedData, seriesOptions]);
96
+ }, [dataLabels, dispatcher, preparedData, seriesOptions]);
101
97
  return (React.createElement(React.Fragment, null,
102
98
  React.createElement("g", { ref: ref, className: b(), clipPath: `url(#${clipPathId})` }),
103
- React.createElement(HtmlLayer, { preparedData: preparedData, htmlLayout: htmlLayout })));
99
+ React.createElement(HtmlLayer, { preparedData: { htmlElements }, htmlLayout: htmlLayout })));
104
100
  };
@@ -1,7 +1,7 @@
1
1
  import type { ChartScale } from '../../useAxisScales';
2
2
  import type { PreparedAxis } from '../../useChartOptions/types';
3
3
  import type { PreparedBarYSeries, PreparedSeriesOptions } from '../../useSeries/types';
4
- import type { PreparedBarYData } from './types';
4
+ import type { BarYShapesArgs } from './types';
5
5
  export declare const prepareBarYData: (args: {
6
6
  series: PreparedBarYSeries[];
7
7
  seriesOptions: PreparedSeriesOptions;
@@ -9,4 +9,4 @@ export declare const prepareBarYData: (args: {
9
9
  xScale: ChartScale;
10
10
  yAxis: PreparedAxis[];
11
11
  yScale: ChartScale[];
12
- }) => Promise<PreparedBarYData[]>;
12
+ }) => Promise<BarYShapesArgs>;
@@ -1,98 +1,16 @@
1
- import { ascending, descending, max, sort } from 'd3';
1
+ import { ascending, descending, sort } from 'd3';
2
2
  import get from 'lodash/get';
3
- import { getDataCategoryValue, getLabelsSize } from '../../../utils';
3
+ import { filterOverlappingLabels, getLabelsSize, getTextSizeFn } from '../../../utils';
4
4
  import { getFormattedValue } from '../../../utils/chart/format';
5
- import { MIN_BAR_GAP, MIN_BAR_GROUP_GAP, MIN_BAR_WIDTH } from '../constants';
5
+ import { getBarYLayoutForCategoryScale, getBarYLayoutForNumericScale, groupBarYDataByYValue, } from '../../utils';
6
6
  const DEFAULT_LABEL_PADDING = 7;
7
- function groupByYValue(series, yAxis) {
8
- const data = {};
9
- series.forEach((s) => {
10
- s.data.forEach((d) => {
11
- const axisIndex = get(s, 'yAxis', 0);
12
- const seriesYAxis = yAxis[axisIndex];
13
- const categories = get(seriesYAxis, 'categories', []);
14
- const key = seriesYAxis.type === 'category'
15
- ? getDataCategoryValue({ axisDirection: 'y', categories, data: d })
16
- : d.y;
17
- if (key) {
18
- if (!data[key]) {
19
- data[key] = {};
20
- }
21
- if (!data[key][s.stackId]) {
22
- data[key][s.stackId] = [];
23
- }
24
- data[key][s.stackId].push({ data: d, series: s });
25
- }
26
- });
27
- });
28
- return data;
29
- }
30
- function getBandWidth(series, yAxis, yScale) {
31
- let bandWidth = Infinity;
32
- if (yAxis[0].type === 'category') {
33
- bandWidth = yScale.bandwidth();
34
- }
35
- else {
36
- const scale = yScale;
37
- const axisValues = series.reduce((acc, s) => {
38
- s.data.forEach((dataItem) => acc.push(Number(dataItem.y)));
39
- return acc;
40
- }, []);
41
- axisValues.sort().forEach((value, index) => {
42
- if (index > 0 && value !== axisValues[index - 1]) {
43
- const dist = scale(value) - scale(axisValues[index - 1]);
44
- if (dist < bandWidth) {
45
- bandWidth = dist;
46
- }
47
- }
48
- });
49
- }
50
- return bandWidth;
51
- }
52
- async function setLabel(prepared) {
53
- const dataLabels = prepared.series.dataLabels;
54
- if (!dataLabels.enabled) {
55
- return;
56
- }
57
- const data = prepared.data;
58
- const content = getFormattedValue(Object.assign({ value: data.label || data.x }, dataLabels));
59
- const { maxHeight: height, maxWidth: width } = await getLabelsSize({
60
- labels: [content],
61
- style: dataLabels.style,
62
- html: dataLabels.html,
63
- });
64
- const x = dataLabels.inside
65
- ? prepared.x + prepared.width / 2
66
- : prepared.x + prepared.width + DEFAULT_LABEL_PADDING;
67
- const y = prepared.y + prepared.height / 2;
68
- if (dataLabels.html) {
69
- prepared.htmlElements.push({
70
- x,
71
- y: y - height / 2,
72
- content,
73
- size: { width, height },
74
- style: dataLabels.style,
75
- });
76
- }
77
- else {
78
- prepared.label = {
79
- x,
80
- y: y + height / 2,
81
- text: content,
82
- textAnchor: dataLabels.inside ? 'middle' : 'right',
83
- style: dataLabels.style,
84
- series: prepared.series,
85
- size: { width, height },
86
- };
87
- }
88
- }
89
7
  export const prepareBarYData = async (args) => {
8
+ var _a;
90
9
  const { series, seriesOptions, yAxis, xScale, yScale: [yScale], } = args;
91
10
  const xLinearScale = xScale;
11
+ const yLinearScale = yScale;
12
+ const plotHeight = yLinearScale(yLinearScale.domain()[0]);
92
13
  const plotWidth = xLinearScale(xLinearScale.domain()[1]);
93
- const barMaxWidth = get(seriesOptions, 'bar-y.barMaxWidth');
94
- const barPadding = get(seriesOptions, 'bar-y.barPadding');
95
- const groupPadding = get(seriesOptions, 'bar-y.groupPadding');
96
14
  const sortingOptions = get(seriesOptions, 'bar-y.dataSorting');
97
15
  const comparator = (sortingOptions === null || sortingOptions === void 0 ? void 0 : sortingOptions.direction) === 'desc' ? descending : ascending;
98
16
  const sortKey = (() => {
@@ -108,19 +26,21 @@ export const prepareBarYData = async (args) => {
108
26
  }
109
27
  }
110
28
  })();
111
- const groupedData = groupByYValue(series, yAxis);
112
- const bandWidth = getBandWidth(series, yAxis, yScale);
113
- const maxGroupSize = max(Object.values(groupedData), (d) => Object.values(d).length) || 1;
114
- const groupGap = Math.max(bandWidth * groupPadding, MIN_BAR_GROUP_GAP);
115
- const groupWidth = bandWidth - groupGap;
116
- const rectGap = Math.max(bandWidth * barPadding, MIN_BAR_GAP);
117
- const barHeight = Math.max(MIN_BAR_WIDTH, Math.min(groupWidth / maxGroupSize - rectGap, barMaxWidth));
29
+ const groupedData = groupBarYDataByYValue(series, yAxis);
30
+ const { bandSize, barGap, barSize } = yAxis[0].type === 'category'
31
+ ? getBarYLayoutForCategoryScale({ groupedData, seriesOptions, yScale })
32
+ : getBarYLayoutForNumericScale({
33
+ groupedData,
34
+ seriesOptions,
35
+ plotHeight: plotHeight - plotHeight * yAxis[0].maxPadding,
36
+ });
118
37
  const result = [];
38
+ const baseRangeValue = xLinearScale.range()[0];
119
39
  Object.entries(groupedData).forEach(([yValue, val]) => {
120
40
  const stacks = Object.values(val);
121
- const currentBarHeight = barHeight * stacks.length + rectGap * (stacks.length - 1);
41
+ const currentBarHeight = barSize * stacks.length + barGap * (stacks.length - 1);
122
42
  stacks.forEach((measureValues, groupItemIndex) => {
123
- const base = xLinearScale(0);
43
+ const base = xLinearScale(0 - measureValues[0].series.borderWidth);
124
44
  let stackSum = base;
125
45
  const stackItems = [];
126
46
  const sortedData = sortKey
@@ -130,25 +50,29 @@ export const prepareBarYData = async (args) => {
130
50
  let center;
131
51
  if (yAxis[0].type === 'category') {
132
52
  const bandScale = yScale;
133
- center = (bandScale(yValue) || 0) + bandWidth / 2;
53
+ center = (bandScale(yValue) || 0) + bandSize / 2;
134
54
  }
135
55
  else {
136
56
  const scale = yScale;
137
57
  center = scale(Number(yValue));
138
58
  }
139
- const y = center - currentBarHeight / 2 + (barHeight + rectGap) * groupItemIndex;
59
+ const y = center - currentBarHeight / 2 + (barSize + barGap) * groupItemIndex;
140
60
  const xValue = Number(data.x);
141
- const width = xValue > 0 ? xLinearScale(xValue) - base : base - xLinearScale(xValue);
61
+ const width = Math.abs(xLinearScale(xValue) - base);
62
+ if (width <= 0) {
63
+ return;
64
+ }
142
65
  const item = {
143
- x: xValue > 0 ? stackSum : stackSum - width,
66
+ x: xValue > baseRangeValue ? stackSum : stackSum - width,
144
67
  y,
145
68
  width,
146
- height: barHeight,
69
+ height: barSize,
147
70
  color: data.color || s.color,
71
+ borderColor: s.borderColor,
72
+ borderWidth: s.borderWidth,
148
73
  opacity: get(data, 'opacity', null),
149
74
  data,
150
75
  series: s,
151
- htmlElements: [],
152
76
  isLastStackItem: xValueIndex === sortedData.length - 1,
153
77
  };
154
78
  stackItems.push(item);
@@ -166,8 +90,57 @@ export const prepareBarYData = async (args) => {
166
90
  result.push(...stackItems);
167
91
  });
168
92
  });
169
- await Promise.all(result.map(async (d) => {
170
- await setLabel(d);
171
- }));
172
- return result;
93
+ let labels = [];
94
+ const htmlElements = [];
95
+ const map = new Map();
96
+ for (let i = 0; i < result.length; i++) {
97
+ const prepared = result[i];
98
+ const dataLabels = prepared.series.dataLabels;
99
+ if (dataLabels.enabled) {
100
+ const data = prepared.data;
101
+ const content = getFormattedValue(Object.assign({ value: data.label || data.x }, dataLabels));
102
+ const x = dataLabels.inside
103
+ ? prepared.x + prepared.width / 2
104
+ : prepared.x + prepared.width + DEFAULT_LABEL_PADDING;
105
+ const y = prepared.y + prepared.height / 2;
106
+ if (dataLabels.html) {
107
+ const { maxHeight: height, maxWidth: width } = await getLabelsSize({
108
+ labels: [content],
109
+ style: dataLabels.style,
110
+ html: dataLabels.html,
111
+ });
112
+ htmlElements.push({
113
+ x,
114
+ y: y - height / 2,
115
+ content,
116
+ size: { width, height },
117
+ style: dataLabels.style,
118
+ });
119
+ }
120
+ else {
121
+ if (!map.has(dataLabels.style)) {
122
+ map.set(dataLabels.style, getTextSizeFn({ style: dataLabels.style }));
123
+ }
124
+ const getTextSize = map.get(dataLabels.style);
125
+ const { width, height } = await getTextSize(content);
126
+ labels.push({
127
+ x,
128
+ y: y + height / 2,
129
+ text: content,
130
+ textAnchor: dataLabels.inside ? 'middle' : 'right',
131
+ style: dataLabels.style,
132
+ series: prepared.series,
133
+ size: { width, height },
134
+ });
135
+ }
136
+ }
137
+ }
138
+ if (!((_a = result[0]) === null || _a === void 0 ? void 0 : _a.series.dataLabels.allowOverlap)) {
139
+ labels = filterOverlappingLabels(labels);
140
+ }
141
+ return {
142
+ shapes: result,
143
+ labels,
144
+ htmlElements,
145
+ };
173
146
  };
@@ -6,9 +6,14 @@ export type PreparedBarYData = Omit<TooltipDataChunkBarX, 'series'> & {
6
6
  width: number;
7
7
  height: number;
8
8
  color: string;
9
+ borderWidth: number;
10
+ borderColor: string;
9
11
  opacity: number | null;
10
12
  series: PreparedBarYSeries;
11
- label?: LabelData;
12
- htmlElements: HtmlItem[];
13
13
  isLastStackItem: boolean;
14
14
  };
15
+ export type BarYShapesArgs = {
16
+ shapes: PreparedBarYData[];
17
+ labels: LabelData[];
18
+ htmlElements: HtmlItem[];
19
+ };
@@ -64,7 +64,7 @@ export const useShapes = (args) => {
64
64
  yScale,
65
65
  });
66
66
  shapes.push(React.createElement(BarYSeriesShapes, { key: "bar-y", dispatcher: dispatcher, seriesOptions: seriesOptions, preparedData: preparedData, htmlLayout: htmlLayout, clipPathId: clipPathId }));
67
- shapesData.push(...preparedData);
67
+ shapesData.push(...preparedData.shapes);
68
68
  }
69
69
  break;
70
70
  }