@gravity-ui/charts 1.42.2 → 1.42.4

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 (83) hide show
  1. package/dist/cjs/components/AxisX/AxisX.js +4 -4
  2. package/dist/cjs/components/AxisX/prepare-axis-data.js +17 -13
  3. package/dist/cjs/components/AxisY/AxisY.js +4 -4
  4. package/dist/cjs/components/AxisY/prepare-axis-data.js +27 -21
  5. package/dist/cjs/components/AxisY/prepare-axis-title.js +8 -3
  6. package/dist/cjs/components/AxisY/styles.css +1 -1
  7. package/dist/cjs/components/ChartInner/index.js +5 -15
  8. package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +4 -1
  9. package/dist/cjs/components/ChartInner/useChartInnerProps.js +22 -11
  10. package/dist/cjs/components/ChartInner/utils/title.d.ts +1 -1
  11. package/dist/cjs/components/ChartInner/utils/title.js +3 -3
  12. package/dist/cjs/components/Legend/index.js +19 -13
  13. package/dist/cjs/components/Legend/styles.css +1 -1
  14. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +1 -1
  15. package/dist/cjs/components/utils/axis-title.js +1 -1
  16. package/dist/cjs/core/axes/x-axis.js +2 -2
  17. package/dist/cjs/core/axes/y-axis.js +2 -2
  18. package/dist/cjs/core/layout/split.d.ts +2 -2
  19. package/dist/cjs/core/layout/split.js +22 -19
  20. package/dist/cjs/core/series/prepare-legend.js +7 -7
  21. package/dist/cjs/core/series/types.d.ts +2 -0
  22. package/dist/cjs/core/utils/axis-generators/bottom.js +6 -16
  23. package/dist/cjs/core/utils/common.d.ts +0 -4
  24. package/dist/cjs/core/utils/common.js +0 -13
  25. package/dist/cjs/core/utils/labels.d.ts +1 -0
  26. package/dist/cjs/core/utils/labels.js +5 -5
  27. package/dist/cjs/core/utils/text.d.ts +1 -0
  28. package/dist/cjs/core/utils/text.js +4 -0
  29. package/dist/cjs/hooks/useShapes/area/prepare-data.js +1 -1
  30. package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +3 -2
  31. package/dist/cjs/hooks/useShapes/funnel/prepare-data.js +4 -1
  32. package/dist/cjs/hooks/useShapes/heatmap/prepare-data.js +1 -1
  33. package/dist/cjs/hooks/useShapes/line/prepare-data.js +4 -1
  34. package/dist/cjs/hooks/useShapes/pie/prepare-data.js +9 -2
  35. package/dist/cjs/hooks/useShapes/radar/prepare-data.js +17 -7
  36. package/dist/cjs/hooks/useShapes/sankey/prepare-data.js +1 -1
  37. package/dist/cjs/hooks/useShapes/sankey/sankey-layout.d.ts +49 -0
  38. package/dist/cjs/hooks/useShapes/sankey/sankey-layout.js +362 -0
  39. package/dist/cjs/hooks/useShapes/styles.css +4 -4
  40. package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +3 -1
  41. package/dist/cjs/types/chart-ui.d.ts +1 -0
  42. package/dist/esm/components/AxisX/AxisX.js +4 -4
  43. package/dist/esm/components/AxisX/prepare-axis-data.js +17 -13
  44. package/dist/esm/components/AxisY/AxisY.js +4 -4
  45. package/dist/esm/components/AxisY/prepare-axis-data.js +27 -21
  46. package/dist/esm/components/AxisY/prepare-axis-title.js +8 -3
  47. package/dist/esm/components/AxisY/styles.css +1 -1
  48. package/dist/esm/components/ChartInner/index.js +5 -15
  49. package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +4 -1
  50. package/dist/esm/components/ChartInner/useChartInnerProps.js +22 -11
  51. package/dist/esm/components/ChartInner/utils/title.d.ts +1 -1
  52. package/dist/esm/components/ChartInner/utils/title.js +3 -3
  53. package/dist/esm/components/Legend/index.js +19 -13
  54. package/dist/esm/components/Legend/styles.css +1 -1
  55. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +1 -1
  56. package/dist/esm/components/utils/axis-title.js +1 -1
  57. package/dist/esm/core/axes/x-axis.js +2 -2
  58. package/dist/esm/core/axes/y-axis.js +2 -2
  59. package/dist/esm/core/layout/split.d.ts +2 -2
  60. package/dist/esm/core/layout/split.js +22 -19
  61. package/dist/esm/core/series/prepare-legend.js +7 -7
  62. package/dist/esm/core/series/types.d.ts +2 -0
  63. package/dist/esm/core/utils/axis-generators/bottom.js +6 -16
  64. package/dist/esm/core/utils/common.d.ts +0 -4
  65. package/dist/esm/core/utils/common.js +0 -13
  66. package/dist/esm/core/utils/labels.d.ts +1 -0
  67. package/dist/esm/core/utils/labels.js +5 -5
  68. package/dist/esm/core/utils/text.d.ts +1 -0
  69. package/dist/esm/core/utils/text.js +4 -0
  70. package/dist/esm/hooks/useShapes/area/prepare-data.js +1 -1
  71. package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +3 -2
  72. package/dist/esm/hooks/useShapes/funnel/prepare-data.js +4 -1
  73. package/dist/esm/hooks/useShapes/heatmap/prepare-data.js +1 -1
  74. package/dist/esm/hooks/useShapes/line/prepare-data.js +4 -1
  75. package/dist/esm/hooks/useShapes/pie/prepare-data.js +9 -2
  76. package/dist/esm/hooks/useShapes/radar/prepare-data.js +17 -7
  77. package/dist/esm/hooks/useShapes/sankey/prepare-data.js +1 -1
  78. package/dist/esm/hooks/useShapes/sankey/sankey-layout.d.ts +49 -0
  79. package/dist/esm/hooks/useShapes/sankey/sankey-layout.js +362 -0
  80. package/dist/esm/hooks/useShapes/styles.css +4 -4
  81. package/dist/esm/hooks/useShapes/treemap/prepare-data.js +3 -1
  82. package/dist/esm/types/chart-ui.d.ts +1 -0
  83. package/package.json +1 -3
@@ -0,0 +1,362 @@
1
+ // Derived from d3-sankey v0.12.3 (https://github.com/d3/d3-sankey)
2
+ // Copyright 2015-2021 Mike Bostock — ISC License
3
+ //
4
+ // Changes:
5
+ // - Ported to TypeScript with explicit generic types (SankeyComputedNode, SankeyComputedLink)
6
+ // - sankeyLinkHorizontal() implemented via linkHorizontal() from d3-shape
7
+ // - Removed unused alignment helpers (left, right, center); only justify is kept
8
+ // - No d3-sankey dependency; uses d3-array and d3-shape (already project dependencies)
9
+ import { max, min, sum } from 'd3-array';
10
+ import { linkHorizontal } from 'd3-shape';
11
+ function justify(node, n) {
12
+ return node.sourceLinks.length ? node.depth : n - 1;
13
+ }
14
+ function ascendingBreadth(a, b) {
15
+ return a.y0 - b.y0;
16
+ }
17
+ function ascendingSourceBreadth(a, b) {
18
+ return ascendingBreadth(a.source, b.source) || a.index - b.index;
19
+ }
20
+ function ascendingTargetBreadth(a, b) {
21
+ return ascendingBreadth(a.target, b.target) || a.index - b.index;
22
+ }
23
+ function nodeValue(d) {
24
+ return d.value;
25
+ }
26
+ function linkValue(d) {
27
+ return d.value;
28
+ }
29
+ export function sankey() {
30
+ let x0 = 0, y0 = 0, x1 = 1, y1 = 1;
31
+ let dx = 24; // nodeWidth
32
+ let dy = 8, py; // nodePadding
33
+ let getId = (_d, i) => i;
34
+ let align = justify;
35
+ let sort;
36
+ let linkSort;
37
+ let iterations = 6;
38
+ function generator(input) {
39
+ // Mutate input in-place (same as original d3-sankey): layout props are added
40
+ // directly to node/link objects so that source/target references stay consistent.
41
+ const graph = {
42
+ nodes: input.nodes,
43
+ links: input.links,
44
+ };
45
+ computeNodeLinks(graph);
46
+ computeNodeValues(graph);
47
+ computeNodeDepths(graph);
48
+ computeNodeHeights(graph);
49
+ computeNodeBreadths(graph);
50
+ computeLinkBreadths(graph);
51
+ return graph;
52
+ }
53
+ generator.nodeId = function (fn) {
54
+ getId = fn;
55
+ return generator;
56
+ };
57
+ generator.nodeAlign = function (fn) {
58
+ align = fn;
59
+ return generator;
60
+ };
61
+ generator.nodeSort = function (fn) {
62
+ sort = fn;
63
+ return generator;
64
+ };
65
+ generator.nodeWidth = function (value) {
66
+ dx = value;
67
+ return generator;
68
+ };
69
+ generator.nodePadding = function (value) {
70
+ dy = py = value;
71
+ return generator;
72
+ };
73
+ generator.linkSort = function (fn) {
74
+ linkSort = fn;
75
+ return generator;
76
+ };
77
+ generator.extent = function ([[left, top], [right, bottom]]) {
78
+ x0 = left;
79
+ y0 = top;
80
+ x1 = right;
81
+ y1 = bottom;
82
+ return generator;
83
+ };
84
+ generator.iterations = function (value) {
85
+ iterations = value;
86
+ return generator;
87
+ };
88
+ function computeNodeLinks(graph) {
89
+ for (const [i, node] of graph.nodes.entries()) {
90
+ node.index = i;
91
+ node.sourceLinks = [];
92
+ node.targetLinks = [];
93
+ }
94
+ const nodeById = new Map(graph.nodes.map((d, i) => [getId(d, i), d]));
95
+ for (const [i, link] of graph.links.entries()) {
96
+ link.index = i;
97
+ const unresolved = link;
98
+ if (typeof unresolved.source !== 'object') {
99
+ unresolved.source = findNode(nodeById, unresolved.source);
100
+ }
101
+ if (typeof unresolved.target !== 'object') {
102
+ unresolved.target = findNode(nodeById, unresolved.target);
103
+ }
104
+ link.source.sourceLinks.push(link);
105
+ link.target.targetLinks.push(link);
106
+ }
107
+ if (linkSort !== null && linkSort !== undefined) {
108
+ for (const { sourceLinks, targetLinks } of graph.nodes) {
109
+ sourceLinks.sort(linkSort);
110
+ targetLinks.sort(linkSort);
111
+ }
112
+ }
113
+ }
114
+ function computeNodeValues(graph) {
115
+ for (const node of graph.nodes) {
116
+ node.value =
117
+ node.fixedValue === undefined
118
+ ? Math.max(sum(node.sourceLinks, linkValue), sum(node.targetLinks, linkValue))
119
+ : node.fixedValue;
120
+ }
121
+ }
122
+ function computeNodeDepths(graph) {
123
+ const n = graph.nodes.length;
124
+ let current = new Set(graph.nodes);
125
+ let next = new Set();
126
+ let x = 0;
127
+ while (current.size) {
128
+ for (const node of current) {
129
+ node.depth = x;
130
+ for (const { target } of node.sourceLinks) {
131
+ next.add(target);
132
+ }
133
+ }
134
+ if (++x > n)
135
+ throw new Error('circular link');
136
+ current = next;
137
+ next = new Set();
138
+ }
139
+ }
140
+ function computeNodeHeights(graph) {
141
+ const n = graph.nodes.length;
142
+ let current = new Set(graph.nodes);
143
+ let next = new Set();
144
+ let x = 0;
145
+ while (current.size) {
146
+ for (const node of current) {
147
+ node.height = x;
148
+ for (const { source } of node.targetLinks) {
149
+ next.add(source);
150
+ }
151
+ }
152
+ if (++x > n)
153
+ throw new Error('circular link');
154
+ current = next;
155
+ next = new Set();
156
+ }
157
+ }
158
+ function computeNodeLayers(graph) {
159
+ var _a;
160
+ const x = ((_a = max(graph.nodes, (d) => d.depth)) !== null && _a !== void 0 ? _a : 0) + 1;
161
+ const kx = (x1 - x0 - dx) / (x - 1);
162
+ const columns = new Array(x);
163
+ for (const node of graph.nodes) {
164
+ const i = Math.max(0, Math.min(x - 1, Math.floor(align(node, x))));
165
+ node.layer = i;
166
+ node.x0 = x0 + i * kx;
167
+ node.x1 = node.x0 + dx;
168
+ if (columns[i])
169
+ columns[i].push(node);
170
+ else
171
+ columns[i] = [node];
172
+ }
173
+ if (sort) {
174
+ for (const column of columns) {
175
+ column.sort(sort);
176
+ }
177
+ }
178
+ return columns;
179
+ }
180
+ function initializeNodeBreadths(columns) {
181
+ var _a;
182
+ const ky = (_a = min(columns, (c) => (y1 - y0 - (c.length - 1) * py) / sum(c, nodeValue))) !== null && _a !== void 0 ? _a : 0;
183
+ for (const nodes of columns) {
184
+ let y = y0;
185
+ for (const node of nodes) {
186
+ node.y0 = y;
187
+ node.y1 = y + node.value * ky;
188
+ y = node.y1 + py;
189
+ for (const link of node.sourceLinks) {
190
+ link.width = link.value * ky;
191
+ }
192
+ }
193
+ y = (y1 - y + py) / (nodes.length + 1);
194
+ for (let i = 0; i < nodes.length; ++i) {
195
+ const node = nodes[i];
196
+ node.y0 += y * (i + 1);
197
+ node.y1 += y * (i + 1);
198
+ }
199
+ reorderLinks(nodes);
200
+ }
201
+ }
202
+ function computeNodeBreadths(graph) {
203
+ var _a;
204
+ const columns = computeNodeLayers(graph);
205
+ py = Math.min(dy, (y1 - y0) / (((_a = max(columns, (c) => c.length)) !== null && _a !== void 0 ? _a : 1) - 1));
206
+ initializeNodeBreadths(columns);
207
+ for (let i = 0; i < iterations; ++i) {
208
+ const alpha = Math.pow(0.99, i);
209
+ const beta = Math.max(1 - alpha, (i + 1) / iterations);
210
+ relaxRightToLeft(columns, alpha, beta);
211
+ relaxLeftToRight(columns, alpha, beta);
212
+ }
213
+ }
214
+ function computeLinkBreadths(graph) {
215
+ for (const node of graph.nodes) {
216
+ let ly0 = node.y0;
217
+ let ly1 = ly0;
218
+ for (const link of node.sourceLinks) {
219
+ link.y0 = ly0 + link.width / 2;
220
+ ly0 += link.width;
221
+ }
222
+ for (const link of node.targetLinks) {
223
+ link.y1 = ly1 + link.width / 2;
224
+ ly1 += link.width;
225
+ }
226
+ }
227
+ }
228
+ function relaxLeftToRight(columns, alpha, beta) {
229
+ for (let i = 1, n = columns.length; i < n; ++i) {
230
+ const column = columns[i];
231
+ for (const target of column) {
232
+ let y = 0;
233
+ let w = 0;
234
+ for (const { source, value } of target.targetLinks) {
235
+ const v = value * (target.layer - source.layer);
236
+ y += targetTop(source, target) * v;
237
+ w += v;
238
+ }
239
+ if (!(w > 0))
240
+ continue;
241
+ const d = (y / w - target.y0) * alpha;
242
+ target.y0 += d;
243
+ target.y1 += d;
244
+ reorderNodeLinks(target);
245
+ }
246
+ if (sort === undefined)
247
+ column.sort(ascendingBreadth);
248
+ resolveCollisions(column, beta);
249
+ }
250
+ }
251
+ function relaxRightToLeft(columns, alpha, beta) {
252
+ for (let n = columns.length, i = n - 2; i >= 0; --i) {
253
+ const column = columns[i];
254
+ for (const source of column) {
255
+ let y = 0;
256
+ let w = 0;
257
+ for (const { target, value } of source.sourceLinks) {
258
+ const v = value * (target.layer - source.layer);
259
+ y += sourceTop(source, target) * v;
260
+ w += v;
261
+ }
262
+ if (!(w > 0))
263
+ continue;
264
+ const d = (y / w - source.y0) * alpha;
265
+ source.y0 += d;
266
+ source.y1 += d;
267
+ reorderNodeLinks(source);
268
+ }
269
+ if (sort === undefined)
270
+ column.sort(ascendingBreadth);
271
+ resolveCollisions(column, beta);
272
+ }
273
+ }
274
+ function resolveCollisions(nodes, alpha) {
275
+ const i = Math.floor(nodes.length / 2);
276
+ const subject = nodes[i];
277
+ resolveCollisionsBottomToTop(nodes, subject.y0 - py, i - 1, alpha);
278
+ resolveCollisionsTopToBottom(nodes, subject.y1 + py, i + 1, alpha);
279
+ resolveCollisionsBottomToTop(nodes, y1, nodes.length - 1, alpha);
280
+ resolveCollisionsTopToBottom(nodes, y0, 0, alpha);
281
+ }
282
+ function resolveCollisionsTopToBottom(nodes, y, i, alpha) {
283
+ for (; i < nodes.length; ++i) {
284
+ const node = nodes[i];
285
+ const d = (y - node.y0) * alpha;
286
+ if (d > 1e-6) {
287
+ node.y0 += d;
288
+ node.y1 += d;
289
+ }
290
+ y = node.y1 + py;
291
+ }
292
+ }
293
+ function resolveCollisionsBottomToTop(nodes, y, i, alpha) {
294
+ for (; i >= 0; --i) {
295
+ const node = nodes[i];
296
+ const d = (node.y1 - y) * alpha;
297
+ if (d > 1e-6) {
298
+ node.y0 -= d;
299
+ node.y1 -= d;
300
+ }
301
+ y = node.y0 - py;
302
+ }
303
+ }
304
+ function reorderNodeLinks(node) {
305
+ if (linkSort === undefined) {
306
+ for (const { source: { sourceLinks }, } of node.targetLinks) {
307
+ sourceLinks.sort(ascendingTargetBreadth);
308
+ }
309
+ for (const { target: { targetLinks }, } of node.sourceLinks) {
310
+ targetLinks.sort(ascendingSourceBreadth);
311
+ }
312
+ }
313
+ }
314
+ function reorderLinks(nodes) {
315
+ if (linkSort === undefined) {
316
+ for (const { sourceLinks, targetLinks } of nodes) {
317
+ sourceLinks.sort(ascendingTargetBreadth);
318
+ targetLinks.sort(ascendingSourceBreadth);
319
+ }
320
+ }
321
+ }
322
+ function targetTop(source, target) {
323
+ let y = source.y0 - ((source.sourceLinks.length - 1) * py) / 2;
324
+ for (const { target: node, width } of source.sourceLinks) {
325
+ if (node === target)
326
+ break;
327
+ y += width + py;
328
+ }
329
+ for (const { source: node, width } of target.targetLinks) {
330
+ if (node === source)
331
+ break;
332
+ y -= width;
333
+ }
334
+ return y;
335
+ }
336
+ function sourceTop(source, target) {
337
+ let y = target.y0 - ((target.targetLinks.length - 1) * py) / 2;
338
+ for (const { source: node, width } of target.targetLinks) {
339
+ if (node === source)
340
+ break;
341
+ y += width + py;
342
+ }
343
+ for (const { target: node, width } of source.sourceLinks) {
344
+ if (node === target)
345
+ break;
346
+ y -= width;
347
+ }
348
+ return y;
349
+ }
350
+ return generator;
351
+ }
352
+ export function sankeyLinkHorizontal() {
353
+ return linkHorizontal()
354
+ .source((d) => [d.source.x1, d.y0])
355
+ .target((d) => [d.target.x0, d.y1]);
356
+ }
357
+ function findNode(nodeById, id) {
358
+ const node = nodeById.get(id);
359
+ if (!node)
360
+ throw new Error('missing: ' + id);
361
+ return node;
362
+ }
@@ -3,7 +3,7 @@
3
3
  .gcharts-radar__label,
4
4
  .gcharts-heatmap__label,
5
5
  .gcharts-funnel__label {
6
- dominant-baseline: text-before-edge;
6
+ dominant-baseline: hanging;
7
7
  }
8
8
 
9
9
  .gcharts-scatter__point {
@@ -17,7 +17,7 @@
17
17
  font-size: 11px;
18
18
  font-weight: bold;
19
19
  fill: var(--g-color-text-complementary);
20
- dominant-baseline: text-before-edge;
20
+ dominant-baseline: hanging;
21
21
  }
22
22
 
23
23
  .gcharts-bar-x__label {
@@ -28,14 +28,14 @@
28
28
  .gcharts-bar-y__label {
29
29
  user-select: none;
30
30
  fill: var(--g-color-text-complementary);
31
- dominant-baseline: text-after-edge;
31
+ dominant-baseline: hanging;
32
32
  }
33
33
 
34
34
  .gcharts-treemap__label {
35
35
  user-select: none;
36
36
  pointer-events: none;
37
37
  fill: var(--g-color-text-complementary);
38
- dominant-baseline: text-before-edge;
38
+ dominant-baseline: hanging;
39
39
  }
40
40
 
41
41
  .gcharts-waterfall__connector {
@@ -22,6 +22,7 @@ async function getLabels(args) {
22
22
  const label = getFormattedValue(Object.assign({ value: text }, args.options));
23
23
  let labelMaxHeight = 0;
24
24
  let labelMaxWidth = 0;
25
+ let hangingOffset = 0;
25
26
  if (html) {
26
27
  const size = (_a = (await getLabelsSize({
27
28
  labels: [label],
@@ -35,9 +36,10 @@ async function getLabels(args) {
35
36
  const size = await getTextSize(label);
36
37
  labelMaxHeight = size.height;
37
38
  labelMaxWidth = size.width;
39
+ hangingOffset = size.hangingOffset;
38
40
  }
39
41
  let x = left;
40
- const y = prevLabelsHeight + d.y0 + padding;
42
+ const y = prevLabelsHeight + d.y0 + padding + hangingOffset;
41
43
  const labelWidth = Math.min(labelMaxWidth, spaceWidth);
42
44
  const labelHeight = Math.min(labelMaxHeight, availableSpaceHeight);
43
45
  if (!labelWidth || y > d.y1) {
@@ -7,6 +7,7 @@ export interface LabelData {
7
7
  size: {
8
8
  width: number;
9
9
  height: number;
10
+ hangingOffset?: number;
10
11
  };
11
12
  textAnchor: 'start' | 'end' | 'middle';
12
13
  series: {
@@ -45,7 +45,7 @@ export const AxisX = (props) => {
45
45
  .html((d) => d.text)
46
46
  .attr('x', (d) => d.x)
47
47
  .attr('y', (d) => d.y)
48
- .attr('dominant-baseline', 'text-before-edge')
48
+ .attr('dominant-baseline', 'hanging')
49
49
  .attr('text-anchor', 'start');
50
50
  }
51
51
  if (preparedAxisData.domain) {
@@ -98,7 +98,7 @@ export const AxisX = (props) => {
98
98
  .attr('y', (d) => d.y)
99
99
  .attr('text-anchor', 'start')
100
100
  .attr('class', labelClassName)
101
- .style('dominant-baseline', 'text-before-edge')
101
+ .style('dominant-baseline', 'hanging')
102
102
  .style('font-size', label.style.fontSize)
103
103
  .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '');
104
104
  }
@@ -134,7 +134,7 @@ export const AxisX = (props) => {
134
134
  .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '')
135
135
  .style('font-size', label.style.fontSize)
136
136
  .style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
137
- .style('dominant-baseline', 'text-before-edge')
137
+ .style('dominant-baseline', 'hanging')
138
138
  .style('text-anchor', 'start')
139
139
  .attr('transform', `translate(${label.x}, ${label.y}) rotate(${label.rotate})`)
140
140
  .attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null);
@@ -176,7 +176,7 @@ export const AxisX = (props) => {
176
176
  .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '')
177
177
  .style('font-size', label.style.fontSize)
178
178
  .style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
179
- .style('dominant-baseline', 'text-before-edge')
179
+ .style('dominant-baseline', 'hanging')
180
180
  .style('text-anchor', 'start')
181
181
  .attr('transform', `translate(${label.x}, ${label.y}) rotate(${label.rotate})`)
182
182
  .attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null);
@@ -1,5 +1,5 @@
1
1
  import { getUniqId } from '@gravity-ui/uikit';
2
- import { calculateSin, formatAxisTickLabel, getBandsPosition, getLabelsSize, getMinSpaceBetween, getTextSizeFn, getTextWithElipsis, } from '../../core/utils';
2
+ import { calculateCos, calculateSin, formatAxisTickLabel, getBandsPosition, getLabelsSize, getMinSpaceBetween, getTextSizeFn, getTextWithElipsis, } from '../../core/utils';
3
3
  import { getXAxisTickValues } from '../../core/utils/axis/x-axis';
4
4
  import { getMultilineTitleContentRows } from '../utils/axis-title';
5
5
  async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWidth, axisWidth, boundsOffsetLeft, boundsOffsetRight, }) {
@@ -56,7 +56,9 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
56
56
  x = left + actualTextWidth / 2 - xOffset;
57
57
  }
58
58
  const yOffset = rotation <= 0 ? textSize.width * calculateSin(a) : 0;
59
- const y = top + yOffset + axis.labels.margin;
59
+ const hOffset = textSize.hangingOffset;
60
+ const y = top + yOffset + axis.labels.margin + hOffset * calculateCos(rotation);
61
+ x -= hOffset * calculateSin(rotation);
60
62
  const svgLabel = {
61
63
  title: ((_a = content[0]) === null || _a === void 0 ? void 0 : _a.text) === text ? undefined : text,
62
64
  content,
@@ -69,7 +71,7 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
69
71
  return svgLabel;
70
72
  }
71
73
  export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRight, boundsWidth, height, scale, series, split, yAxis, }) {
72
- var _a, _b, _c, _d, _e, _f, _g;
74
+ var _a, _b, _c, _d, _e, _f, _g, _h;
73
75
  const xAxisItems = [];
74
76
  const splitPlots = (_a = split === null || split === void 0 ? void 0 : split.plots) !== null && _a !== void 0 ? _a : [];
75
77
  for (let plotIndex = 0; plotIndex < splitPlots.length; plotIndex++) {
@@ -201,7 +203,8 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
201
203
  const titleContent = [];
202
204
  const titleMaxWidth = axisWidth;
203
205
  if (axis.title.maxRowCount > 1) {
204
- titleContent.push(...(await getMultilineTitleContentRows({ axis, titleMaxWidth })));
206
+ const rows = await getMultilineTitleContentRows({ axis, titleMaxWidth });
207
+ titleContent.push(...rows);
205
208
  }
206
209
  else {
207
210
  const text = await getTextWithElipsis({
@@ -209,11 +212,12 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
209
212
  maxWidth: titleMaxWidth,
210
213
  getTextWidth: async (s) => (await getTitleTextSize(s)).width,
211
214
  });
215
+ const titleSize = await getTitleTextSize(text);
212
216
  titleContent.push({
213
217
  text,
214
218
  x: 0,
215
- y: 0,
216
- size: await getTitleTextSize(text),
219
+ y: titleSize.hangingOffset,
220
+ size: titleSize,
217
221
  });
218
222
  }
219
223
  const titleTextSize = titleContent.reduce((acc, item) => {
@@ -258,14 +262,14 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
258
262
  const halfBandwidth = ((_f = (_e = axisScale.bandwidth) === null || _e === void 0 ? void 0 : _e.call(axisScale)) !== null && _f !== void 0 ? _f : 0) / 2;
259
263
  const startPos = halfBandwidth + Math.min(from, to);
260
264
  const endPos = Math.min(Math.abs(to - from), axisWidth - Math.min(from, to));
261
- const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
262
- const labelSize = plotBand.label.text
263
- ? await getPlotLabelSize(plotBand.label.text)
264
- : null;
265
265
  const plotBandWidth = Math.min(endPos, axisWidth);
266
266
  if (plotBandWidth < 0) {
267
267
  continue;
268
268
  }
269
+ const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
270
+ const labelSize = plotBand.label.text
271
+ ? await getPlotLabelSize(plotBand.label.text)
272
+ : null;
269
273
  plotBands.push({
270
274
  layerPlacement: plotBand.layerPlacement,
271
275
  x: Math.max(0, startPos),
@@ -278,8 +282,8 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
278
282
  ? {
279
283
  text: plotBand.label.text,
280
284
  style: plotBand.label.style,
281
- x: plotBand.label.padding,
282
- y: plotBand.label.padding + ((_g = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _g !== void 0 ? _g : 0),
285
+ x: plotBand.label.padding + ((_g = labelSize === null || labelSize === void 0 ? void 0 : labelSize.hangingOffset) !== null && _g !== void 0 ? _g : 0),
286
+ y: plotBand.label.padding + ((_h = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _h !== void 0 ? _h : 0),
283
287
  rotate: -90,
284
288
  qa: plotBand.label.qa,
285
289
  }
@@ -305,7 +309,7 @@ export async function prepareXAxisData({ axis, boundsOffsetLeft, boundsOffsetRig
305
309
  label = {
306
310
  text: plotLine.label.text,
307
311
  style: plotLine.label.style,
308
- x: plotLineValue - plotLine.label.padding - size.height,
312
+ x: plotLineValue - plotLine.label.padding - size.height + size.hangingOffset,
309
313
  y: plotLine.label.padding + size.width,
310
314
  rotate: -90,
311
315
  qa: plotLine.label.qa,
@@ -50,7 +50,7 @@ export const AxisY = (props) => {
50
50
  .html((d) => d.text)
51
51
  .attr('x', (d) => d.x)
52
52
  .attr('y', (d) => d.y)
53
- .attr('dominant-baseline', 'text-after-edge')
53
+ .attr('dominant-baseline', 'hanging')
54
54
  .attr('text-anchor', 'start');
55
55
  }
56
56
  if (preparedAxisData.domain) {
@@ -103,7 +103,7 @@ export const AxisY = (props) => {
103
103
  .attr('y', (d) => d.y)
104
104
  .attr('text-anchor', 'start')
105
105
  .attr('class', labelClassName)
106
- .style('dominant-baseline', 'text-before-edge')
106
+ .style('dominant-baseline', 'hanging')
107
107
  .style('font-size', label.style.fontSize)
108
108
  .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '');
109
109
  }
@@ -139,7 +139,7 @@ export const AxisY = (props) => {
139
139
  .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '')
140
140
  .style('font-size', label.style.fontSize)
141
141
  .style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
142
- .style('dominant-baseline', 'text-before-edge')
142
+ .style('dominant-baseline', 'hanging')
143
143
  .attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null)
144
144
  .attr('x', label.x)
145
145
  .attr('y', label.y);
@@ -181,7 +181,7 @@ export const AxisY = (props) => {
181
181
  .style('fill', (_a = label.style.fontColor) !== null && _a !== void 0 ? _a : '')
182
182
  .style('font-size', label.style.fontSize)
183
183
  .style('font-weight', (_b = label.style.fontWeight) !== null && _b !== void 0 ? _b : '')
184
- .style('dominant-baseline', 'text-before-edge')
184
+ .style('dominant-baseline', 'hanging')
185
185
  .attr('data-qa', (_c = label.qa) !== null && _c !== void 0 ? _c : null)
186
186
  .attr('x', label.x)
187
187
  .attr('y', label.y);