@gravity-ui/charts 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/components/Axis/AxisX.js +42 -5
- package/dist/cjs/components/Axis/AxisY.d.ts +1 -1
- package/dist/cjs/components/Axis/AxisY.js +48 -5
- package/dist/cjs/components/ChartInner/index.js +1 -1
- package/dist/cjs/components/ChartInner/styles.css +2 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +3 -3
- package/dist/cjs/components/Legend/index.js +22 -10
- package/dist/cjs/components/Title/index.js +1 -1
- package/dist/cjs/constants/defaults/legend.d.ts +1 -0
- package/dist/cjs/constants/defaults/legend.js +1 -0
- package/dist/cjs/hooks/useChartOptions/types.d.ts +5 -3
- package/dist/cjs/hooks/useChartOptions/x-axis.js +7 -0
- package/dist/cjs/hooks/useChartOptions/y-axis.js +12 -1
- package/dist/cjs/hooks/useSeries/prepare-legend.js +1 -0
- package/dist/cjs/hooks/useShapes/HtmlLayer.js +2 -1
- package/dist/cjs/hooks/useShapes/area/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/line/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/pie/index.js +1 -1
- package/dist/cjs/hooks/useShapes/pie/prepare-data.js +11 -6
- package/dist/cjs/hooks/useShapes/radar/prepare-data.js +1 -0
- package/dist/cjs/hooks/useShapes/treemap/index.js +1 -1
- package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +14 -8
- package/dist/cjs/i18n/keysets/en.json +3 -1
- package/dist/cjs/i18n/keysets/ru.json +3 -1
- package/dist/cjs/libs/chart-error/index.d.ts +1 -0
- package/dist/cjs/libs/chart-error/index.js +1 -0
- package/dist/cjs/types/chart/axis.d.ts +30 -7
- package/dist/cjs/types/chart/legend.d.ts +6 -0
- package/dist/cjs/types/chart-ui.d.ts +1 -0
- package/dist/cjs/utils/chart/axis.d.ts +12 -1
- package/dist/cjs/utils/chart/axis.js +35 -0
- package/dist/cjs/utils/chart/index.d.ts +2 -1
- package/dist/cjs/utils/chart/types.d.ts +1 -0
- package/dist/cjs/utils/chart/types.js +1 -0
- package/dist/cjs/validation/index.js +144 -0
- package/dist/esm/components/Axis/AxisX.js +42 -5
- package/dist/esm/components/Axis/AxisY.d.ts +1 -1
- package/dist/esm/components/Axis/AxisY.js +48 -5
- package/dist/esm/components/ChartInner/index.js +1 -1
- package/dist/esm/components/ChartInner/styles.css +2 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.js +3 -3
- package/dist/esm/components/Legend/index.js +22 -10
- package/dist/esm/components/Title/index.js +1 -1
- package/dist/esm/constants/defaults/legend.d.ts +1 -0
- package/dist/esm/constants/defaults/legend.js +1 -0
- package/dist/esm/hooks/useChartOptions/types.d.ts +5 -3
- package/dist/esm/hooks/useChartOptions/x-axis.js +7 -0
- package/dist/esm/hooks/useChartOptions/y-axis.js +12 -1
- package/dist/esm/hooks/useSeries/prepare-legend.js +1 -0
- package/dist/esm/hooks/useShapes/HtmlLayer.js +2 -1
- package/dist/esm/hooks/useShapes/area/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/line/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/pie/index.js +1 -1
- package/dist/esm/hooks/useShapes/pie/prepare-data.js +11 -6
- package/dist/esm/hooks/useShapes/radar/prepare-data.js +1 -0
- package/dist/esm/hooks/useShapes/treemap/index.js +1 -1
- package/dist/esm/hooks/useShapes/treemap/prepare-data.js +14 -8
- package/dist/esm/i18n/keysets/en.json +3 -1
- package/dist/esm/i18n/keysets/ru.json +3 -1
- package/dist/esm/libs/chart-error/index.d.ts +1 -0
- package/dist/esm/libs/chart-error/index.js +1 -0
- package/dist/esm/types/chart/axis.d.ts +30 -7
- package/dist/esm/types/chart/legend.d.ts +6 -0
- package/dist/esm/types/chart-ui.d.ts +1 -0
- package/dist/esm/utils/chart/axis.d.ts +12 -1
- package/dist/esm/utils/chart/axis.js +35 -0
- package/dist/esm/utils/chart/index.d.ts +2 -1
- package/dist/esm/utils/chart/types.d.ts +1 -0
- package/dist/esm/utils/chart/types.js +1 -0
- package/dist/esm/validation/index.js +144 -0
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { line, select } from 'd3';
|
|
3
|
-
import { block, formatAxisTickLabel, getAxisTitleRows, getClosestPointsRange, getLineDashArray, getMaxTickCount, getScaleTicks, getTicksCount, handleOverflowingText, } from '../../utils';
|
|
3
|
+
import { block, formatAxisTickLabel, getAxisTitleRows, getBandsPosition, getClosestPointsRange, getLineDashArray, getMaxTickCount, getScaleTicks, getTicksCount, handleOverflowingText, } from '../../utils';
|
|
4
4
|
import { axisBottom } from '../../utils/chart/axis-generators';
|
|
5
5
|
import './styles.css';
|
|
6
6
|
const b = block('axis');
|
|
@@ -114,14 +114,51 @@ export const AxisX = React.memo(function AxisX(props) {
|
|
|
114
114
|
}
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
|
+
// add plot bands
|
|
118
|
+
if (plotContainer && axis.plotBands.length > 0) {
|
|
119
|
+
const plotBandClassName = b('plot-x-band');
|
|
120
|
+
const plotBandsSelection = plotContainer
|
|
121
|
+
.selectAll(`.${plotBandClassName}-x`)
|
|
122
|
+
.data(axis.plotBands)
|
|
123
|
+
.join('g')
|
|
124
|
+
.attr('class', `${plotClassName} ${plotBandClassName}-x`);
|
|
125
|
+
plotBandsSelection
|
|
126
|
+
.append('rect')
|
|
127
|
+
.attr('x', (band) => {
|
|
128
|
+
var _a, _b;
|
|
129
|
+
const { from, to } = getBandsPosition({ band, axisScale, axis: 'x' });
|
|
130
|
+
const halfBandwidth = ((_b = (_a = axisScale.bandwidth) === null || _a === void 0 ? void 0 : _a.call(axisScale)) !== null && _b !== void 0 ? _b : 0) / 2;
|
|
131
|
+
const startPos = halfBandwidth + Math.min(from, to);
|
|
132
|
+
return Math.max(0, startPos);
|
|
133
|
+
})
|
|
134
|
+
.attr('width', (band) => {
|
|
135
|
+
const { from, to } = getBandsPosition({ band, axisScale, axis: 'x' });
|
|
136
|
+
const startPos = width - Math.min(from, to);
|
|
137
|
+
const endPos = Math.min(Math.abs(to - from), startPos);
|
|
138
|
+
return Math.min(endPos, width);
|
|
139
|
+
})
|
|
140
|
+
.attr('y', 0)
|
|
141
|
+
.attr('height', totalHeight)
|
|
142
|
+
.attr('fill', (band) => band.color)
|
|
143
|
+
.attr('opacity', (band) => band.opacity);
|
|
144
|
+
plotBandsSelection.each((plotBandData, i, nodes) => {
|
|
145
|
+
const plotLineSelection = select(nodes[i]);
|
|
146
|
+
if (plotBandData.layerPlacement === 'before') {
|
|
147
|
+
plotLineSelection.lower();
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
plotLineSelection.raise();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
117
154
|
// add plot lines
|
|
118
155
|
if (plotContainer && axis.plotLines.length > 0) {
|
|
119
|
-
const plotLineClassName = b('
|
|
156
|
+
const plotLineClassName = b('plot-x-line');
|
|
120
157
|
const plotLinesSelection = plotContainer
|
|
121
|
-
.selectAll(`.${plotLineClassName}
|
|
158
|
+
.selectAll(`.${plotLineClassName}`)
|
|
122
159
|
.data(axis.plotLines)
|
|
123
160
|
.join('g')
|
|
124
|
-
.attr('class', `${plotClassName} ${plotLineClassName}
|
|
161
|
+
.attr('class', `${plotClassName} ${plotLineClassName}`);
|
|
125
162
|
const lineGenerator = line();
|
|
126
163
|
plotLinesSelection
|
|
127
164
|
.append('path')
|
|
@@ -148,6 +185,6 @@ export const AxisX = React.memo(function AxisX(props) {
|
|
|
148
185
|
}
|
|
149
186
|
});
|
|
150
187
|
}
|
|
151
|
-
}, [axis, width, totalHeight, scale, split, plotRef]);
|
|
188
|
+
}, [axis, width, totalHeight, scale, split, plotRef, leftmostLimit]);
|
|
152
189
|
return React.createElement("g", { ref: ref });
|
|
153
190
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { axisLeft, axisRight, line, select } from 'd3';
|
|
3
|
-
import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getClosestPointsRange, getLineDashArray, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
|
|
3
|
+
import { block, calculateCos, calculateSin, formatAxisTickLabel, getAxisHeight, getAxisTitleRows, getBandsPosition, getClosestPointsRange, getLineDashArray, getScaleTicks, getTicksCount, handleOverflowingText, parseTransformStyle, setEllipsisForOverflowTexts, wrapText, } from '../../utils';
|
|
4
4
|
import './styles.css';
|
|
5
5
|
const b = block('axis');
|
|
6
6
|
function transformLabel(args) {
|
|
@@ -85,7 +85,7 @@ function getTitlePosition(args) {
|
|
|
85
85
|
return { x, y };
|
|
86
86
|
}
|
|
87
87
|
export const AxisY = (props) => {
|
|
88
|
-
const { axes: allAxes, width, height: totalHeight, scale, split, plotRef,
|
|
88
|
+
const { axes: allAxes, width, height: totalHeight, scale, split, plotRef, bottomLimit = 0, } = props;
|
|
89
89
|
const height = getAxisHeight({ split, boundsHeight: totalHeight });
|
|
90
90
|
const ref = React.useRef(null);
|
|
91
91
|
const lineGenerator = line();
|
|
@@ -118,6 +118,12 @@ export const AxisY = (props) => {
|
|
|
118
118
|
}
|
|
119
119
|
return acc;
|
|
120
120
|
}, []);
|
|
121
|
+
const plotBands = axes.reduce((acc, axis) => {
|
|
122
|
+
if (axis.plotBands.length) {
|
|
123
|
+
acc.push(...axis.plotBands.map((plotBand) => (Object.assign(Object.assign({}, plotBand), { transform: getAxisPosition(axis) }))));
|
|
124
|
+
}
|
|
125
|
+
return acc;
|
|
126
|
+
}, []);
|
|
121
127
|
const axisSelection = svgElement
|
|
122
128
|
.selectAll('axis')
|
|
123
129
|
.data(axes)
|
|
@@ -153,7 +159,7 @@ export const AxisY = (props) => {
|
|
|
153
159
|
const currentElement = this;
|
|
154
160
|
const currentElementPosition = currentElement.getBoundingClientRect();
|
|
155
161
|
const text = select(currentElement);
|
|
156
|
-
if (currentElementPosition.bottom >
|
|
162
|
+
if (currentElementPosition.bottom > bottomLimit) {
|
|
157
163
|
const transform = transformLabel({
|
|
158
164
|
node: this,
|
|
159
165
|
axis: d,
|
|
@@ -190,8 +196,45 @@ export const AxisY = (props) => {
|
|
|
190
196
|
})
|
|
191
197
|
.remove();
|
|
192
198
|
}
|
|
199
|
+
if (plotContainer && d.plotBands.length > 0) {
|
|
200
|
+
const plotBandClassName = b('plot-y-band');
|
|
201
|
+
const plotBandsSelection = plotContainer
|
|
202
|
+
.selectAll(`.${plotBandClassName}`)
|
|
203
|
+
.data(plotBands)
|
|
204
|
+
.join('g')
|
|
205
|
+
.attr('class', `${plotClassName} ${plotBandClassName}`)
|
|
206
|
+
.style('transform', (plotBand) => plotBand.transform);
|
|
207
|
+
plotBandsSelection
|
|
208
|
+
.append('rect')
|
|
209
|
+
.attr('x', 0)
|
|
210
|
+
.attr('width', width)
|
|
211
|
+
.attr('y', (band) => {
|
|
212
|
+
var _a, _b;
|
|
213
|
+
const { from, to } = getBandsPosition({ band, axisScale, axis: 'y' });
|
|
214
|
+
const halfBandwidth = ((_b = (_a = axisScale.bandwidth) === null || _a === void 0 ? void 0 : _a.call(axisScale)) !== null && _b !== void 0 ? _b : 0) / 2;
|
|
215
|
+
const startPos = halfBandwidth + Math.min(from, to);
|
|
216
|
+
return Math.max(0, startPos);
|
|
217
|
+
})
|
|
218
|
+
.attr('height', (band) => {
|
|
219
|
+
const { from, to } = getBandsPosition({ band, axisScale, axis: 'y' });
|
|
220
|
+
const startPos = height - Math.min(from, to);
|
|
221
|
+
const endPos = Math.min(Math.abs(to - from), startPos);
|
|
222
|
+
return Math.min(endPos, height);
|
|
223
|
+
})
|
|
224
|
+
.attr('fill', (band) => band.color)
|
|
225
|
+
.attr('opacity', (band) => band.opacity);
|
|
226
|
+
plotBandsSelection.each((plotBandData, i, nodes) => {
|
|
227
|
+
const plotLineSelection = select(nodes[i]);
|
|
228
|
+
if (plotBandData.layerPlacement === 'before') {
|
|
229
|
+
plotLineSelection.lower();
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
plotLineSelection.raise();
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
}
|
|
193
236
|
if (plotContainer && d.plotLines.length > 0) {
|
|
194
|
-
const plotLineClassName = b('
|
|
237
|
+
const plotLineClassName = b('plot-y-line');
|
|
195
238
|
const plotLinesSelection = plotContainer
|
|
196
239
|
.selectAll(`.${plotLineClassName}`)
|
|
197
240
|
.data(plotLines)
|
|
@@ -268,6 +311,6 @@ export const AxisY = (props) => {
|
|
|
268
311
|
handleOverflowingText(nodes[index], height);
|
|
269
312
|
}
|
|
270
313
|
});
|
|
271
|
-
}, [allAxes, width, height, scale, split]);
|
|
314
|
+
}, [allAxes, width, height, scale, split, bottomLimit]);
|
|
272
315
|
return React.createElement("g", { ref: ref, className: b('container') });
|
|
273
316
|
};
|
|
@@ -67,7 +67,7 @@ export const ChartInner = (props) => {
|
|
|
67
67
|
})),
|
|
68
68
|
React.createElement("g", { width: boundsWidth, height: boundsHeight, transform: `translate(${[boundsOffsetLeft, boundsOffsetTop].join(',')})`, ref: plotRef },
|
|
69
69
|
xScale && (yScale === null || yScale === void 0 ? void 0 : yScale.length) && (React.createElement(React.Fragment, null,
|
|
70
|
-
React.createElement(AxisY, {
|
|
70
|
+
React.createElement(AxisY, { bottomLimit: svgBottomPos, axes: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale, split: preparedSplit, plotRef: plotRef }),
|
|
71
71
|
React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
|
|
72
72
|
React.createElement(AxisX, { leftmostLimit: svgXPos, axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale, split: preparedSplit, plotRef: plotRef })))),
|
|
73
73
|
shapes),
|
|
@@ -58,9 +58,9 @@ export function useChartInnerProps(props) {
|
|
|
58
58
|
// We need to calculate the width of each axis because the first axis can be hidden
|
|
59
59
|
const boundsOffsetLeft = chart.margin.left +
|
|
60
60
|
yAxis.reduce((acc, axis) => {
|
|
61
|
-
const
|
|
62
|
-
if (acc <
|
|
63
|
-
acc =
|
|
61
|
+
const axisWidth = getYAxisWidth(axis);
|
|
62
|
+
if (acc < axisWidth) {
|
|
63
|
+
acc = axisWidth;
|
|
64
64
|
}
|
|
65
65
|
return acc;
|
|
66
66
|
}, 0);
|
|
@@ -114,6 +114,7 @@ function renderLegendSymbol(args) {
|
|
|
114
114
|
}
|
|
115
115
|
case 'symbol': {
|
|
116
116
|
const y = legend.lineHeight / 2;
|
|
117
|
+
const translateX = x + d.symbol.width / 2;
|
|
117
118
|
element
|
|
118
119
|
.append('svg:path')
|
|
119
120
|
.attr('d', () => {
|
|
@@ -123,7 +124,7 @@ function renderLegendSymbol(args) {
|
|
|
123
124
|
return symbol(scatterSymbol, d.symbol.width * d.symbol.width)();
|
|
124
125
|
})
|
|
125
126
|
.attr('transform', () => {
|
|
126
|
-
return 'translate(' +
|
|
127
|
+
return 'translate(' + translateX + ',' + y + ')';
|
|
127
128
|
})
|
|
128
129
|
.attr('class', className)
|
|
129
130
|
.style('fill', color);
|
|
@@ -185,21 +186,32 @@ export const Legend = (props) => {
|
|
|
185
186
|
const mods = { selected: d.visible, unselected: !d.visible };
|
|
186
187
|
return b('item-text', mods);
|
|
187
188
|
})
|
|
188
|
-
.
|
|
189
|
+
.html(function (d) {
|
|
189
190
|
return ('name' in d && d.name);
|
|
190
191
|
})
|
|
191
192
|
.style('font-size', legend.itemStyle.fontSize);
|
|
192
193
|
const contentWidth = ((_a = legendLine.node()) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().width) || 0;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
194
|
+
let left = 0;
|
|
195
|
+
switch (legend.justifyContent) {
|
|
196
|
+
case 'center': {
|
|
197
|
+
const legendLinePostion = getLegendPosition({
|
|
198
|
+
align: legend.align,
|
|
199
|
+
width: boundsWidth,
|
|
200
|
+
offsetWidth: 0,
|
|
201
|
+
contentWidth,
|
|
202
|
+
});
|
|
203
|
+
left = legendLinePostion.left;
|
|
204
|
+
legendWidth = boundsWidth;
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case 'start': {
|
|
208
|
+
legendWidth = Math.max(legendWidth, contentWidth);
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
199
212
|
const top = legend.lineHeight * lineIndex;
|
|
200
213
|
legendLine.attr('transform', `translate(${[left, top].join(',')})`);
|
|
201
214
|
});
|
|
202
|
-
legendWidth = boundsWidth;
|
|
203
215
|
if (config.pagination) {
|
|
204
216
|
const transform = `translate(${[
|
|
205
217
|
0,
|
|
@@ -283,7 +295,7 @@ export const Legend = (props) => {
|
|
|
283
295
|
.attr('font-size', (_d = legend.title.style.fontSize) !== null && _d !== void 0 ? _d : null)
|
|
284
296
|
.attr('fill', (_e = legend.title.style.fontColor) !== null && _e !== void 0 ? _e : null)
|
|
285
297
|
.style('alignment-baseline', 'before-edge')
|
|
286
|
-
.
|
|
298
|
+
.html(legend.title.text);
|
|
287
299
|
}
|
|
288
300
|
const { left } = getLegendPosition({
|
|
289
301
|
align: legend.align,
|
|
@@ -5,5 +5,5 @@ const b = block('title');
|
|
|
5
5
|
export const Title = (props) => {
|
|
6
6
|
const { chartWidth, text, height, style } = props;
|
|
7
7
|
return (React.createElement("text", { className: b(), dx: chartWidth / 2, dy: height / 2, dominantBaseline: "middle", textAnchor: "middle", style: Object.assign({ lineHeight: `${height}px` }, style) },
|
|
8
|
-
React.createElement("tspan",
|
|
8
|
+
React.createElement("tspan", { dangerouslySetInnerHTML: { __html: text } })));
|
|
9
9
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DashStyle } from 'src/constants';
|
|
2
|
-
import type {
|
|
2
|
+
import type { AxisPlotBand, BaseTextStyle, ChartAxis, ChartAxisLabels, ChartAxisTitleAlignment, ChartAxisType, ChartData, ChartMargin, PlotLayerPlacement } from '../../types';
|
|
3
3
|
type PreparedAxisLabels = Omit<ChartAxisLabels, 'enabled' | 'padding' | 'style' | 'autoRotation'> & Required<Pick<ChartAxisLabels, 'enabled' | 'padding' | 'margin' | 'rotation'>> & {
|
|
4
4
|
style: BaseTextStyle;
|
|
5
5
|
rotation: number;
|
|
@@ -11,15 +11,16 @@ type PreparedAxisLabels = Omit<ChartAxisLabels, 'enabled' | 'padding' | 'style'
|
|
|
11
11
|
export type PreparedChart = {
|
|
12
12
|
margin: ChartMargin;
|
|
13
13
|
};
|
|
14
|
+
export type PreparedAxisPlotBand = Required<AxisPlotBand>;
|
|
14
15
|
export type PreparedAxisPlotLine = {
|
|
15
16
|
value: number;
|
|
16
17
|
color: string;
|
|
17
18
|
width: number;
|
|
18
19
|
dashStyle: DashStyle;
|
|
19
20
|
opacity: number;
|
|
20
|
-
layerPlacement:
|
|
21
|
+
layerPlacement: PlotLayerPlacement;
|
|
21
22
|
};
|
|
22
|
-
export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels' | 'plotLines'> & {
|
|
23
|
+
export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels' | 'plotLines' | 'plotBands'> & {
|
|
23
24
|
type: ChartAxisType;
|
|
24
25
|
labels: PreparedAxisLabels;
|
|
25
26
|
title: {
|
|
@@ -42,6 +43,7 @@ export type PreparedAxis = Omit<ChartAxis, 'type' | 'labels' | 'plotLines'> & {
|
|
|
42
43
|
position: 'left' | 'right' | 'top' | 'bottom';
|
|
43
44
|
plotIndex: number;
|
|
44
45
|
plotLines: PreparedAxisPlotLine[];
|
|
46
|
+
plotBands: PreparedAxisPlotBand[];
|
|
45
47
|
};
|
|
46
48
|
export type PreparedTitle = ChartData['title'] & {
|
|
47
49
|
height: number;
|
|
@@ -110,6 +110,13 @@ export const getPreparedXAxis = ({ xAxis, series, width, }) => {
|
|
|
110
110
|
opacity: get(d, 'opacity', 1),
|
|
111
111
|
layerPlacement: get(d, 'layerPlacement', 'before'),
|
|
112
112
|
})),
|
|
113
|
+
plotBands: get(xAxis, 'plotBands', []).map((d) => ({
|
|
114
|
+
color: get(d, 'color', 'var(--g-color-base-brand)'),
|
|
115
|
+
opacity: get(d, 'opacity', 1),
|
|
116
|
+
from: get(d, 'from', 0),
|
|
117
|
+
to: get(d, 'to', 0),
|
|
118
|
+
layerPlacement: get(d, 'layerPlacement', 'before'),
|
|
119
|
+
})),
|
|
113
120
|
visible: get(xAxis, 'visible', true),
|
|
114
121
|
};
|
|
115
122
|
const { height, rotation } = getLabelSettings({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import get from 'lodash/get';
|
|
2
2
|
import { DEFAULT_AXIS_LABEL_FONT_SIZE, DEFAULT_AXIS_TYPE, DashStyle, axisLabelsDefaults, yAxisTitleDefaults, } from '../../constants';
|
|
3
|
-
import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, getWaterfallPointSubtotal, wrapText, } from '../../utils';
|
|
3
|
+
import { CHART_SERIES_WITH_VOLUME_ON_Y_AXIS, formatAxisTickLabel, getClosestPointsRange, getHorisontalSvgTextHeight, getLabelsSize, getScaleTicks, getWaterfallPointSubtotal, isAxisRelatedSeries, wrapText, } from '../../utils';
|
|
4
4
|
import { createYScale } from '../useAxisScales';
|
|
5
5
|
const getAxisLabelMaxWidth = (args) => {
|
|
6
6
|
const { axis, series } = args;
|
|
@@ -45,6 +45,10 @@ function getAxisMin(axis, series) {
|
|
|
45
45
|
export const getPreparedYAxis = ({ series, yAxis, height, }) => {
|
|
46
46
|
const axisByPlot = [];
|
|
47
47
|
const axisItems = yAxis || [{}];
|
|
48
|
+
const hasAxisRelatedSeries = series.some(isAxisRelatedSeries);
|
|
49
|
+
if (!hasAxisRelatedSeries) {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
48
52
|
return axisItems.map((axisItem) => {
|
|
49
53
|
const plotIndex = get(axisItem, 'plotIndex', 0);
|
|
50
54
|
const firstPlotAxis = !axisByPlot[plotIndex];
|
|
@@ -116,6 +120,13 @@ export const getPreparedYAxis = ({ series, yAxis, height, }) => {
|
|
|
116
120
|
opacity: get(d, 'opacity', 1),
|
|
117
121
|
layerPlacement: get(d, 'layerPlacement', 'before'),
|
|
118
122
|
})),
|
|
123
|
+
plotBands: get(axisItem, 'plotBands', []).map((d) => ({
|
|
124
|
+
color: get(d, 'color', 'var(--g-color-base-brand)'),
|
|
125
|
+
opacity: get(d, 'opacity', 1),
|
|
126
|
+
from: get(d, 'from', 0),
|
|
127
|
+
to: get(d, 'to', 0),
|
|
128
|
+
layerPlacement: get(d, 'layerPlacement', 'before'),
|
|
129
|
+
})),
|
|
119
130
|
visible: get(axisItem, 'visible', true),
|
|
120
131
|
};
|
|
121
132
|
if (labelsEnabled) {
|
|
@@ -50,6 +50,7 @@ export const getPreparedLegend = (args) => {
|
|
|
50
50
|
const legendWidth = get(legend, 'width', CONTINUOUS_LEGEND_SIZE.width);
|
|
51
51
|
return {
|
|
52
52
|
align: get(legend, 'align', legendDefaults.align),
|
|
53
|
+
justifyContent: get(legend, 'justifyContent', legendDefaults.justifyContent),
|
|
53
54
|
enabled,
|
|
54
55
|
height,
|
|
55
56
|
itemDistance: get(legend, 'itemDistance', legendDefaults.itemDistance),
|
|
@@ -17,6 +17,7 @@ export const HtmlLayer = (props) => {
|
|
|
17
17
|
return null;
|
|
18
18
|
}
|
|
19
19
|
return (React.createElement(Portal, { container: htmlLayout }, items.map((item, index) => {
|
|
20
|
-
|
|
20
|
+
const style = Object.assign(Object.assign({}, item.style), { position: 'absolute', left: item.x, top: item.y });
|
|
21
|
+
return (React.createElement("div", { key: index, dangerouslySetInnerHTML: { __html: item.content }, style: style }));
|
|
21
22
|
})));
|
|
22
23
|
};
|
|
@@ -35,6 +35,7 @@ function getHtmlLabel(point, series, xMax) {
|
|
|
35
35
|
y: Math.max(0, point.y - series.dataLabels.padding - size.maxHeight),
|
|
36
36
|
content,
|
|
37
37
|
size: { width: size.maxWidth, height: size.maxHeight },
|
|
38
|
+
style: series.dataLabels.style,
|
|
38
39
|
};
|
|
39
40
|
}
|
|
40
41
|
export const prepareLineData = (args) => {
|
|
@@ -17,7 +17,10 @@ const getCenter = (boundsWidth, boundsHeight, center) => {
|
|
|
17
17
|
};
|
|
18
18
|
export function preparePieData(args) {
|
|
19
19
|
const { series: preparedSeries, boundsWidth, boundsHeight } = args;
|
|
20
|
-
const
|
|
20
|
+
const haloSize = preparedSeries[0].states.hover.halo.enabled
|
|
21
|
+
? preparedSeries[0].states.hover.halo.size
|
|
22
|
+
: 0;
|
|
23
|
+
const maxRadius = Math.min(boundsWidth, boundsHeight) / 2 - haloSize;
|
|
21
24
|
const groupedPieSeries = group(preparedSeries, (pieSeries) => pieSeries.stackId);
|
|
22
25
|
const prepareItem = (stackId, items) => {
|
|
23
26
|
var _a;
|
|
@@ -184,6 +187,7 @@ export function preparePieData(args) {
|
|
|
184
187
|
y: Math.max(0, data.center[1] + label.y),
|
|
185
188
|
content: label.text,
|
|
186
189
|
size: label.size,
|
|
190
|
+
style: label.style,
|
|
187
191
|
});
|
|
188
192
|
}
|
|
189
193
|
else {
|
|
@@ -209,19 +213,20 @@ export function preparePieData(args) {
|
|
|
209
213
|
series: items,
|
|
210
214
|
});
|
|
211
215
|
const segmentMaxRadius = Math.max(...data.segments.map((s) => s.data.radius));
|
|
212
|
-
const
|
|
216
|
+
const topAdjustment = Math.min(data.center[1] - segmentMaxRadius, ...preparedLabels.labels.map((l) => l.y + data.center[1]), ...preparedLabels.htmlLabels.map((l) => l.y));
|
|
213
217
|
const bottom = Math.max(data.center[1] + segmentMaxRadius, ...preparedLabels.labels.map((l) => l.y + data.center[1] + l.size.height), ...preparedLabels.htmlLabels.map((l) => l.y + l.size.height));
|
|
214
|
-
const topAdjustment = Math.floor(top - data.halo.size);
|
|
215
218
|
if (topAdjustment > 0) {
|
|
216
219
|
data.segments.forEach((s) => {
|
|
217
|
-
s.data.radius
|
|
220
|
+
const nextPossibleRadius = s.data.radius + topAdjustment / 2;
|
|
221
|
+
s.data.radius = Math.min(nextPossibleRadius, maxRadius);
|
|
218
222
|
});
|
|
219
223
|
data.center[1] -= topAdjustment / 2;
|
|
220
224
|
}
|
|
221
|
-
const bottomAdjustment = Math.floor(boundsHeight - bottom
|
|
225
|
+
const bottomAdjustment = Math.floor(boundsHeight - bottom);
|
|
222
226
|
if (bottomAdjustment > 0) {
|
|
223
227
|
data.segments.forEach((s) => {
|
|
224
|
-
s.data.radius
|
|
228
|
+
const nextPossibleRadius = s.data.radius + bottomAdjustment / 2;
|
|
229
|
+
s.data.radius = Math.min(nextPossibleRadius, maxRadius);
|
|
225
230
|
});
|
|
226
231
|
data.center[1] += bottomAdjustment / 2;
|
|
227
232
|
}
|
|
@@ -10,23 +10,28 @@ function getLabels(args) {
|
|
|
10
10
|
texts.forEach((text, index) => {
|
|
11
11
|
var _a;
|
|
12
12
|
const label = getFormattedValue(Object.assign({ value: text }, args.options));
|
|
13
|
-
const { maxHeight: lineHeight, maxWidth:
|
|
13
|
+
const { maxHeight: lineHeight, maxWidth: labelMaxWidth } = (_a = getLabelsSize({ labels: [label], html })) !== null && _a !== void 0 ? _a : {};
|
|
14
14
|
const left = d.x0 + padding;
|
|
15
15
|
const right = d.x1 - padding;
|
|
16
|
-
const
|
|
16
|
+
const spaceWidth = Math.max(0, right - left);
|
|
17
|
+
const spaceHeight = Math.max(0, d.y1 - d.y0 - padding);
|
|
17
18
|
let x = left;
|
|
18
19
|
const y = index * lineHeight + d.y0 + padding;
|
|
20
|
+
const labelWidth = Math.min(labelMaxWidth, spaceWidth);
|
|
21
|
+
if (!labelWidth || lineHeight > spaceHeight) {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
19
24
|
switch (align) {
|
|
20
25
|
case 'left': {
|
|
21
26
|
x = left;
|
|
22
27
|
break;
|
|
23
28
|
}
|
|
24
29
|
case 'center': {
|
|
25
|
-
x = Math.max(left, left + (
|
|
30
|
+
x = Math.max(left, left + (spaceWidth - labelMaxWidth) / 2);
|
|
26
31
|
break;
|
|
27
32
|
}
|
|
28
33
|
case 'right': {
|
|
29
|
-
x = Math.max(left, right -
|
|
34
|
+
x = Math.max(left, right - labelMaxWidth);
|
|
30
35
|
break;
|
|
31
36
|
}
|
|
32
37
|
}
|
|
@@ -35,13 +40,13 @@ function getLabels(args) {
|
|
|
35
40
|
content: label,
|
|
36
41
|
x,
|
|
37
42
|
y,
|
|
38
|
-
size: { width, height: lineHeight },
|
|
43
|
+
size: { width: labelWidth, height: lineHeight },
|
|
39
44
|
}
|
|
40
45
|
: {
|
|
41
46
|
text: label,
|
|
42
47
|
x,
|
|
43
48
|
y,
|
|
44
|
-
width,
|
|
49
|
+
width: labelWidth,
|
|
45
50
|
nodeData: d.data,
|
|
46
51
|
};
|
|
47
52
|
acc.push(item);
|
|
@@ -94,10 +99,11 @@ export function prepareTreemapData(args) {
|
|
|
94
99
|
let labelData = [];
|
|
95
100
|
const htmlElements = [];
|
|
96
101
|
if ((_a = series.dataLabels) === null || _a === void 0 ? void 0 : _a.enabled) {
|
|
97
|
-
const { html } = series.dataLabels;
|
|
102
|
+
const { html, style: dataLabelsStyle } = series.dataLabels;
|
|
98
103
|
const labels = getLabels({ data: leaves, options: series.dataLabels });
|
|
99
104
|
if (html) {
|
|
100
|
-
|
|
105
|
+
const htmlItems = labels.map((l) => (Object.assign({ style: dataLabelsStyle }, l)));
|
|
106
|
+
htmlElements.push(...htmlItems);
|
|
101
107
|
}
|
|
102
108
|
else {
|
|
103
109
|
labelData = labels;
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
"label_invalid-series-property": "It seems you are trying to use inappropriate value for \"{{key}}\", or defined it incorrectly. Available values: [{{values}}].",
|
|
12
12
|
"label_invalid-treemap-redundant-value": "It seems you are trying to set \"value\" for container node. Check node with this properties: { id: \"{{id}}\", name: \"{{name}}\" }",
|
|
13
13
|
"label_invalid-treemap-missing-value": "It seems you are trying to use node without \"value\". Check node with this properties: { id: \"{{id}}\", name: \"{{name}}\" }",
|
|
14
|
-
"label_invalid-y-axis-index": "It seems you are trying to use inappropriate index for Y axis: \"{{index}}\""
|
|
14
|
+
"label_invalid-y-axis-index": "It seems you are trying to use inappropriate index for Y axis: \"{{index}}\"",
|
|
15
|
+
"label_invalid-axis-plot-band-option": "It seems you are trying to use inappropriate type for \"{{axis}}\" axis plot band option: \"{{option}}\"",
|
|
16
|
+
"label_axis-plot-band-options-not-equal": "It seems you are trying to use different type for \"{{axis}}\" axis plot band options"
|
|
15
17
|
}
|
|
16
18
|
}
|
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
"label_invalid-series-property": "Похоже, что вы пытаетесь использовать недопустимое значение для \"{{key}}\", или указали его неверно. Доступные значения: [{{values}}].",
|
|
12
12
|
"label_invalid-treemap-redundant-value": "Похоже, что вы пытаетесь установить значение \"value\" для узла, используемого в качестве контейнера. Проверьте узел с этими свойствами: { id: \"{{id}}\", name: \"{{name}}\" }",
|
|
13
13
|
"label_invalid-treemap-missing-value": "Похоже, что вы пытаетесь использовать узел без значения \"value\". Проверьте узел с этими свойствами: { id: \"{{id}}\", name: \"{{name}}\" }",
|
|
14
|
-
"label_invalid-y-axis-index": "Похоже, что вы пытаетесь использовать некорректный индекс для оси Y: \"{{index}}\""
|
|
14
|
+
"label_invalid-y-axis-index": "Похоже, что вы пытаетесь использовать некорректный индекс для оси Y: \"{{index}}\"",
|
|
15
|
+
"label_invalid-axis-plot-band-option": "Похоже, что вы пытаетесь использовать некорректный тип для параметра полосы: \"{{option}}\" для оси \"{{axis}}\"",
|
|
16
|
+
"label_axis-plot-band-options-not-equal": "Похоже, что вы пытаетесь использовать разные типы для для параметра полосы для оси \"{{axis}}\""
|
|
15
17
|
}
|
|
16
18
|
}
|
|
@@ -2,6 +2,7 @@ export const CHART_ERROR_CODE = {
|
|
|
2
2
|
NO_DATA: 'ERR.CK.NO_DATA',
|
|
3
3
|
INVALID_DATA: 'ERR.CK.INVALID_DATA',
|
|
4
4
|
UNKNOWN: 'ERR.CK.UNKNOWN_ERROR',
|
|
5
|
+
INVALID_OPTION_TYPE: 'ERR.CK.INVALID_OPTION_TYPE',
|
|
5
6
|
};
|
|
6
7
|
export class ChartError extends Error {
|
|
7
8
|
constructor({ originalError, message, code = CHART_ERROR_CODE.UNKNOWN } = {}) {
|