@gravity-ui/charts 1.27.0 → 1.27.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/AxisX/prepare-axis-data.d.ts +5 -3
- package/dist/cjs/components/AxisX/prepare-axis-data.js +253 -210
- package/dist/cjs/components/ChartInner/index.js +7 -3
- package/dist/cjs/hooks/useAxis/x-axis.js +6 -4
- package/dist/cjs/hooks/useSplit/index.js +6 -2
- package/dist/esm/components/AxisX/prepare-axis-data.d.ts +5 -3
- package/dist/esm/components/AxisX/prepare-axis-data.js +253 -210
- package/dist/esm/components/ChartInner/index.js +7 -3
- package/dist/esm/hooks/useAxis/x-axis.js +6 -4
- package/dist/esm/hooks/useSplit/index.js +6 -2
- package/package.json +1 -1
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { ChartScale, PreparedAxis } from '../../hooks';
|
|
1
|
+
import type { ChartScale, PreparedAxis, PreparedSplit } from '../../hooks';
|
|
2
2
|
import type { AxisXData } from './types';
|
|
3
|
-
export declare function prepareXAxisData({ axis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, }: {
|
|
3
|
+
export declare function prepareXAxisData({ axis, yAxis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, split, }: {
|
|
4
4
|
axis: PreparedAxis;
|
|
5
|
+
yAxis: PreparedAxis[];
|
|
5
6
|
scale: ChartScale;
|
|
6
7
|
boundsWidth: number;
|
|
7
8
|
boundsOffsetLeft: number;
|
|
8
9
|
boundsOffsetRight: number;
|
|
9
10
|
height: number;
|
|
10
|
-
|
|
11
|
+
split: PreparedSplit;
|
|
12
|
+
}): Promise<AxisXData[]>;
|
|
@@ -8,13 +8,22 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
|
|
|
8
8
|
let rowText = text;
|
|
9
9
|
let textSize = await getTextSize(text);
|
|
10
10
|
const a = (360 + rotation) % 90;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
let textMaxWidth = Infinity;
|
|
12
|
+
if (a === 0) {
|
|
13
|
+
textMaxWidth = Math.min(labelMaxWidth,
|
|
13
14
|
// rightmost label
|
|
14
|
-
labelMaxWidth / 2 + axisWidth + boundsOffsetRight - left)
|
|
15
|
-
|
|
15
|
+
labelMaxWidth / 2 + axisWidth + boundsOffsetRight - left);
|
|
16
|
+
}
|
|
17
|
+
else if (rotation > 0) {
|
|
18
|
+
textMaxWidth = Math.min(axis.labels.height / calculateSin(a) - textSize.height * calculateSin(90 - a),
|
|
19
|
+
// rightmost label
|
|
20
|
+
(axisWidth - left) / calculateSin(a));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
textMaxWidth = Math.min(axis.labels.height / calculateSin(a) - textSize.height * calculateSin(90 - a),
|
|
16
24
|
// leftmostLabel
|
|
17
25
|
(boundsOffsetLeft + left) / calculateSin(a));
|
|
26
|
+
}
|
|
18
27
|
if (textSize.width > textMaxWidth) {
|
|
19
28
|
rowText = await getTextWithElipsis({
|
|
20
29
|
text: rowText,
|
|
@@ -23,245 +32,279 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
|
|
|
23
32
|
});
|
|
24
33
|
textSize = await getTextSize(rowText);
|
|
25
34
|
}
|
|
26
|
-
const actualTextWidth = a
|
|
27
|
-
? textSize.width * calculateSin(90 - a) + textSize.height * calculateSin(a)
|
|
28
|
-
: textSize.width;
|
|
29
|
-
const xOffset = a ? (textSize.width * calculateSin(90 - a)) / 2 : 0;
|
|
30
|
-
const yOffset = textSize.width * calculateSin(a);
|
|
31
35
|
content.push({
|
|
32
36
|
text: rowText,
|
|
33
37
|
x: 0,
|
|
34
38
|
y: 0,
|
|
35
39
|
size: textSize,
|
|
36
40
|
});
|
|
37
|
-
const
|
|
41
|
+
const actualTextWidth = a
|
|
42
|
+
? textSize.width * calculateSin(90 - a) + textSize.height * calculateSin(a)
|
|
43
|
+
: textSize.width;
|
|
44
|
+
let x = 0;
|
|
45
|
+
if (rotation === 0) {
|
|
46
|
+
x = Math.min(left - actualTextWidth / 2, axisWidth - actualTextWidth);
|
|
47
|
+
}
|
|
48
|
+
else if (rotation < 0) {
|
|
49
|
+
const xOffset = (textSize.width * calculateSin(90 - a)) / 2;
|
|
50
|
+
x = left - actualTextWidth / 2 - xOffset;
|
|
51
|
+
x = Math.min(x, axisWidth - actualTextWidth);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const xOffset = (textSize.width * calculateSin(90 - a)) / 2;
|
|
55
|
+
x = left + actualTextWidth / 2 - xOffset;
|
|
56
|
+
}
|
|
57
|
+
const yOffset = rotation <= 0 ? textSize.width * calculateSin(a) : 0;
|
|
38
58
|
const y = top + yOffset + axis.labels.margin;
|
|
39
59
|
const svgLabel = {
|
|
40
60
|
title: ((_a = content[0]) === null || _a === void 0 ? void 0 : _a.text) === text ? undefined : text,
|
|
41
61
|
content,
|
|
42
62
|
style: axis.labels.style,
|
|
43
63
|
size: textSize,
|
|
44
|
-
x,
|
|
64
|
+
x: Math.max(-boundsOffsetLeft, x),
|
|
45
65
|
y,
|
|
46
66
|
angle: rotation,
|
|
47
67
|
};
|
|
48
68
|
return svgLabel;
|
|
49
69
|
}
|
|
50
70
|
// eslint-disable-next-line complexity
|
|
51
|
-
export async function prepareXAxisData({ axis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, }) {
|
|
52
|
-
var _a, _b, _c, _d;
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, split, }) {
|
|
72
|
+
var _a, _b, _c, _d, _e, _f;
|
|
73
|
+
const xAxisItems = [];
|
|
74
|
+
for (let plotIndex = 0; plotIndex < split.plots.length; plotIndex++) {
|
|
75
|
+
const plot = split.plots[plotIndex];
|
|
76
|
+
const axisTop = plot.top;
|
|
77
|
+
const axisHeight = plot.height;
|
|
78
|
+
const axisWidth = boundsWidth;
|
|
79
|
+
const isBottomPlot = plotIndex === split.plots.length - 1;
|
|
80
|
+
const plotYAxes = yAxis.filter((a) => a.plotIndex === plotIndex);
|
|
81
|
+
const yDomainLeftPosition = ((_a = plotYAxes.find((a) => a.position === 'left')) === null || _a === void 0 ? void 0 : _a.visible)
|
|
82
|
+
? 0
|
|
83
|
+
: null;
|
|
84
|
+
const yDomainRightPosition = ((_b = plotYAxes.find((a) => a.position === 'right')) === null || _b === void 0 ? void 0 : _b.visible)
|
|
85
|
+
? axisWidth
|
|
86
|
+
: null;
|
|
87
|
+
let domain = null;
|
|
88
|
+
if (isBottomPlot && axis.visible) {
|
|
89
|
+
domain = {
|
|
90
|
+
start: [0, axisTop + axisHeight],
|
|
91
|
+
end: [axisWidth, axisTop + axisHeight],
|
|
92
|
+
lineColor: (_c = axis.lineColor) !== null && _c !== void 0 ? _c : '',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const ticks = [];
|
|
96
|
+
const getTextSize = getTextSizeFn({ style: axis.labels.style });
|
|
97
|
+
const labelLineHeight = (await getTextSize('Tmp')).height;
|
|
98
|
+
const values = getXAxisTickValues({ scale, axis, labelLineHeight });
|
|
99
|
+
const tickStep = getMinSpaceBetween(values, (d) => Number(d.value));
|
|
100
|
+
const labelMaxWidth = values.length > 1
|
|
101
|
+
? Math.abs(values[0].x - values[1].x) - axis.labels.padding * 2
|
|
102
|
+
: axisWidth;
|
|
103
|
+
for (let i = 0; i < values.length; i++) {
|
|
104
|
+
const tickValue = values[i];
|
|
105
|
+
let svgLabel = null;
|
|
106
|
+
let htmlLabel = null;
|
|
107
|
+
if (isBottomPlot && axis.labels.enabled) {
|
|
108
|
+
if (axis.labels.html) {
|
|
109
|
+
const content = String(tickValue.value);
|
|
110
|
+
const labelSize = await getLabelsSize({
|
|
111
|
+
labels: [content],
|
|
112
|
+
html: true,
|
|
113
|
+
style: axis.labels.style,
|
|
114
|
+
});
|
|
115
|
+
const size = { width: labelSize.maxWidth, height: labelSize.maxHeight };
|
|
116
|
+
htmlLabel = {
|
|
117
|
+
content,
|
|
118
|
+
x: tickValue.x - size.width / 2,
|
|
119
|
+
y: height + axis.labels.margin,
|
|
120
|
+
size,
|
|
121
|
+
style: axis.labels.style,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const text = formatAxisTickLabel({
|
|
126
|
+
value: tickValue.value,
|
|
127
|
+
axis,
|
|
128
|
+
step: tickStep,
|
|
129
|
+
});
|
|
130
|
+
svgLabel = await getSvgAxisLabel({
|
|
131
|
+
getTextSize,
|
|
132
|
+
text,
|
|
133
|
+
axis,
|
|
134
|
+
top: height,
|
|
135
|
+
left: tickValue.x,
|
|
136
|
+
labelMaxWidth,
|
|
137
|
+
axisWidth,
|
|
138
|
+
boundsOffsetLeft,
|
|
139
|
+
boundsOffsetRight,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
91
142
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
boundsOffsetLeft,
|
|
103
|
-
boundsOffsetRight,
|
|
104
|
-
});
|
|
143
|
+
let tickLine = null;
|
|
144
|
+
if (axis.grid.enabled &&
|
|
145
|
+
tickValue.x !== yDomainLeftPosition &&
|
|
146
|
+
tickValue.x !== yDomainRightPosition) {
|
|
147
|
+
tickLine = {
|
|
148
|
+
points: [
|
|
149
|
+
[tickValue.x, axisTop],
|
|
150
|
+
[tickValue.x, axisTop + axisHeight],
|
|
151
|
+
],
|
|
152
|
+
};
|
|
105
153
|
}
|
|
154
|
+
ticks.push({
|
|
155
|
+
line: tickLine,
|
|
156
|
+
svgLabel,
|
|
157
|
+
htmlLabel,
|
|
158
|
+
});
|
|
106
159
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
160
|
+
let title = null;
|
|
161
|
+
if (axis.title.text) {
|
|
162
|
+
const getTitleTextSize = getTextSizeFn({ style: axis.title.style });
|
|
163
|
+
const titleContent = [];
|
|
164
|
+
const titleMaxWidth = axisWidth;
|
|
165
|
+
if (axis.title.maxRowCount > 1) {
|
|
166
|
+
const titleTextRows = await wrapText({
|
|
167
|
+
text: axis.title.text,
|
|
168
|
+
style: axis.title.style,
|
|
169
|
+
width: titleMaxWidth,
|
|
170
|
+
getTextSize: getTitleTextSize,
|
|
171
|
+
});
|
|
172
|
+
for (let i = 0; i < axis.title.maxRowCount && i < titleTextRows.length; i++) {
|
|
173
|
+
const textRow = titleTextRows[i];
|
|
174
|
+
const textRowContent = textRow.text.trim();
|
|
175
|
+
const textRowSize = await getTitleTextSize(textRowContent);
|
|
176
|
+
titleContent.push({
|
|
177
|
+
text: textRowContent,
|
|
178
|
+
x: 0,
|
|
179
|
+
y: textRow.y,
|
|
180
|
+
size: textRowSize,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
113
183
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
let title = null;
|
|
122
|
-
if (axis.title.text) {
|
|
123
|
-
const getTitleTextSize = getTextSizeFn({ style: axis.title.style });
|
|
124
|
-
const titleContent = [];
|
|
125
|
-
const titleMaxWidth = axisWidth;
|
|
126
|
-
if (axis.title.maxRowCount > 1) {
|
|
127
|
-
const titleTextRows = await wrapText({
|
|
128
|
-
text: axis.title.text,
|
|
129
|
-
style: axis.title.style,
|
|
130
|
-
width: titleMaxWidth,
|
|
131
|
-
getTextSize: getTitleTextSize,
|
|
132
|
-
});
|
|
133
|
-
for (let i = 0; i < axis.title.maxRowCount && i < titleTextRows.length; i++) {
|
|
134
|
-
const textRow = titleTextRows[i];
|
|
135
|
-
const textRowContent = textRow.text.trim();
|
|
136
|
-
const textRowSize = await getTitleTextSize(textRowContent);
|
|
184
|
+
else {
|
|
185
|
+
const text = await getTextWithElipsis({
|
|
186
|
+
text: axis.title.text,
|
|
187
|
+
maxWidth: titleMaxWidth,
|
|
188
|
+
getTextWidth: async (s) => (await getTitleTextSize(s)).width,
|
|
189
|
+
});
|
|
137
190
|
titleContent.push({
|
|
138
|
-
text
|
|
191
|
+
text,
|
|
139
192
|
x: 0,
|
|
140
|
-
y:
|
|
141
|
-
size:
|
|
193
|
+
y: 0,
|
|
194
|
+
size: await getTitleTextSize(text),
|
|
142
195
|
});
|
|
143
196
|
}
|
|
197
|
+
const titleTextSize = titleContent.reduce((acc, item) => {
|
|
198
|
+
acc.width = Math.max(acc.width, item.size.width);
|
|
199
|
+
acc.height += item.size.height;
|
|
200
|
+
return acc;
|
|
201
|
+
}, { width: 0, height: 0 });
|
|
202
|
+
let x = 0;
|
|
203
|
+
switch (axis.title.align) {
|
|
204
|
+
case 'left': {
|
|
205
|
+
x = 0;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case 'center': {
|
|
209
|
+
x = Math.max(axisWidth / 2 - titleTextSize.width / 2);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
case 'right': {
|
|
213
|
+
x = Math.max(0, axisWidth - titleTextSize.width);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
title = {
|
|
218
|
+
content: titleContent,
|
|
219
|
+
style: axis.title.style,
|
|
220
|
+
size: titleTextSize,
|
|
221
|
+
x,
|
|
222
|
+
y: height +
|
|
223
|
+
axis.labels.margin +
|
|
224
|
+
axis.labels.height +
|
|
225
|
+
axis.title.margin +
|
|
226
|
+
titleTextSize.height,
|
|
227
|
+
rotate: 0,
|
|
228
|
+
offset: 0,
|
|
229
|
+
};
|
|
144
230
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
231
|
+
const plotBands = [];
|
|
232
|
+
for (let i = 0; i < axis.plotBands.length; i++) {
|
|
233
|
+
const plotBand = axis.plotBands[i];
|
|
234
|
+
const axisScale = scale;
|
|
235
|
+
const { from, to } = getBandsPosition({
|
|
236
|
+
band: plotBand,
|
|
237
|
+
axisScale,
|
|
238
|
+
axis: 'x',
|
|
150
239
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
240
|
+
const halfBandwidth = ((_e = (_d = axisScale.bandwidth) === null || _d === void 0 ? void 0 : _d.call(axisScale)) !== null && _e !== void 0 ? _e : 0) / 2;
|
|
241
|
+
const startPos = halfBandwidth + Math.min(from, to);
|
|
242
|
+
const endPos = Math.min(Math.abs(to - from), axisWidth - Math.min(from, to));
|
|
243
|
+
const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
|
|
244
|
+
const labelSize = plotBand.label.text
|
|
245
|
+
? await getPlotLabelSize(plotBand.label.text)
|
|
246
|
+
: null;
|
|
247
|
+
plotBands.push({
|
|
248
|
+
layerPlacement: plotBand.layerPlacement,
|
|
249
|
+
x: Math.max(0, startPos),
|
|
154
250
|
y: 0,
|
|
155
|
-
|
|
251
|
+
width: Math.min(endPos, axisWidth),
|
|
252
|
+
height: axisHeight,
|
|
253
|
+
color: plotBand.color,
|
|
254
|
+
opacity: plotBand.opacity,
|
|
255
|
+
label: plotBand.label.text
|
|
256
|
+
? {
|
|
257
|
+
text: plotBand.label.text,
|
|
258
|
+
style: plotBand.label.style,
|
|
259
|
+
x: plotBand.label.padding,
|
|
260
|
+
y: plotBand.label.padding + ((_f = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _f !== void 0 ? _f : 0),
|
|
261
|
+
rotate: -90,
|
|
262
|
+
}
|
|
263
|
+
: null,
|
|
156
264
|
});
|
|
157
265
|
}
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
title = {
|
|
179
|
-
content: titleContent,
|
|
180
|
-
style: axis.title.style,
|
|
181
|
-
size: titleTextSize,
|
|
182
|
-
x,
|
|
183
|
-
y: height +
|
|
184
|
-
axis.labels.margin +
|
|
185
|
-
axis.labels.height +
|
|
186
|
-
axis.title.margin +
|
|
187
|
-
titleTextSize.height,
|
|
188
|
-
rotate: 0,
|
|
189
|
-
offset: 0,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
const plotBands = [];
|
|
193
|
-
for (let i = 0; i < axis.plotBands.length; i++) {
|
|
194
|
-
const plotBand = axis.plotBands[i];
|
|
195
|
-
const axisScale = scale;
|
|
196
|
-
const { from, to } = getBandsPosition({
|
|
197
|
-
band: plotBand,
|
|
198
|
-
axisScale,
|
|
199
|
-
axis: 'x',
|
|
200
|
-
});
|
|
201
|
-
const halfBandwidth = ((_c = (_b = axisScale.bandwidth) === null || _b === void 0 ? void 0 : _b.call(axisScale)) !== null && _c !== void 0 ? _c : 0) / 2;
|
|
202
|
-
const startPos = halfBandwidth + Math.min(from, to);
|
|
203
|
-
const endPos = Math.min(Math.abs(to - from), axisWidth - Math.min(from, to));
|
|
204
|
-
const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
|
|
205
|
-
const labelSize = plotBand.label.text ? await getPlotLabelSize(plotBand.label.text) : null;
|
|
206
|
-
plotBands.push({
|
|
207
|
-
layerPlacement: plotBand.layerPlacement,
|
|
208
|
-
x: Math.max(0, startPos),
|
|
209
|
-
y: 0,
|
|
210
|
-
width: Math.min(endPos, axisWidth),
|
|
211
|
-
height: axisHeight,
|
|
212
|
-
color: plotBand.color,
|
|
213
|
-
opacity: plotBand.opacity,
|
|
214
|
-
label: plotBand.label.text
|
|
215
|
-
? {
|
|
216
|
-
text: plotBand.label.text,
|
|
217
|
-
style: plotBand.label.style,
|
|
218
|
-
x: plotBand.label.padding,
|
|
219
|
-
y: plotBand.label.padding + ((_d = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _d !== void 0 ? _d : 0),
|
|
266
|
+
const plotLines = [];
|
|
267
|
+
for (let i = 0; i < axis.plotLines.length; i++) {
|
|
268
|
+
const plotLine = axis.plotLines[i];
|
|
269
|
+
const axisScale = scale;
|
|
270
|
+
const plotLineValue = Number(axisScale(plotLine.value));
|
|
271
|
+
const points = [
|
|
272
|
+
[plotLineValue, 0],
|
|
273
|
+
[plotLineValue, axisHeight],
|
|
274
|
+
];
|
|
275
|
+
let label = null;
|
|
276
|
+
if (plotLine.label.text) {
|
|
277
|
+
const getTitleTextSize = getTextSizeFn({ style: plotLine.label.style });
|
|
278
|
+
const size = await getTitleTextSize(plotLine.label.text);
|
|
279
|
+
label = {
|
|
280
|
+
text: plotLine.label.text,
|
|
281
|
+
style: plotLine.label.style,
|
|
282
|
+
x: plotLineValue - plotLine.label.padding - size.height,
|
|
283
|
+
y: plotLine.label.padding + size.width,
|
|
220
284
|
rotate: -90,
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (plotLine.label.text) {
|
|
236
|
-
const getTitleTextSize = getTextSizeFn({ style: plotLine.label.style });
|
|
237
|
-
const size = await getTitleTextSize(plotLine.label.text);
|
|
238
|
-
label = {
|
|
239
|
-
text: plotLine.label.text,
|
|
240
|
-
style: plotLine.label.style,
|
|
241
|
-
x: plotLineValue - plotLine.label.padding - size.height,
|
|
242
|
-
y: plotLine.label.padding + size.width,
|
|
243
|
-
rotate: -90,
|
|
244
|
-
};
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
plotLines.push({
|
|
288
|
+
layerPlacement: plotLine.layerPlacement,
|
|
289
|
+
x: 0,
|
|
290
|
+
y: 0,
|
|
291
|
+
width: axisWidth,
|
|
292
|
+
color: plotLine.color,
|
|
293
|
+
opacity: plotLine.opacity,
|
|
294
|
+
label,
|
|
295
|
+
points,
|
|
296
|
+
lineWidth: plotLine.width,
|
|
297
|
+
dashStyle: plotLine.dashStyle,
|
|
298
|
+
});
|
|
245
299
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
label,
|
|
254
|
-
points,
|
|
255
|
-
lineWidth: plotLine.width,
|
|
256
|
-
dashStyle: plotLine.dashStyle,
|
|
300
|
+
xAxisItems.push({
|
|
301
|
+
id: getUniqId(),
|
|
302
|
+
title,
|
|
303
|
+
ticks,
|
|
304
|
+
domain,
|
|
305
|
+
plotBands,
|
|
306
|
+
plotLines,
|
|
257
307
|
});
|
|
258
308
|
}
|
|
259
|
-
return
|
|
260
|
-
id: getUniqId(),
|
|
261
|
-
title,
|
|
262
|
-
ticks,
|
|
263
|
-
domain,
|
|
264
|
-
plotBands,
|
|
265
|
-
plotLines,
|
|
266
|
-
};
|
|
309
|
+
return xAxisItems;
|
|
267
310
|
}
|
|
@@ -158,16 +158,18 @@ export const ChartInner = (props) => {
|
|
|
158
158
|
if (axis && scale) {
|
|
159
159
|
const axisData = await prepareXAxisData({
|
|
160
160
|
axis,
|
|
161
|
+
yAxis,
|
|
161
162
|
scale,
|
|
162
163
|
boundsWidth,
|
|
163
164
|
boundsOffsetLeft: boundsOffsetLeft,
|
|
164
165
|
boundsOffsetRight: width - boundsWidth - boundsOffsetLeft,
|
|
165
166
|
height: boundsHeight,
|
|
167
|
+
split: preparedSplit,
|
|
166
168
|
});
|
|
167
|
-
items.push(axisData);
|
|
169
|
+
items.push(...axisData);
|
|
168
170
|
}
|
|
169
171
|
return items;
|
|
170
|
-
}, [
|
|
172
|
+
}, [xAxis, xScale, yAxis, boundsWidth, boundsOffsetLeft, width, boundsHeight, preparedSplit]);
|
|
171
173
|
const xAxisDataItems = useAsyncState([], setXAxisDataItems);
|
|
172
174
|
React.useEffect(() => {
|
|
173
175
|
if (!initialized && xScale) {
|
|
@@ -200,7 +202,9 @@ export const ChartInner = (props) => {
|
|
|
200
202
|
return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
|
|
201
203
|
})),
|
|
202
204
|
React.createElement("g", { className: b('content'), width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
|
|
203
|
-
xScale && xAxisDataItems.length && (React.createElement(
|
|
205
|
+
xScale && xAxisDataItems.length && (React.createElement(React.Fragment, null, xAxisDataItems.map((axisData) => {
|
|
206
|
+
return (React.createElement(AxisX, { key: axisData.id, htmlLayout: htmlLayout, plotAfterRef: plotAfterRef, plotBeforeRef: plotBeforeRef, preparedAxisData: axisData }));
|
|
207
|
+
}))),
|
|
204
208
|
Boolean(yAxisDataItems.length) && (React.createElement(React.Fragment, null, yAxisDataItems.map((axisData, index) => {
|
|
205
209
|
if (!axisData) {
|
|
206
210
|
return null;
|
|
@@ -5,7 +5,8 @@ import { getXAxisTickValues } from '../../utils/chart/axis/x-axis';
|
|
|
5
5
|
import { createXScale } from '../useAxisScales';
|
|
6
6
|
import { getPreparedRangeSlider } from './range-slider';
|
|
7
7
|
import { prepareAxisPlotLabel } from './utils';
|
|
8
|
-
async function setLabelSettings({ axis, seriesData, width,
|
|
8
|
+
async function setLabelSettings({ axis, seriesData, width, axisLabels, }) {
|
|
9
|
+
var _a, _b;
|
|
9
10
|
const scale = createXScale({ axis, series: seriesData, boundsWidth: width });
|
|
10
11
|
if (!scale) {
|
|
11
12
|
axis.labels.height = 0;
|
|
@@ -36,9 +37,10 @@ async function setLabelSettings({ axis, seriesData, width, autoRotation = true,
|
|
|
36
37
|
}
|
|
37
38
|
return false;
|
|
38
39
|
};
|
|
40
|
+
const autoRotation = (_a = axisLabels === null || axisLabels === void 0 ? void 0 : axisLabels.autoRotation) !== null && _a !== void 0 ? _a : true;
|
|
39
41
|
const overlapping = axis.labels.html ? false : await hasOverlappingLabels();
|
|
40
42
|
const defaultRotation = overlapping && autoRotation ? -45 : 0;
|
|
41
|
-
const rotation = axis.labels.html ? 0 :
|
|
43
|
+
const rotation = axis.labels.html ? 0 : ((_b = axisLabels === null || axisLabels === void 0 ? void 0 : axisLabels.rotation) !== null && _b !== void 0 ? _b : defaultRotation);
|
|
42
44
|
const labelsHeight = rotation || axis.labels.html
|
|
43
45
|
? (await getLabelsSize({
|
|
44
46
|
labels,
|
|
@@ -58,7 +60,7 @@ function getMaxPaddingBySeries({ series }) {
|
|
|
58
60
|
return 0.01;
|
|
59
61
|
}
|
|
60
62
|
export const getPreparedXAxis = async ({ xAxis, seriesData, width, boundsWidth, }) => {
|
|
61
|
-
var _a, _b, _c, _d
|
|
63
|
+
var _a, _b, _c, _d;
|
|
62
64
|
const hasAxisRelatedSeries = seriesData.some(isAxisRelatedSeries);
|
|
63
65
|
if (!hasAxisRelatedSeries) {
|
|
64
66
|
return Promise.resolve(null);
|
|
@@ -168,7 +170,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, boundsWidth,
|
|
|
168
170
|
axis: preparedXAxis,
|
|
169
171
|
seriesData,
|
|
170
172
|
width: boundsWidth,
|
|
171
|
-
|
|
173
|
+
axisLabels: xAxis === null || xAxis === void 0 ? void 0 : xAxis.labels,
|
|
172
174
|
});
|
|
173
175
|
return preparedXAxis;
|
|
174
176
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import get from 'lodash/get';
|
|
3
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
4
|
import { calculateNumericProperty, getHorizontalSvgTextHeight } from '../../utils';
|
|
4
5
|
const DEFAULT_TITLE_FONT_SIZE = '15px';
|
|
5
6
|
const TITLE_TOP_BOTTOM_PADDING = 8;
|
|
@@ -34,10 +35,13 @@ export function getPlotHeight(args) {
|
|
|
34
35
|
export const useSplit = (args) => {
|
|
35
36
|
const { split, boundsHeight, chartWidth } = args;
|
|
36
37
|
return React.useMemo(() => {
|
|
37
|
-
var _a;
|
|
38
|
+
var _a, _b;
|
|
38
39
|
const splitGap = (_a = calculateNumericProperty({ value: split === null || split === void 0 ? void 0 : split.gap, base: boundsHeight })) !== null && _a !== void 0 ? _a : 0;
|
|
39
40
|
const plotHeight = getPlotHeight({ split: split, boundsHeight, gap: splitGap });
|
|
40
|
-
const plots = (split === null || split === void 0 ? void 0 : split.plots)
|
|
41
|
+
const plots = (_b = split === null || split === void 0 ? void 0 : split.plots) !== null && _b !== void 0 ? _b : [];
|
|
42
|
+
if (isEmpty(plots)) {
|
|
43
|
+
plots.push({});
|
|
44
|
+
}
|
|
41
45
|
return {
|
|
42
46
|
plots: plots.map((p, index) => {
|
|
43
47
|
const title = preparePlotTitle({
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import type { ChartScale, PreparedAxis } from '../../hooks';
|
|
1
|
+
import type { ChartScale, PreparedAxis, PreparedSplit } from '../../hooks';
|
|
2
2
|
import type { AxisXData } from './types';
|
|
3
|
-
export declare function prepareXAxisData({ axis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, }: {
|
|
3
|
+
export declare function prepareXAxisData({ axis, yAxis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, split, }: {
|
|
4
4
|
axis: PreparedAxis;
|
|
5
|
+
yAxis: PreparedAxis[];
|
|
5
6
|
scale: ChartScale;
|
|
6
7
|
boundsWidth: number;
|
|
7
8
|
boundsOffsetLeft: number;
|
|
8
9
|
boundsOffsetRight: number;
|
|
9
10
|
height: number;
|
|
10
|
-
|
|
11
|
+
split: PreparedSplit;
|
|
12
|
+
}): Promise<AxisXData[]>;
|
|
@@ -8,13 +8,22 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
|
|
|
8
8
|
let rowText = text;
|
|
9
9
|
let textSize = await getTextSize(text);
|
|
10
10
|
const a = (360 + rotation) % 90;
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
let textMaxWidth = Infinity;
|
|
12
|
+
if (a === 0) {
|
|
13
|
+
textMaxWidth = Math.min(labelMaxWidth,
|
|
13
14
|
// rightmost label
|
|
14
|
-
labelMaxWidth / 2 + axisWidth + boundsOffsetRight - left)
|
|
15
|
-
|
|
15
|
+
labelMaxWidth / 2 + axisWidth + boundsOffsetRight - left);
|
|
16
|
+
}
|
|
17
|
+
else if (rotation > 0) {
|
|
18
|
+
textMaxWidth = Math.min(axis.labels.height / calculateSin(a) - textSize.height * calculateSin(90 - a),
|
|
19
|
+
// rightmost label
|
|
20
|
+
(axisWidth - left) / calculateSin(a));
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
textMaxWidth = Math.min(axis.labels.height / calculateSin(a) - textSize.height * calculateSin(90 - a),
|
|
16
24
|
// leftmostLabel
|
|
17
25
|
(boundsOffsetLeft + left) / calculateSin(a));
|
|
26
|
+
}
|
|
18
27
|
if (textSize.width > textMaxWidth) {
|
|
19
28
|
rowText = await getTextWithElipsis({
|
|
20
29
|
text: rowText,
|
|
@@ -23,245 +32,279 @@ async function getSvgAxisLabel({ getTextSize, text, axis, top, left, labelMaxWid
|
|
|
23
32
|
});
|
|
24
33
|
textSize = await getTextSize(rowText);
|
|
25
34
|
}
|
|
26
|
-
const actualTextWidth = a
|
|
27
|
-
? textSize.width * calculateSin(90 - a) + textSize.height * calculateSin(a)
|
|
28
|
-
: textSize.width;
|
|
29
|
-
const xOffset = a ? (textSize.width * calculateSin(90 - a)) / 2 : 0;
|
|
30
|
-
const yOffset = textSize.width * calculateSin(a);
|
|
31
35
|
content.push({
|
|
32
36
|
text: rowText,
|
|
33
37
|
x: 0,
|
|
34
38
|
y: 0,
|
|
35
39
|
size: textSize,
|
|
36
40
|
});
|
|
37
|
-
const
|
|
41
|
+
const actualTextWidth = a
|
|
42
|
+
? textSize.width * calculateSin(90 - a) + textSize.height * calculateSin(a)
|
|
43
|
+
: textSize.width;
|
|
44
|
+
let x = 0;
|
|
45
|
+
if (rotation === 0) {
|
|
46
|
+
x = Math.min(left - actualTextWidth / 2, axisWidth - actualTextWidth);
|
|
47
|
+
}
|
|
48
|
+
else if (rotation < 0) {
|
|
49
|
+
const xOffset = (textSize.width * calculateSin(90 - a)) / 2;
|
|
50
|
+
x = left - actualTextWidth / 2 - xOffset;
|
|
51
|
+
x = Math.min(x, axisWidth - actualTextWidth);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
const xOffset = (textSize.width * calculateSin(90 - a)) / 2;
|
|
55
|
+
x = left + actualTextWidth / 2 - xOffset;
|
|
56
|
+
}
|
|
57
|
+
const yOffset = rotation <= 0 ? textSize.width * calculateSin(a) : 0;
|
|
38
58
|
const y = top + yOffset + axis.labels.margin;
|
|
39
59
|
const svgLabel = {
|
|
40
60
|
title: ((_a = content[0]) === null || _a === void 0 ? void 0 : _a.text) === text ? undefined : text,
|
|
41
61
|
content,
|
|
42
62
|
style: axis.labels.style,
|
|
43
63
|
size: textSize,
|
|
44
|
-
x,
|
|
64
|
+
x: Math.max(-boundsOffsetLeft, x),
|
|
45
65
|
y,
|
|
46
66
|
angle: rotation,
|
|
47
67
|
};
|
|
48
68
|
return svgLabel;
|
|
49
69
|
}
|
|
50
70
|
// eslint-disable-next-line complexity
|
|
51
|
-
export async function prepareXAxisData({ axis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, }) {
|
|
52
|
-
var _a, _b, _c, _d;
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
71
|
+
export async function prepareXAxisData({ axis, yAxis, scale, boundsWidth, boundsOffsetLeft, boundsOffsetRight, height, split, }) {
|
|
72
|
+
var _a, _b, _c, _d, _e, _f;
|
|
73
|
+
const xAxisItems = [];
|
|
74
|
+
for (let plotIndex = 0; plotIndex < split.plots.length; plotIndex++) {
|
|
75
|
+
const plot = split.plots[plotIndex];
|
|
76
|
+
const axisTop = plot.top;
|
|
77
|
+
const axisHeight = plot.height;
|
|
78
|
+
const axisWidth = boundsWidth;
|
|
79
|
+
const isBottomPlot = plotIndex === split.plots.length - 1;
|
|
80
|
+
const plotYAxes = yAxis.filter((a) => a.plotIndex === plotIndex);
|
|
81
|
+
const yDomainLeftPosition = ((_a = plotYAxes.find((a) => a.position === 'left')) === null || _a === void 0 ? void 0 : _a.visible)
|
|
82
|
+
? 0
|
|
83
|
+
: null;
|
|
84
|
+
const yDomainRightPosition = ((_b = plotYAxes.find((a) => a.position === 'right')) === null || _b === void 0 ? void 0 : _b.visible)
|
|
85
|
+
? axisWidth
|
|
86
|
+
: null;
|
|
87
|
+
let domain = null;
|
|
88
|
+
if (isBottomPlot && axis.visible) {
|
|
89
|
+
domain = {
|
|
90
|
+
start: [0, axisTop + axisHeight],
|
|
91
|
+
end: [axisWidth, axisTop + axisHeight],
|
|
92
|
+
lineColor: (_c = axis.lineColor) !== null && _c !== void 0 ? _c : '',
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const ticks = [];
|
|
96
|
+
const getTextSize = getTextSizeFn({ style: axis.labels.style });
|
|
97
|
+
const labelLineHeight = (await getTextSize('Tmp')).height;
|
|
98
|
+
const values = getXAxisTickValues({ scale, axis, labelLineHeight });
|
|
99
|
+
const tickStep = getMinSpaceBetween(values, (d) => Number(d.value));
|
|
100
|
+
const labelMaxWidth = values.length > 1
|
|
101
|
+
? Math.abs(values[0].x - values[1].x) - axis.labels.padding * 2
|
|
102
|
+
: axisWidth;
|
|
103
|
+
for (let i = 0; i < values.length; i++) {
|
|
104
|
+
const tickValue = values[i];
|
|
105
|
+
let svgLabel = null;
|
|
106
|
+
let htmlLabel = null;
|
|
107
|
+
if (isBottomPlot && axis.labels.enabled) {
|
|
108
|
+
if (axis.labels.html) {
|
|
109
|
+
const content = String(tickValue.value);
|
|
110
|
+
const labelSize = await getLabelsSize({
|
|
111
|
+
labels: [content],
|
|
112
|
+
html: true,
|
|
113
|
+
style: axis.labels.style,
|
|
114
|
+
});
|
|
115
|
+
const size = { width: labelSize.maxWidth, height: labelSize.maxHeight };
|
|
116
|
+
htmlLabel = {
|
|
117
|
+
content,
|
|
118
|
+
x: tickValue.x - size.width / 2,
|
|
119
|
+
y: height + axis.labels.margin,
|
|
120
|
+
size,
|
|
121
|
+
style: axis.labels.style,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
const text = formatAxisTickLabel({
|
|
126
|
+
value: tickValue.value,
|
|
127
|
+
axis,
|
|
128
|
+
step: tickStep,
|
|
129
|
+
});
|
|
130
|
+
svgLabel = await getSvgAxisLabel({
|
|
131
|
+
getTextSize,
|
|
132
|
+
text,
|
|
133
|
+
axis,
|
|
134
|
+
top: height,
|
|
135
|
+
left: tickValue.x,
|
|
136
|
+
labelMaxWidth,
|
|
137
|
+
axisWidth,
|
|
138
|
+
boundsOffsetLeft,
|
|
139
|
+
boundsOffsetRight,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
91
142
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
boundsOffsetLeft,
|
|
103
|
-
boundsOffsetRight,
|
|
104
|
-
});
|
|
143
|
+
let tickLine = null;
|
|
144
|
+
if (axis.grid.enabled &&
|
|
145
|
+
tickValue.x !== yDomainLeftPosition &&
|
|
146
|
+
tickValue.x !== yDomainRightPosition) {
|
|
147
|
+
tickLine = {
|
|
148
|
+
points: [
|
|
149
|
+
[tickValue.x, axisTop],
|
|
150
|
+
[tickValue.x, axisTop + axisHeight],
|
|
151
|
+
],
|
|
152
|
+
};
|
|
105
153
|
}
|
|
154
|
+
ticks.push({
|
|
155
|
+
line: tickLine,
|
|
156
|
+
svgLabel,
|
|
157
|
+
htmlLabel,
|
|
158
|
+
});
|
|
106
159
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
160
|
+
let title = null;
|
|
161
|
+
if (axis.title.text) {
|
|
162
|
+
const getTitleTextSize = getTextSizeFn({ style: axis.title.style });
|
|
163
|
+
const titleContent = [];
|
|
164
|
+
const titleMaxWidth = axisWidth;
|
|
165
|
+
if (axis.title.maxRowCount > 1) {
|
|
166
|
+
const titleTextRows = await wrapText({
|
|
167
|
+
text: axis.title.text,
|
|
168
|
+
style: axis.title.style,
|
|
169
|
+
width: titleMaxWidth,
|
|
170
|
+
getTextSize: getTitleTextSize,
|
|
171
|
+
});
|
|
172
|
+
for (let i = 0; i < axis.title.maxRowCount && i < titleTextRows.length; i++) {
|
|
173
|
+
const textRow = titleTextRows[i];
|
|
174
|
+
const textRowContent = textRow.text.trim();
|
|
175
|
+
const textRowSize = await getTitleTextSize(textRowContent);
|
|
176
|
+
titleContent.push({
|
|
177
|
+
text: textRowContent,
|
|
178
|
+
x: 0,
|
|
179
|
+
y: textRow.y,
|
|
180
|
+
size: textRowSize,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
113
183
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
121
|
-
let title = null;
|
|
122
|
-
if (axis.title.text) {
|
|
123
|
-
const getTitleTextSize = getTextSizeFn({ style: axis.title.style });
|
|
124
|
-
const titleContent = [];
|
|
125
|
-
const titleMaxWidth = axisWidth;
|
|
126
|
-
if (axis.title.maxRowCount > 1) {
|
|
127
|
-
const titleTextRows = await wrapText({
|
|
128
|
-
text: axis.title.text,
|
|
129
|
-
style: axis.title.style,
|
|
130
|
-
width: titleMaxWidth,
|
|
131
|
-
getTextSize: getTitleTextSize,
|
|
132
|
-
});
|
|
133
|
-
for (let i = 0; i < axis.title.maxRowCount && i < titleTextRows.length; i++) {
|
|
134
|
-
const textRow = titleTextRows[i];
|
|
135
|
-
const textRowContent = textRow.text.trim();
|
|
136
|
-
const textRowSize = await getTitleTextSize(textRowContent);
|
|
184
|
+
else {
|
|
185
|
+
const text = await getTextWithElipsis({
|
|
186
|
+
text: axis.title.text,
|
|
187
|
+
maxWidth: titleMaxWidth,
|
|
188
|
+
getTextWidth: async (s) => (await getTitleTextSize(s)).width,
|
|
189
|
+
});
|
|
137
190
|
titleContent.push({
|
|
138
|
-
text
|
|
191
|
+
text,
|
|
139
192
|
x: 0,
|
|
140
|
-
y:
|
|
141
|
-
size:
|
|
193
|
+
y: 0,
|
|
194
|
+
size: await getTitleTextSize(text),
|
|
142
195
|
});
|
|
143
196
|
}
|
|
197
|
+
const titleTextSize = titleContent.reduce((acc, item) => {
|
|
198
|
+
acc.width = Math.max(acc.width, item.size.width);
|
|
199
|
+
acc.height += item.size.height;
|
|
200
|
+
return acc;
|
|
201
|
+
}, { width: 0, height: 0 });
|
|
202
|
+
let x = 0;
|
|
203
|
+
switch (axis.title.align) {
|
|
204
|
+
case 'left': {
|
|
205
|
+
x = 0;
|
|
206
|
+
break;
|
|
207
|
+
}
|
|
208
|
+
case 'center': {
|
|
209
|
+
x = Math.max(axisWidth / 2 - titleTextSize.width / 2);
|
|
210
|
+
break;
|
|
211
|
+
}
|
|
212
|
+
case 'right': {
|
|
213
|
+
x = Math.max(0, axisWidth - titleTextSize.width);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
title = {
|
|
218
|
+
content: titleContent,
|
|
219
|
+
style: axis.title.style,
|
|
220
|
+
size: titleTextSize,
|
|
221
|
+
x,
|
|
222
|
+
y: height +
|
|
223
|
+
axis.labels.margin +
|
|
224
|
+
axis.labels.height +
|
|
225
|
+
axis.title.margin +
|
|
226
|
+
titleTextSize.height,
|
|
227
|
+
rotate: 0,
|
|
228
|
+
offset: 0,
|
|
229
|
+
};
|
|
144
230
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
231
|
+
const plotBands = [];
|
|
232
|
+
for (let i = 0; i < axis.plotBands.length; i++) {
|
|
233
|
+
const plotBand = axis.plotBands[i];
|
|
234
|
+
const axisScale = scale;
|
|
235
|
+
const { from, to } = getBandsPosition({
|
|
236
|
+
band: plotBand,
|
|
237
|
+
axisScale,
|
|
238
|
+
axis: 'x',
|
|
150
239
|
});
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
240
|
+
const halfBandwidth = ((_e = (_d = axisScale.bandwidth) === null || _d === void 0 ? void 0 : _d.call(axisScale)) !== null && _e !== void 0 ? _e : 0) / 2;
|
|
241
|
+
const startPos = halfBandwidth + Math.min(from, to);
|
|
242
|
+
const endPos = Math.min(Math.abs(to - from), axisWidth - Math.min(from, to));
|
|
243
|
+
const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
|
|
244
|
+
const labelSize = plotBand.label.text
|
|
245
|
+
? await getPlotLabelSize(plotBand.label.text)
|
|
246
|
+
: null;
|
|
247
|
+
plotBands.push({
|
|
248
|
+
layerPlacement: plotBand.layerPlacement,
|
|
249
|
+
x: Math.max(0, startPos),
|
|
154
250
|
y: 0,
|
|
155
|
-
|
|
251
|
+
width: Math.min(endPos, axisWidth),
|
|
252
|
+
height: axisHeight,
|
|
253
|
+
color: plotBand.color,
|
|
254
|
+
opacity: plotBand.opacity,
|
|
255
|
+
label: plotBand.label.text
|
|
256
|
+
? {
|
|
257
|
+
text: plotBand.label.text,
|
|
258
|
+
style: plotBand.label.style,
|
|
259
|
+
x: plotBand.label.padding,
|
|
260
|
+
y: plotBand.label.padding + ((_f = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _f !== void 0 ? _f : 0),
|
|
261
|
+
rotate: -90,
|
|
262
|
+
}
|
|
263
|
+
: null,
|
|
156
264
|
});
|
|
157
265
|
}
|
|
158
|
-
const
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
title = {
|
|
179
|
-
content: titleContent,
|
|
180
|
-
style: axis.title.style,
|
|
181
|
-
size: titleTextSize,
|
|
182
|
-
x,
|
|
183
|
-
y: height +
|
|
184
|
-
axis.labels.margin +
|
|
185
|
-
axis.labels.height +
|
|
186
|
-
axis.title.margin +
|
|
187
|
-
titleTextSize.height,
|
|
188
|
-
rotate: 0,
|
|
189
|
-
offset: 0,
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
const plotBands = [];
|
|
193
|
-
for (let i = 0; i < axis.plotBands.length; i++) {
|
|
194
|
-
const plotBand = axis.plotBands[i];
|
|
195
|
-
const axisScale = scale;
|
|
196
|
-
const { from, to } = getBandsPosition({
|
|
197
|
-
band: plotBand,
|
|
198
|
-
axisScale,
|
|
199
|
-
axis: 'x',
|
|
200
|
-
});
|
|
201
|
-
const halfBandwidth = ((_c = (_b = axisScale.bandwidth) === null || _b === void 0 ? void 0 : _b.call(axisScale)) !== null && _c !== void 0 ? _c : 0) / 2;
|
|
202
|
-
const startPos = halfBandwidth + Math.min(from, to);
|
|
203
|
-
const endPos = Math.min(Math.abs(to - from), axisWidth - Math.min(from, to));
|
|
204
|
-
const getPlotLabelSize = getTextSizeFn({ style: plotBand.label.style });
|
|
205
|
-
const labelSize = plotBand.label.text ? await getPlotLabelSize(plotBand.label.text) : null;
|
|
206
|
-
plotBands.push({
|
|
207
|
-
layerPlacement: plotBand.layerPlacement,
|
|
208
|
-
x: Math.max(0, startPos),
|
|
209
|
-
y: 0,
|
|
210
|
-
width: Math.min(endPos, axisWidth),
|
|
211
|
-
height: axisHeight,
|
|
212
|
-
color: plotBand.color,
|
|
213
|
-
opacity: plotBand.opacity,
|
|
214
|
-
label: plotBand.label.text
|
|
215
|
-
? {
|
|
216
|
-
text: plotBand.label.text,
|
|
217
|
-
style: plotBand.label.style,
|
|
218
|
-
x: plotBand.label.padding,
|
|
219
|
-
y: plotBand.label.padding + ((_d = labelSize === null || labelSize === void 0 ? void 0 : labelSize.width) !== null && _d !== void 0 ? _d : 0),
|
|
266
|
+
const plotLines = [];
|
|
267
|
+
for (let i = 0; i < axis.plotLines.length; i++) {
|
|
268
|
+
const plotLine = axis.plotLines[i];
|
|
269
|
+
const axisScale = scale;
|
|
270
|
+
const plotLineValue = Number(axisScale(plotLine.value));
|
|
271
|
+
const points = [
|
|
272
|
+
[plotLineValue, 0],
|
|
273
|
+
[plotLineValue, axisHeight],
|
|
274
|
+
];
|
|
275
|
+
let label = null;
|
|
276
|
+
if (plotLine.label.text) {
|
|
277
|
+
const getTitleTextSize = getTextSizeFn({ style: plotLine.label.style });
|
|
278
|
+
const size = await getTitleTextSize(plotLine.label.text);
|
|
279
|
+
label = {
|
|
280
|
+
text: plotLine.label.text,
|
|
281
|
+
style: plotLine.label.style,
|
|
282
|
+
x: plotLineValue - plotLine.label.padding - size.height,
|
|
283
|
+
y: plotLine.label.padding + size.width,
|
|
220
284
|
rotate: -90,
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
if (plotLine.label.text) {
|
|
236
|
-
const getTitleTextSize = getTextSizeFn({ style: plotLine.label.style });
|
|
237
|
-
const size = await getTitleTextSize(plotLine.label.text);
|
|
238
|
-
label = {
|
|
239
|
-
text: plotLine.label.text,
|
|
240
|
-
style: plotLine.label.style,
|
|
241
|
-
x: plotLineValue - plotLine.label.padding - size.height,
|
|
242
|
-
y: plotLine.label.padding + size.width,
|
|
243
|
-
rotate: -90,
|
|
244
|
-
};
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
plotLines.push({
|
|
288
|
+
layerPlacement: plotLine.layerPlacement,
|
|
289
|
+
x: 0,
|
|
290
|
+
y: 0,
|
|
291
|
+
width: axisWidth,
|
|
292
|
+
color: plotLine.color,
|
|
293
|
+
opacity: plotLine.opacity,
|
|
294
|
+
label,
|
|
295
|
+
points,
|
|
296
|
+
lineWidth: plotLine.width,
|
|
297
|
+
dashStyle: plotLine.dashStyle,
|
|
298
|
+
});
|
|
245
299
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
label,
|
|
254
|
-
points,
|
|
255
|
-
lineWidth: plotLine.width,
|
|
256
|
-
dashStyle: plotLine.dashStyle,
|
|
300
|
+
xAxisItems.push({
|
|
301
|
+
id: getUniqId(),
|
|
302
|
+
title,
|
|
303
|
+
ticks,
|
|
304
|
+
domain,
|
|
305
|
+
plotBands,
|
|
306
|
+
plotLines,
|
|
257
307
|
});
|
|
258
308
|
}
|
|
259
|
-
return
|
|
260
|
-
id: getUniqId(),
|
|
261
|
-
title,
|
|
262
|
-
ticks,
|
|
263
|
-
domain,
|
|
264
|
-
plotBands,
|
|
265
|
-
plotLines,
|
|
266
|
-
};
|
|
309
|
+
return xAxisItems;
|
|
267
310
|
}
|
|
@@ -158,16 +158,18 @@ export const ChartInner = (props) => {
|
|
|
158
158
|
if (axis && scale) {
|
|
159
159
|
const axisData = await prepareXAxisData({
|
|
160
160
|
axis,
|
|
161
|
+
yAxis,
|
|
161
162
|
scale,
|
|
162
163
|
boundsWidth,
|
|
163
164
|
boundsOffsetLeft: boundsOffsetLeft,
|
|
164
165
|
boundsOffsetRight: width - boundsWidth - boundsOffsetLeft,
|
|
165
166
|
height: boundsHeight,
|
|
167
|
+
split: preparedSplit,
|
|
166
168
|
});
|
|
167
|
-
items.push(axisData);
|
|
169
|
+
items.push(...axisData);
|
|
168
170
|
}
|
|
169
171
|
return items;
|
|
170
|
-
}, [
|
|
172
|
+
}, [xAxis, xScale, yAxis, boundsWidth, boundsOffsetLeft, width, boundsHeight, preparedSplit]);
|
|
171
173
|
const xAxisDataItems = useAsyncState([], setXAxisDataItems);
|
|
172
174
|
React.useEffect(() => {
|
|
173
175
|
if (!initialized && xScale) {
|
|
@@ -200,7 +202,9 @@ export const ChartInner = (props) => {
|
|
|
200
202
|
return React.createElement(PlotTitle, { key: `plot-${index}`, title: plot.title });
|
|
201
203
|
})),
|
|
202
204
|
React.createElement("g", { className: b('content'), width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
|
|
203
|
-
xScale && xAxisDataItems.length && (React.createElement(
|
|
205
|
+
xScale && xAxisDataItems.length && (React.createElement(React.Fragment, null, xAxisDataItems.map((axisData) => {
|
|
206
|
+
return (React.createElement(AxisX, { key: axisData.id, htmlLayout: htmlLayout, plotAfterRef: plotAfterRef, plotBeforeRef: plotBeforeRef, preparedAxisData: axisData }));
|
|
207
|
+
}))),
|
|
204
208
|
Boolean(yAxisDataItems.length) && (React.createElement(React.Fragment, null, yAxisDataItems.map((axisData, index) => {
|
|
205
209
|
if (!axisData) {
|
|
206
210
|
return null;
|
|
@@ -5,7 +5,8 @@ import { getXAxisTickValues } from '../../utils/chart/axis/x-axis';
|
|
|
5
5
|
import { createXScale } from '../useAxisScales';
|
|
6
6
|
import { getPreparedRangeSlider } from './range-slider';
|
|
7
7
|
import { prepareAxisPlotLabel } from './utils';
|
|
8
|
-
async function setLabelSettings({ axis, seriesData, width,
|
|
8
|
+
async function setLabelSettings({ axis, seriesData, width, axisLabels, }) {
|
|
9
|
+
var _a, _b;
|
|
9
10
|
const scale = createXScale({ axis, series: seriesData, boundsWidth: width });
|
|
10
11
|
if (!scale) {
|
|
11
12
|
axis.labels.height = 0;
|
|
@@ -36,9 +37,10 @@ async function setLabelSettings({ axis, seriesData, width, autoRotation = true,
|
|
|
36
37
|
}
|
|
37
38
|
return false;
|
|
38
39
|
};
|
|
40
|
+
const autoRotation = (_a = axisLabels === null || axisLabels === void 0 ? void 0 : axisLabels.autoRotation) !== null && _a !== void 0 ? _a : true;
|
|
39
41
|
const overlapping = axis.labels.html ? false : await hasOverlappingLabels();
|
|
40
42
|
const defaultRotation = overlapping && autoRotation ? -45 : 0;
|
|
41
|
-
const rotation = axis.labels.html ? 0 :
|
|
43
|
+
const rotation = axis.labels.html ? 0 : ((_b = axisLabels === null || axisLabels === void 0 ? void 0 : axisLabels.rotation) !== null && _b !== void 0 ? _b : defaultRotation);
|
|
42
44
|
const labelsHeight = rotation || axis.labels.html
|
|
43
45
|
? (await getLabelsSize({
|
|
44
46
|
labels,
|
|
@@ -58,7 +60,7 @@ function getMaxPaddingBySeries({ series }) {
|
|
|
58
60
|
return 0.01;
|
|
59
61
|
}
|
|
60
62
|
export const getPreparedXAxis = async ({ xAxis, seriesData, width, boundsWidth, }) => {
|
|
61
|
-
var _a, _b, _c, _d
|
|
63
|
+
var _a, _b, _c, _d;
|
|
62
64
|
const hasAxisRelatedSeries = seriesData.some(isAxisRelatedSeries);
|
|
63
65
|
if (!hasAxisRelatedSeries) {
|
|
64
66
|
return Promise.resolve(null);
|
|
@@ -168,7 +170,7 @@ export const getPreparedXAxis = async ({ xAxis, seriesData, width, boundsWidth,
|
|
|
168
170
|
axis: preparedXAxis,
|
|
169
171
|
seriesData,
|
|
170
172
|
width: boundsWidth,
|
|
171
|
-
|
|
173
|
+
axisLabels: xAxis === null || xAxis === void 0 ? void 0 : xAxis.labels,
|
|
172
174
|
});
|
|
173
175
|
return preparedXAxis;
|
|
174
176
|
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import get from 'lodash/get';
|
|
3
|
+
import isEmpty from 'lodash/isEmpty';
|
|
3
4
|
import { calculateNumericProperty, getHorizontalSvgTextHeight } from '../../utils';
|
|
4
5
|
const DEFAULT_TITLE_FONT_SIZE = '15px';
|
|
5
6
|
const TITLE_TOP_BOTTOM_PADDING = 8;
|
|
@@ -34,10 +35,13 @@ export function getPlotHeight(args) {
|
|
|
34
35
|
export const useSplit = (args) => {
|
|
35
36
|
const { split, boundsHeight, chartWidth } = args;
|
|
36
37
|
return React.useMemo(() => {
|
|
37
|
-
var _a;
|
|
38
|
+
var _a, _b;
|
|
38
39
|
const splitGap = (_a = calculateNumericProperty({ value: split === null || split === void 0 ? void 0 : split.gap, base: boundsHeight })) !== null && _a !== void 0 ? _a : 0;
|
|
39
40
|
const plotHeight = getPlotHeight({ split: split, boundsHeight, gap: splitGap });
|
|
40
|
-
const plots = (split === null || split === void 0 ? void 0 : split.plots)
|
|
41
|
+
const plots = (_b = split === null || split === void 0 ? void 0 : split.plots) !== null && _b !== void 0 ? _b : [];
|
|
42
|
+
if (isEmpty(plots)) {
|
|
43
|
+
plots.push({});
|
|
44
|
+
}
|
|
41
45
|
return {
|
|
42
46
|
plots: plots.map((p, index) => {
|
|
43
47
|
const title = preparePlotTitle({
|