@gravity-ui/charts 1.2.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/Legend/index.js +20 -8
- package/dist/cjs/constants/defaults/legend.d.ts +1 -0
- package/dist/cjs/constants/defaults/legend.js +1 -0
- package/dist/cjs/hooks/useChartOptions/y-axis.js +5 -1
- package/dist/cjs/hooks/useSeries/prepare-legend.js +1 -0
- package/dist/cjs/hooks/useShapes/pie/prepare-data.js +10 -6
- package/dist/cjs/hooks/useShapes/treemap/prepare-data.js +11 -6
- package/dist/cjs/types/chart/legend.d.ts +6 -0
- package/dist/esm/components/Legend/index.js +20 -8
- package/dist/esm/constants/defaults/legend.d.ts +1 -0
- package/dist/esm/constants/defaults/legend.js +1 -0
- package/dist/esm/hooks/useChartOptions/y-axis.js +5 -1
- package/dist/esm/hooks/useSeries/prepare-legend.js +1 -0
- package/dist/esm/hooks/useShapes/pie/prepare-data.js +10 -6
- package/dist/esm/hooks/useShapes/treemap/prepare-data.js +11 -6
- package/dist/esm/types/chart/legend.d.ts +6 -0
- package/package.json +1 -1
|
@@ -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);
|
|
@@ -190,16 +191,27 @@ export const Legend = (props) => {
|
|
|
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,
|
|
@@ -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];
|
|
@@ -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,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;
|
|
@@ -210,19 +213,20 @@ export function preparePieData(args) {
|
|
|
210
213
|
series: items,
|
|
211
214
|
});
|
|
212
215
|
const segmentMaxRadius = Math.max(...data.segments.map((s) => s.data.radius));
|
|
213
|
-
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));
|
|
214
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));
|
|
215
|
-
const topAdjustment = Math.floor(top - data.halo.size);
|
|
216
218
|
if (topAdjustment > 0) {
|
|
217
219
|
data.segments.forEach((s) => {
|
|
218
|
-
s.data.radius
|
|
220
|
+
const nextPossibleRadius = s.data.radius + topAdjustment / 2;
|
|
221
|
+
s.data.radius = Math.min(nextPossibleRadius, maxRadius);
|
|
219
222
|
});
|
|
220
223
|
data.center[1] -= topAdjustment / 2;
|
|
221
224
|
}
|
|
222
|
-
const bottomAdjustment = Math.floor(boundsHeight - bottom
|
|
225
|
+
const bottomAdjustment = Math.floor(boundsHeight - bottom);
|
|
223
226
|
if (bottomAdjustment > 0) {
|
|
224
227
|
data.segments.forEach((s) => {
|
|
225
|
-
s.data.radius
|
|
228
|
+
const nextPossibleRadius = s.data.radius + bottomAdjustment / 2;
|
|
229
|
+
s.data.radius = Math.min(nextPossibleRadius, maxRadius);
|
|
226
230
|
});
|
|
227
231
|
data.center[1] += bottomAdjustment / 2;
|
|
228
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);
|
|
@@ -15,6 +15,12 @@ export interface ChartLegend {
|
|
|
15
15
|
* @default center
|
|
16
16
|
* */
|
|
17
17
|
align?: 'left' | 'center' | 'right';
|
|
18
|
+
/**
|
|
19
|
+
* Defines how items should be positioned in the legend when overflowing (moving to the next line).
|
|
20
|
+
*
|
|
21
|
+
* @default center
|
|
22
|
+
* */
|
|
23
|
+
justifyContent?: 'start' | 'center';
|
|
18
24
|
/**
|
|
19
25
|
* Defines the pixel distance between each legend item
|
|
20
26
|
*
|
|
@@ -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);
|
|
@@ -190,16 +191,27 @@ export const Legend = (props) => {
|
|
|
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,
|
|
@@ -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];
|
|
@@ -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,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;
|
|
@@ -210,19 +213,20 @@ export function preparePieData(args) {
|
|
|
210
213
|
series: items,
|
|
211
214
|
});
|
|
212
215
|
const segmentMaxRadius = Math.max(...data.segments.map((s) => s.data.radius));
|
|
213
|
-
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));
|
|
214
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));
|
|
215
|
-
const topAdjustment = Math.floor(top - data.halo.size);
|
|
216
218
|
if (topAdjustment > 0) {
|
|
217
219
|
data.segments.forEach((s) => {
|
|
218
|
-
s.data.radius
|
|
220
|
+
const nextPossibleRadius = s.data.radius + topAdjustment / 2;
|
|
221
|
+
s.data.radius = Math.min(nextPossibleRadius, maxRadius);
|
|
219
222
|
});
|
|
220
223
|
data.center[1] -= topAdjustment / 2;
|
|
221
224
|
}
|
|
222
|
-
const bottomAdjustment = Math.floor(boundsHeight - bottom
|
|
225
|
+
const bottomAdjustment = Math.floor(boundsHeight - bottom);
|
|
223
226
|
if (bottomAdjustment > 0) {
|
|
224
227
|
data.segments.forEach((s) => {
|
|
225
|
-
s.data.radius
|
|
228
|
+
const nextPossibleRadius = s.data.radius + bottomAdjustment / 2;
|
|
229
|
+
s.data.radius = Math.min(nextPossibleRadius, maxRadius);
|
|
226
230
|
});
|
|
227
231
|
data.center[1] += bottomAdjustment / 2;
|
|
228
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);
|
|
@@ -15,6 +15,12 @@ export interface ChartLegend {
|
|
|
15
15
|
* @default center
|
|
16
16
|
* */
|
|
17
17
|
align?: 'left' | 'center' | 'right';
|
|
18
|
+
/**
|
|
19
|
+
* Defines how items should be positioned in the legend when overflowing (moving to the next line).
|
|
20
|
+
*
|
|
21
|
+
* @default center
|
|
22
|
+
* */
|
|
23
|
+
justifyContent?: 'start' | 'center';
|
|
18
24
|
/**
|
|
19
25
|
* Defines the pixel distance between each legend item
|
|
20
26
|
*
|