@gravity-ui/chartkit 4.4.1 → 4.5.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/build/plugins/d3/renderer/components/AxisX.d.ts +2 -1
- package/build/plugins/d3/renderer/components/AxisX.js +25 -13
- package/build/plugins/d3/renderer/components/Chart.js +1 -1
- package/build/plugins/d3/renderer/hooks/useAxisScales/index.js +8 -5
- package/build/plugins/d3/renderer/hooks/useChartOptions/chart.js +3 -7
- package/build/plugins/d3/renderer/utils/index.d.ts +1 -0
- package/build/plugins/d3/renderer/utils/index.js +1 -0
- package/build/plugins/d3/renderer/utils/text.d.ts +2 -0
- package/build/plugins/d3/renderer/utils/text.js +12 -0
- package/package.json +2 -2
|
@@ -5,6 +5,7 @@ type Props = {
|
|
|
5
5
|
width: number;
|
|
6
6
|
height: number;
|
|
7
7
|
scale: ChartScale;
|
|
8
|
+
chartWidth: number;
|
|
8
9
|
};
|
|
9
|
-
export declare const AxisX: ({ axis, width, height, scale }: Props) => React.JSX.Element;
|
|
10
|
+
export declare const AxisX: ({ axis, width, height, scale, chartWidth }: Props) => React.JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { axisBottom, select } from 'd3';
|
|
3
3
|
import { block } from '../../../../utils/cn';
|
|
4
|
-
import { formatAxisTickLabel, parseTransformStyle } from '../utils';
|
|
4
|
+
import { formatAxisTickLabel, parseTransformStyle, setEllipsisForOverflowText } from '../utils';
|
|
5
5
|
const b = block('d3-axis');
|
|
6
6
|
const EMPTY_SPACE_BETWEEN_LABELS = 10;
|
|
7
7
|
// FIXME: add overflow ellipsis for the labels that out of boundaries
|
|
8
|
-
export const AxisX = ({ axis, width, height, scale }) => {
|
|
8
|
+
export const AxisX = ({ axis, width, height, scale, chartWidth }) => {
|
|
9
9
|
const ref = React.useRef(null);
|
|
10
10
|
React.useEffect(() => {
|
|
11
11
|
if (!ref.current) {
|
|
@@ -46,17 +46,7 @@ export const AxisX = ({ axis, width, height, scale }) => {
|
|
|
46
46
|
// Remove tick that has the same x coordinate like domain
|
|
47
47
|
svgElement.select('.tick').remove();
|
|
48
48
|
}
|
|
49
|
-
|
|
50
|
-
const textY = axis.title.height + parseInt(axis.labels.style.fontSize) + axis.labels.padding;
|
|
51
|
-
svgElement
|
|
52
|
-
.append('text')
|
|
53
|
-
.attr('class', b('title'))
|
|
54
|
-
.attr('text-anchor', 'middle')
|
|
55
|
-
.attr('x', width / 2)
|
|
56
|
-
.attr('y', textY)
|
|
57
|
-
.attr('font-size', axis.title.style.fontSize)
|
|
58
|
-
.text(axis.title.text);
|
|
59
|
-
}
|
|
49
|
+
// remove overlapping labels
|
|
60
50
|
let elementX = 0;
|
|
61
51
|
svgElement
|
|
62
52
|
.selectAll('.tick')
|
|
@@ -70,6 +60,28 @@ export const AxisX = ({ axis, width, height, scale }) => {
|
|
|
70
60
|
return false;
|
|
71
61
|
})
|
|
72
62
|
.remove();
|
|
63
|
+
// add an ellipsis to the labels on the right that go beyond the boundaries of the chart
|
|
64
|
+
svgElement.selectAll('.tick text').each(function () {
|
|
65
|
+
const node = this;
|
|
66
|
+
const textRect = node.getBoundingClientRect();
|
|
67
|
+
if (textRect.right > chartWidth) {
|
|
68
|
+
const maxWidth = textRect.width - (textRect.right - chartWidth) * 2;
|
|
69
|
+
select(node).call(setEllipsisForOverflowText, maxWidth);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// add an axis header if necessary
|
|
73
|
+
if (axis.title.text) {
|
|
74
|
+
const textY = axis.title.height + parseInt(axis.labels.style.fontSize) + axis.labels.padding;
|
|
75
|
+
svgElement
|
|
76
|
+
.append('text')
|
|
77
|
+
.attr('class', b('title'))
|
|
78
|
+
.attr('text-anchor', 'middle')
|
|
79
|
+
.attr('x', width / 2)
|
|
80
|
+
.attr('y', textY)
|
|
81
|
+
.attr('font-size', axis.title.style.fontSize)
|
|
82
|
+
.text(axis.title.text)
|
|
83
|
+
.call(setEllipsisForOverflowText, width);
|
|
84
|
+
}
|
|
73
85
|
}, [axis, width, height, scale]);
|
|
74
86
|
return React.createElement("g", { ref: ref });
|
|
75
87
|
};
|
|
@@ -53,7 +53,7 @@ export const Chart = (props) => {
|
|
|
53
53
|
xScale && yScale && (React.createElement(React.Fragment, null,
|
|
54
54
|
React.createElement(AxisY, { axises: yAxis, width: boundsWidth, height: boundsHeight, scale: yScale }),
|
|
55
55
|
React.createElement("g", { transform: `translate(0, ${boundsHeight})` },
|
|
56
|
-
React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale })))),
|
|
56
|
+
React.createElement(AxisX, { axis: xAxis, width: boundsWidth, height: boundsHeight, scale: xScale, chartWidth: width })))),
|
|
57
57
|
shapes),
|
|
58
58
|
legend.enabled && (React.createElement(Legend, { width: boundsWidth, offsetWidth: chart.margin.left, height: legend.height, legend: legend, offsetHeight: height - legend.height / 2, chartSeries: preparedSeries, onItemClick: handleLegendItemClick }))),
|
|
59
59
|
React.createElement(Tooltip, { hovered: hovered, pointerPosition: pointerPosition, tooltip: tooltip, xAxis: xAxis, yAxis: yAxis[0] })));
|
|
@@ -33,14 +33,15 @@ const createScales = (args) => {
|
|
|
33
33
|
visibleSeries = visibleSeries.length === 0 ? series : visibleSeries;
|
|
34
34
|
let xScale;
|
|
35
35
|
let yScale;
|
|
36
|
+
const xAxisMinPadding = boundsWidth * xAxis.maxPadding;
|
|
37
|
+
const xRange = [0, boundsWidth - xAxisMinPadding];
|
|
36
38
|
switch (xType) {
|
|
37
39
|
case 'linear': {
|
|
38
40
|
const domain = getDomainDataXBySeries(visibleSeries);
|
|
39
|
-
const range = [0, boundsWidth - boundsWidth * xAxis.maxPadding];
|
|
40
41
|
if (isNumericalArrayData(domain)) {
|
|
41
42
|
const [domainXMin, xMax] = extent(domain);
|
|
42
43
|
const xMinValue = typeof xMin === 'number' ? xMin : domainXMin;
|
|
43
|
-
xScale = scaleLinear().domain([xMinValue, xMax]).range(
|
|
44
|
+
xScale = scaleLinear().domain([xMinValue, xMax]).range(xRange).nice();
|
|
44
45
|
}
|
|
45
46
|
break;
|
|
46
47
|
}
|
|
@@ -52,20 +53,22 @@ const createScales = (args) => {
|
|
|
52
53
|
series: visibleSeries,
|
|
53
54
|
});
|
|
54
55
|
xScale = scaleBand().domain(filteredCategories).range([0, boundsWidth]);
|
|
56
|
+
if (xScale.step() / 2 < xAxisMinPadding) {
|
|
57
|
+
xScale.range(xRange);
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
60
|
break;
|
|
57
61
|
}
|
|
58
62
|
case 'datetime': {
|
|
59
|
-
const range = [0, boundsWidth - boundsWidth * xAxis.maxPadding];
|
|
60
63
|
if (xTimestamps) {
|
|
61
64
|
const [xMin, xMax] = extent(xTimestamps);
|
|
62
|
-
xScale = scaleUtc().domain([xMin, xMax]).range(
|
|
65
|
+
xScale = scaleUtc().domain([xMin, xMax]).range(xRange).nice();
|
|
63
66
|
}
|
|
64
67
|
else {
|
|
65
68
|
const domain = getDomainDataXBySeries(visibleSeries);
|
|
66
69
|
if (isNumericalArrayData(domain)) {
|
|
67
70
|
const [xMin, xMax] = extent(domain);
|
|
68
|
-
xScale = scaleUtc().domain([xMin, xMax]).range(
|
|
71
|
+
xScale = scaleUtc().domain([xMin, xMax]).range(xRange).nice();
|
|
69
72
|
}
|
|
70
73
|
}
|
|
71
74
|
break;
|
|
@@ -80,12 +80,8 @@ const getMarginLeft = (args) => {
|
|
|
80
80
|
return marginLeft;
|
|
81
81
|
};
|
|
82
82
|
const getMarginRight = (args) => {
|
|
83
|
-
const { chart
|
|
84
|
-
|
|
85
|
-
if (hasAxisRelatedSeries) {
|
|
86
|
-
marginRight += getAxisLabelMaxWidth({ axis: preparedXAxis, series: series.data }) / 2;
|
|
87
|
-
}
|
|
88
|
-
return marginRight;
|
|
83
|
+
const { chart } = args;
|
|
84
|
+
return get(chart, 'margin.right', 0);
|
|
89
85
|
};
|
|
90
86
|
export const getPreparedChart = (args) => {
|
|
91
87
|
const { chart, series, preparedLegend, preparedXAxis, preparedY1Axis, preparedTitle } = args;
|
|
@@ -98,7 +94,7 @@ export const getPreparedChart = (args) => {
|
|
|
98
94
|
preparedXAxis,
|
|
99
95
|
});
|
|
100
96
|
const marginLeft = getMarginLeft({ chart, hasAxisRelatedSeries, series, preparedY1Axis });
|
|
101
|
-
const marginRight = getMarginRight({ chart
|
|
97
|
+
const marginRight = getMarginRight({ chart });
|
|
102
98
|
return {
|
|
103
99
|
margin: {
|
|
104
100
|
top: marginTop,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { AxisDomain } from 'd3';
|
|
2
2
|
import type { BaseTextStyle, ChartKitWidgetSeries, ChartKitWidgetSeriesData, ChartKitWidgetAxisType, ChartKitWidgetAxisLabels } from '../../../../types/widget-data';
|
|
3
3
|
export * from './math';
|
|
4
|
+
export * from './text';
|
|
4
5
|
export type AxisDirection = 'x' | 'y';
|
|
5
6
|
type UnknownSeries = {
|
|
6
7
|
type: ChartKitWidgetSeries['type'];
|
|
@@ -5,6 +5,7 @@ import { dateTime } from '@gravity-ui/date-utils';
|
|
|
5
5
|
import { formatNumber } from '../../../shared';
|
|
6
6
|
import { DEFAULT_AXIS_LABEL_FONT_SIZE } from '../constants';
|
|
7
7
|
export * from './math';
|
|
8
|
+
export * from './text';
|
|
8
9
|
const CHARTS_WITHOUT_AXIS = ['pie'];
|
|
9
10
|
/**
|
|
10
11
|
* Checks whether the series should be drawn with axes.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function setEllipsisForOverflowText(selection, maxWidth) {
|
|
2
|
+
var _a, _b;
|
|
3
|
+
let text = selection.text();
|
|
4
|
+
selection.text(null).attr('text-anchor', 'left').append('title').text(text);
|
|
5
|
+
const tSpan = selection.append('tspan').text(text);
|
|
6
|
+
let textLength = ((_a = tSpan.node()) === null || _a === void 0 ? void 0 : _a.getComputedTextLength()) || 0;
|
|
7
|
+
while (textLength > maxWidth && text.length > 1) {
|
|
8
|
+
text = text.slice(0, -1);
|
|
9
|
+
tSpan.text(text + '…');
|
|
10
|
+
textLength = ((_b = tSpan.node()) === null || _b === void 0 ? void 0 : _b.getComputedTextLength()) || 0;
|
|
11
|
+
}
|
|
12
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/chartkit",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.5.0",
|
|
4
4
|
"description": "React component used to render charts based on any sources you need",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": "git@github.com:gravity-ui/ChartKit.git",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"dependencies": {
|
|
49
49
|
"@bem-react/classname": "^1.6.0",
|
|
50
50
|
"@gravity-ui/date-utils": "^1.4.1",
|
|
51
|
-
"@gravity-ui/yagr": "^3.
|
|
51
|
+
"@gravity-ui/yagr": "^3.8.0",
|
|
52
52
|
"d3": "^7.8.5",
|
|
53
53
|
"lodash": "^4.17.21",
|
|
54
54
|
"react-split-pane": "^0.1.92"
|