@gravity-ui/charts 1.42.3 → 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.
- package/dist/cjs/components/AxisX/AxisX.js +4 -4
- package/dist/cjs/components/AxisX/prepare-axis-data.js +17 -13
- package/dist/cjs/components/AxisY/AxisY.js +4 -4
- package/dist/cjs/components/AxisY/prepare-axis-data.js +27 -21
- package/dist/cjs/components/AxisY/prepare-axis-title.js +8 -3
- package/dist/cjs/components/AxisY/styles.css +1 -1
- package/dist/cjs/components/ChartInner/index.js +5 -15
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +4 -1
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +22 -11
- package/dist/cjs/components/ChartInner/utils/title.d.ts +1 -1
- package/dist/cjs/components/ChartInner/utils/title.js +3 -3
- package/dist/cjs/components/Legend/index.js +8 -11
- package/dist/cjs/components/Legend/styles.css +1 -1
- package/dist/cjs/components/utils/axis-title.js +1 -1
- package/dist/cjs/core/axes/x-axis.js +2 -2
- package/dist/cjs/core/axes/y-axis.js +2 -2
- package/dist/cjs/core/layout/split.d.ts +2 -2
- package/dist/cjs/core/layout/split.js +22 -19
- package/dist/cjs/core/series/prepare-legend.js +7 -7
- package/dist/cjs/core/series/types.d.ts +2 -0
- package/dist/cjs/core/utils/axis-generators/bottom.js +6 -16
- package/dist/cjs/core/utils/common.d.ts +0 -4
- package/dist/cjs/core/utils/common.js +0 -13
- package/dist/cjs/core/utils/labels.d.ts +1 -0
- package/dist/cjs/core/utils/labels.js +5 -5
- package/dist/cjs/core/utils/text.d.ts +1 -0
- package/dist/cjs/core/utils/text.js +4 -0
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +1 -1
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +3 -2
- package/dist/cjs/hooks/useShapes/funnel/prepare-data.js +4 -1
- package/dist/cjs/hooks/useShapes/heatmap/prepare-data.js +1 -1
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +4 -1
- package/dist/cjs/hooks/useShapes/pie/prepare-data.js +9 -2
- package/dist/cjs/hooks/useShapes/radar/prepare-data.js +17 -7
- package/dist/cjs/hooks/useShapes/sankey/prepare-data.js +1 -1
- package/dist/cjs/hooks/useShapes/sankey/sankey-layout.d.ts +49 -0
- package/dist/cjs/hooks/useShapes/sankey/sankey-layout.js +362 -0
- package/dist/cjs/hooks/useShapes/styles.css +4 -4
- package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +3 -1
- package/dist/cjs/types/chart-ui.d.ts +1 -0
- package/dist/esm/components/AxisX/AxisX.js +4 -4
- package/dist/esm/components/AxisX/prepare-axis-data.js +17 -13
- package/dist/esm/components/AxisY/AxisY.js +4 -4
- package/dist/esm/components/AxisY/prepare-axis-data.js +27 -21
- package/dist/esm/components/AxisY/prepare-axis-title.js +8 -3
- package/dist/esm/components/AxisY/styles.css +1 -1
- package/dist/esm/components/ChartInner/index.js +5 -15
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +4 -1
- package/dist/esm/components/ChartInner/useChartInnerProps.js +22 -11
- package/dist/esm/components/ChartInner/utils/title.d.ts +1 -1
- package/dist/esm/components/ChartInner/utils/title.js +3 -3
- package/dist/esm/components/Legend/index.js +8 -11
- package/dist/esm/components/Legend/styles.css +1 -1
- package/dist/esm/components/utils/axis-title.js +1 -1
- package/dist/esm/core/axes/x-axis.js +2 -2
- package/dist/esm/core/axes/y-axis.js +2 -2
- package/dist/esm/core/layout/split.d.ts +2 -2
- package/dist/esm/core/layout/split.js +22 -19
- package/dist/esm/core/series/prepare-legend.js +7 -7
- package/dist/esm/core/series/types.d.ts +2 -0
- package/dist/esm/core/utils/axis-generators/bottom.js +6 -16
- package/dist/esm/core/utils/common.d.ts +0 -4
- package/dist/esm/core/utils/common.js +0 -13
- package/dist/esm/core/utils/labels.d.ts +1 -0
- package/dist/esm/core/utils/labels.js +5 -5
- package/dist/esm/core/utils/text.d.ts +1 -0
- package/dist/esm/core/utils/text.js +4 -0
- package/dist/esm/hooks/useShapes/area/prepare-data.js +1 -1
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +3 -2
- package/dist/esm/hooks/useShapes/funnel/prepare-data.js +4 -1
- package/dist/esm/hooks/useShapes/heatmap/prepare-data.js +1 -1
- package/dist/esm/hooks/useShapes/line/prepare-data.js +4 -1
- package/dist/esm/hooks/useShapes/pie/prepare-data.js +9 -2
- package/dist/esm/hooks/useShapes/radar/prepare-data.js +17 -7
- package/dist/esm/hooks/useShapes/sankey/prepare-data.js +1 -1
- package/dist/esm/hooks/useShapes/sankey/sankey-layout.d.ts +49 -0
- package/dist/esm/hooks/useShapes/sankey/sankey-layout.js +362 -0
- package/dist/esm/hooks/useShapes/styles.css +4 -4
- package/dist/esm/hooks/useShapes/treemap/prepare-data.js +3 -1
- package/dist/esm/types/chart-ui.d.ts +1 -0
- 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:
|
|
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:
|
|
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:
|
|
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:
|
|
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) {
|
|
@@ -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', '
|
|
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', '
|
|
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', '
|
|
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', '
|
|
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
|
|
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
|
-
|
|
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:
|
|
216
|
-
size:
|
|
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 + ((
|
|
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', '
|
|
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', '
|
|
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', '
|
|
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', '
|
|
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);
|