@gravity-ui/charts 1.11.3 → 1.12.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/ChartInner/index.js +1 -1
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +1 -0
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +19 -12
- package/dist/cjs/components/Legend/index.d.ts +0 -1
- package/dist/cjs/components/Legend/index.js +13 -23
- package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +1 -0
- package/dist/cjs/components/Tooltip/ChartTooltipContent.js +3 -3
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +102 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
- package/dist/cjs/components/Tooltip/index.js +1 -1
- package/dist/cjs/components/Tooltip/styles.css +14 -2
- package/dist/cjs/components/Tooltip/utils.d.ts +30 -0
- package/dist/cjs/components/Tooltip/utils.js +126 -0
- package/dist/cjs/constants/axis.d.ts +6 -0
- package/dist/cjs/constants/axis.js +6 -0
- package/dist/cjs/constants/index.d.ts +6 -4
- package/dist/cjs/constants/index.js +6 -4
- package/dist/cjs/constants/tooltip.d.ts +3 -0
- package/dist/cjs/constants/tooltip.js +3 -0
- package/dist/cjs/hooks/useAxisScales/index.d.ts +14 -3
- package/dist/cjs/hooks/useAxisScales/index.js +73 -22
- package/dist/cjs/hooks/useChartOptions/x-axis.js +1 -1
- package/dist/cjs/hooks/useChartOptions/y-axis.d.ts +4 -2
- package/dist/cjs/hooks/useChartOptions/y-axis.js +9 -3
- package/dist/cjs/hooks/useSeries/index.d.ts +9 -0
- package/dist/cjs/hooks/useSeries/index.js +59 -29
- package/dist/cjs/hooks/useSeries/prepare-legend.d.ts +2 -2
- package/dist/cjs/hooks/useSeries/prepare-legend.js +4 -6
- package/dist/cjs/hooks/useSeries/types.d.ts +1 -0
- package/dist/cjs/hooks/useShapes/bar-x/prepare-data.js +1 -1
- package/dist/cjs/hooks/useShapes/bar-y/prepare-data.js +17 -62
- package/dist/cjs/hooks/useShapes/waterfall/prepare-data.js +1 -1
- package/dist/cjs/hooks/utils/bar-y.d.ts +27 -0
- package/dist/cjs/hooks/utils/bar-y.js +69 -0
- package/dist/cjs/hooks/utils/index.d.ts +1 -0
- package/dist/cjs/hooks/utils/index.js +1 -0
- package/dist/cjs/i18n/keysets/en.json +7 -1
- package/dist/cjs/i18n/keysets/ru.json +7 -1
- package/dist/cjs/types/chart/axis.d.ts +2 -2
- package/dist/cjs/types/chart/tooltip.d.ts +21 -0
- package/dist/cjs/validation/index.js +55 -1
- package/dist/esm/components/ChartInner/index.js +1 -1
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +1 -0
- package/dist/esm/components/ChartInner/useChartInnerProps.js +19 -12
- package/dist/esm/components/Legend/index.d.ts +0 -1
- package/dist/esm/components/Legend/index.js +13 -23
- package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +1 -0
- package/dist/esm/components/Tooltip/ChartTooltipContent.js +3 -3
- package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.d.ts +9 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +10 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.d.ts +9 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/RowTotals.js +23 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +11 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +102 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.d.ts +30 -0
- package/dist/esm/components/Tooltip/DefaultTooltipContent/utils.js +126 -0
- package/dist/esm/components/Tooltip/index.js +1 -1
- package/dist/esm/components/Tooltip/styles.css +14 -2
- package/dist/esm/components/Tooltip/utils.d.ts +30 -0
- package/dist/esm/components/Tooltip/utils.js +126 -0
- package/dist/esm/constants/axis.d.ts +6 -0
- package/dist/esm/constants/axis.js +6 -0
- package/dist/esm/constants/index.d.ts +6 -4
- package/dist/esm/constants/index.js +6 -4
- package/dist/esm/constants/tooltip.d.ts +3 -0
- package/dist/esm/constants/tooltip.js +3 -0
- package/dist/esm/hooks/useAxisScales/index.d.ts +14 -3
- package/dist/esm/hooks/useAxisScales/index.js +73 -22
- package/dist/esm/hooks/useChartOptions/x-axis.js +1 -1
- package/dist/esm/hooks/useChartOptions/y-axis.d.ts +4 -2
- package/dist/esm/hooks/useChartOptions/y-axis.js +9 -3
- package/dist/esm/hooks/useSeries/index.d.ts +9 -0
- package/dist/esm/hooks/useSeries/index.js +59 -29
- package/dist/esm/hooks/useSeries/prepare-legend.d.ts +2 -2
- package/dist/esm/hooks/useSeries/prepare-legend.js +4 -6
- package/dist/esm/hooks/useSeries/types.d.ts +1 -0
- package/dist/esm/hooks/useShapes/bar-x/prepare-data.js +1 -1
- package/dist/esm/hooks/useShapes/bar-y/prepare-data.js +17 -62
- package/dist/esm/hooks/useShapes/waterfall/prepare-data.js +1 -1
- package/dist/esm/hooks/utils/bar-y.d.ts +27 -0
- package/dist/esm/hooks/utils/bar-y.js +69 -0
- package/dist/esm/hooks/utils/index.d.ts +1 -0
- package/dist/esm/hooks/utils/index.js +1 -0
- package/dist/esm/i18n/keysets/en.json +7 -1
- package/dist/esm/i18n/keysets/ru.json +7 -1
- package/dist/esm/types/chart/axis.d.ts +2 -2
- package/dist/esm/types/chart/tooltip.d.ts +21 -0
- package/dist/esm/validation/index.js +55 -1
- package/package.json +1 -1
- package/dist/cjs/components/Tooltip/DefaultContent.d.ts +0 -10
- package/dist/cjs/components/Tooltip/DefaultContent.js +0 -187
- package/dist/esm/components/Tooltip/DefaultContent.d.ts +0 -10
- package/dist/esm/components/Tooltip/DefaultContent.js +0 -187
- /package/dist/cjs/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
- /package/dist/cjs/hooks/{useShapes/constants.js → constants.js} +0 -0
- /package/dist/esm/hooks/{useShapes/constants.d.ts → constants.d.ts} +0 -0
- /package/dist/esm/hooks/{useShapes/constants.js → constants.js} +0 -0
|
@@ -100,7 +100,7 @@ export const ChartInner = (props) => {
|
|
|
100
100
|
React.createElement("g", { ref: plotBeforeRef }),
|
|
101
101
|
shapes,
|
|
102
102
|
React.createElement("g", { ref: plotAfterRef })),
|
|
103
|
-
(preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries,
|
|
103
|
+
(preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && legendConfig && (React.createElement(Legend, { chartSeries: preparedSeries, legend: preparedLegend, items: legendItems, config: legendConfig, onItemClick: handleLegendItemClick, onUpdate: unpinTooltip, htmlLayout: htmlLayout }))),
|
|
104
104
|
React.createElement("div", { className: b('html-layer'), ref: setHtmlLayout, style: {
|
|
105
105
|
'--g-html-layout-transform': `translate(${boundsOffsetLeft}px, ${boundsOffsetTop}px)`,
|
|
106
106
|
} }),
|
|
@@ -31,6 +31,7 @@ export declare function useChartInnerProps(props: Props): {
|
|
|
31
31
|
end: number;
|
|
32
32
|
}[];
|
|
33
33
|
} | undefined;
|
|
34
|
+
maxWidth: number;
|
|
34
35
|
} | undefined;
|
|
35
36
|
legendItems: never[] | import("../../hooks").LegendItem[][];
|
|
36
37
|
preparedLegend: import("../../hooks").PreparedLegend | null;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapes, useSplit, } from '../../hooks';
|
|
2
|
+
import { useAxisScales, useChartDimensions, useChartOptions, usePrevious, useSeries, useShapeSeries, useShapes, useSplit, } from '../../hooks';
|
|
3
3
|
import { getYAxisWidth } from '../../hooks/useChartDimensions/utils';
|
|
4
4
|
import { getPreparedXAxis } from '../../hooks/useChartOptions/x-axis';
|
|
5
5
|
import { getPreparedYAxis } from '../../hooks/useChartOptions/y-axis';
|
|
6
6
|
import { getLegendComponents } from '../../hooks/useSeries/prepare-legend';
|
|
7
7
|
import { getPreparedOptions } from '../../hooks/useSeries/prepare-options';
|
|
8
|
+
import { getActiveLegendItems } from '../../hooks/useSeries/utils';
|
|
8
9
|
import { useZoom } from '../../hooks/useZoom';
|
|
9
10
|
import { getSortedSeriesData, getZoomedSeriesData } from '../../utils';
|
|
10
11
|
import { hasAtLeastOneSeriesDataPerPlot } from './utils';
|
|
@@ -20,6 +21,9 @@ export function useChartInnerProps(props) {
|
|
|
20
21
|
title: data.title,
|
|
21
22
|
tooltip: data.tooltip,
|
|
22
23
|
});
|
|
24
|
+
const preparedSeriesOptions = React.useMemo(() => {
|
|
25
|
+
return getPreparedOptions(data.series.options);
|
|
26
|
+
}, [data.series.options]);
|
|
23
27
|
const [zoomState, setZoomState] = React.useState({});
|
|
24
28
|
const sortedSeriesData = React.useMemo(() => {
|
|
25
29
|
return getSortedSeriesData(data.series.data);
|
|
@@ -40,11 +44,13 @@ export function useChartInnerProps(props) {
|
|
|
40
44
|
const [yAxis, setYAxis] = React.useState([]);
|
|
41
45
|
React.useEffect(() => {
|
|
42
46
|
setYAxis([]);
|
|
43
|
-
getPreparedYAxis({
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
getPreparedYAxis({
|
|
48
|
+
height,
|
|
49
|
+
seriesData: zoomedSeriesData,
|
|
50
|
+
seriesOptions: preparedSeriesOptions,
|
|
51
|
+
yAxis: data.yAxis,
|
|
52
|
+
}).then((val) => setYAxis(val));
|
|
53
|
+
}, [data.yAxis, height, preparedSeriesOptions, zoomedSeriesData]);
|
|
48
54
|
const { preparedSeries, preparedLegend, handleLegendItemClick } = useSeries({
|
|
49
55
|
colors,
|
|
50
56
|
legend: data.legend,
|
|
@@ -52,12 +58,13 @@ export function useChartInnerProps(props) {
|
|
|
52
58
|
seriesData: zoomedSeriesData,
|
|
53
59
|
seriesOptions: data.series.options,
|
|
54
60
|
});
|
|
55
|
-
const
|
|
61
|
+
const activeLegendItems = React.useMemo(() => getActiveLegendItems(preparedSeries), [preparedSeries]);
|
|
62
|
+
const { preparedSeries: preparedShapesSeries } = useShapeSeries({
|
|
56
63
|
colors,
|
|
57
|
-
legend: data.legend,
|
|
58
|
-
originalSeriesData: data.series.data,
|
|
59
64
|
seriesData: zoomedShapesSeriesData,
|
|
60
65
|
seriesOptions: data.series.options,
|
|
66
|
+
activeLegendItems,
|
|
67
|
+
preparedLegend,
|
|
61
68
|
});
|
|
62
69
|
const { legendConfig, legendItems } = React.useMemo(() => {
|
|
63
70
|
if (!preparedLegend) {
|
|
@@ -69,9 +76,8 @@ export function useChartInnerProps(props) {
|
|
|
69
76
|
chartMargin: chart.margin,
|
|
70
77
|
series: preparedSeries,
|
|
71
78
|
preparedLegend,
|
|
72
|
-
preparedYAxis: yAxis,
|
|
73
79
|
});
|
|
74
|
-
}, [width, height, chart.margin, preparedSeries, preparedLegend
|
|
80
|
+
}, [width, height, chart.margin, preparedSeries, preparedLegend]);
|
|
75
81
|
const { boundsWidth, boundsHeight } = useChartDimensions({
|
|
76
82
|
width,
|
|
77
83
|
height,
|
|
@@ -88,9 +94,10 @@ export function useChartInnerProps(props) {
|
|
|
88
94
|
hasZoomX: Boolean(zoomState.x),
|
|
89
95
|
hasZoomY: Boolean(zoomState.y),
|
|
90
96
|
series: preparedSeries,
|
|
97
|
+
seriesOptions: preparedSeriesOptions,
|
|
98
|
+
split: preparedSplit,
|
|
91
99
|
xAxis,
|
|
92
100
|
yAxis,
|
|
93
|
-
split: preparedSplit,
|
|
94
101
|
});
|
|
95
102
|
const isOutsideBounds = React.useCallback((x, y) => {
|
|
96
103
|
return x < 0 || x > boundsWidth || y < 0 || y > boundsHeight;
|
|
@@ -2,7 +2,6 @@ import React from 'react';
|
|
|
2
2
|
import type { LegendConfig, LegendItem, OnLegendItemClick, PreparedLegend, PreparedSeries } from '../../hooks';
|
|
3
3
|
import './styles.css';
|
|
4
4
|
type Props = {
|
|
5
|
-
boundsWidth: number;
|
|
6
5
|
chartSeries: PreparedSeries[];
|
|
7
6
|
legend: PreparedLegend;
|
|
8
7
|
items: LegendItem[][];
|
|
@@ -7,15 +7,15 @@ import { axisBottom } from '../../utils/chart/axis-generators';
|
|
|
7
7
|
import './styles.css';
|
|
8
8
|
const b = block('legend');
|
|
9
9
|
const getLegendPosition = (args) => {
|
|
10
|
-
const { align,
|
|
10
|
+
const { align, offsetLeft = 0, width, contentWidth } = args;
|
|
11
11
|
const top = 0;
|
|
12
12
|
if (align === 'left') {
|
|
13
|
-
return { top, left:
|
|
13
|
+
return { top, left: offsetLeft };
|
|
14
14
|
}
|
|
15
15
|
if (align === 'right') {
|
|
16
|
-
return { top, left:
|
|
16
|
+
return { top, left: offsetLeft + width - contentWidth };
|
|
17
17
|
}
|
|
18
|
-
return { top, left:
|
|
18
|
+
return { top, left: offsetLeft + width / 2 - contentWidth / 2 };
|
|
19
19
|
};
|
|
20
20
|
const appendPaginator = (args) => {
|
|
21
21
|
const { container, pageIndex, legend, transform, pages, onArrowClick } = args;
|
|
@@ -135,12 +135,12 @@ function renderLegendSymbol(args) {
|
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
export const Legend = (props) => {
|
|
138
|
-
const {
|
|
138
|
+
const { chartSeries, legend, items, config, htmlLayout, onItemClick, onUpdate } = props;
|
|
139
139
|
const ref = React.useRef(null);
|
|
140
140
|
const [pageIndex, setPageIndex] = React.useState(0);
|
|
141
141
|
React.useEffect(() => {
|
|
142
142
|
setPageIndex(0);
|
|
143
|
-
}, [
|
|
143
|
+
}, [config.maxWidth]);
|
|
144
144
|
React.useEffect(() => {
|
|
145
145
|
async function prepareLegend() {
|
|
146
146
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
@@ -250,12 +250,12 @@ export const Legend = (props) => {
|
|
|
250
250
|
case 'center': {
|
|
251
251
|
const legendLinePostion = getLegendPosition({
|
|
252
252
|
align: legend.align,
|
|
253
|
-
width:
|
|
254
|
-
offsetWidth: 0,
|
|
253
|
+
width: config.maxWidth,
|
|
255
254
|
contentWidth,
|
|
255
|
+
offsetLeft: config.offset.left,
|
|
256
256
|
});
|
|
257
257
|
left = legendLinePostion.left;
|
|
258
|
-
legendWidth =
|
|
258
|
+
legendWidth = config.maxWidth;
|
|
259
259
|
break;
|
|
260
260
|
}
|
|
261
261
|
case 'start': {
|
|
@@ -361,9 +361,9 @@ export const Legend = (props) => {
|
|
|
361
361
|
}
|
|
362
362
|
const { left } = getLegendPosition({
|
|
363
363
|
align: legend.align,
|
|
364
|
-
width:
|
|
365
|
-
offsetWidth: config.offset.left,
|
|
364
|
+
width: config.maxWidth,
|
|
366
365
|
contentWidth: legendWidth,
|
|
366
|
+
offsetLeft: config.offset.left,
|
|
367
367
|
});
|
|
368
368
|
svgElement
|
|
369
369
|
.attr('transform', `translate(${[left, config.offset.top].join(',')})`)
|
|
@@ -371,19 +371,9 @@ export const Legend = (props) => {
|
|
|
371
371
|
htmlContainer === null || htmlContainer === void 0 ? void 0 : htmlContainer.style('transform', `translate(${left}px, ${config.offset.top}px)`);
|
|
372
372
|
}
|
|
373
373
|
prepareLegend();
|
|
374
|
-
}, [
|
|
375
|
-
boundsWidth,
|
|
376
|
-
chartSeries,
|
|
377
|
-
onItemClick,
|
|
378
|
-
onUpdate,
|
|
379
|
-
legend,
|
|
380
|
-
items,
|
|
381
|
-
config,
|
|
382
|
-
pageIndex,
|
|
383
|
-
htmlLayout,
|
|
384
|
-
]);
|
|
374
|
+
}, [chartSeries, onItemClick, onUpdate, legend, items, config, pageIndex, htmlLayout]);
|
|
385
375
|
// due to asynchronous processing, we only need to work with the actual element
|
|
386
376
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
387
377
|
const key = React.useMemo(() => getUniqId(), [legend, config]);
|
|
388
|
-
return React.createElement("g", { key: key, className: b(), ref: ref, width:
|
|
378
|
+
return React.createElement("g", { key: key, className: b(), ref: ref, width: config.maxWidth, height: legend.height });
|
|
389
379
|
};
|
|
@@ -6,5 +6,6 @@ export interface ChartTooltipContentProps {
|
|
|
6
6
|
yAxis?: ChartYAxis;
|
|
7
7
|
renderer?: ChartTooltip['renderer'];
|
|
8
8
|
valueFormat?: ChartTooltip['valueFormat'];
|
|
9
|
+
totals?: ChartTooltip['totals'];
|
|
9
10
|
}
|
|
10
11
|
export declare const ChartTooltipContent: (props: ChartTooltipContentProps) => React.JSX.Element | null;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import isNil from 'lodash/isNil';
|
|
3
|
-
import {
|
|
3
|
+
import { DefaultTooltipContent } from './DefaultTooltipContent';
|
|
4
4
|
export const ChartTooltipContent = (props) => {
|
|
5
|
-
const { hovered, xAxis, yAxis, renderer, valueFormat } = props;
|
|
5
|
+
const { hovered, xAxis, yAxis, renderer, valueFormat, totals } = props;
|
|
6
6
|
if (!hovered) {
|
|
7
7
|
return null;
|
|
8
8
|
}
|
|
9
9
|
const customTooltip = renderer === null || renderer === void 0 ? void 0 : renderer({ hovered, xAxis, yAxis });
|
|
10
|
-
return isNil(customTooltip) ? (React.createElement(
|
|
10
|
+
return isNil(customTooltip) ? (React.createElement(DefaultTooltipContent, { hovered: hovered, xAxis: xAxis, yAxis: yAxis, valueFormat: valueFormat, totals: totals })) : (customTooltip);
|
|
11
11
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { block } from '../../../utils';
|
|
3
|
+
const b = block('tooltip');
|
|
4
|
+
export function Row(props) {
|
|
5
|
+
const { label, value, active, color, className, striped } = props;
|
|
6
|
+
return (React.createElement("div", { className: b('content-row', { active, striped }, className) },
|
|
7
|
+
color && React.createElement("div", { className: b('content-row-color'), style: { backgroundColor: color } }),
|
|
8
|
+
label,
|
|
9
|
+
React.createElement("span", { className: b('content-row-value') }, value)));
|
|
10
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ValueFormat } from '../../../types';
|
|
3
|
+
import type { HoveredValue } from './utils';
|
|
4
|
+
export declare function RowTotals(props: {
|
|
5
|
+
aggregation: ChartTooltipTotalsBuiltInAggregation | (() => ChartTooltipTotalsAggregationValue);
|
|
6
|
+
values: HoveredValue[];
|
|
7
|
+
label?: string;
|
|
8
|
+
valueFormat?: ValueFormat;
|
|
9
|
+
}): React.JSX.Element;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { block } from '../../../utils';
|
|
3
|
+
import { getFormattedValue } from '../../../utils/chart/format';
|
|
4
|
+
import { Row } from './Row';
|
|
5
|
+
import { getBuiltInAggregatedValue, getBuiltInAggregationLabel } from './utils';
|
|
6
|
+
const b = block('tooltip');
|
|
7
|
+
export function RowTotals(props) {
|
|
8
|
+
const { aggregation, label, valueFormat, values } = props;
|
|
9
|
+
let resultLabel = label;
|
|
10
|
+
if (!resultLabel && typeof aggregation === 'string') {
|
|
11
|
+
resultLabel = getBuiltInAggregationLabel({ aggregation });
|
|
12
|
+
}
|
|
13
|
+
const resultValue = typeof aggregation === 'function'
|
|
14
|
+
? aggregation()
|
|
15
|
+
: getBuiltInAggregatedValue({ aggregation, values });
|
|
16
|
+
const formattedResultValue = typeof resultValue === 'number'
|
|
17
|
+
? getFormattedValue({
|
|
18
|
+
value: resultValue,
|
|
19
|
+
format: valueFormat || { type: 'number' },
|
|
20
|
+
})
|
|
21
|
+
: resultValue;
|
|
22
|
+
return (React.createElement(Row, { className: b('content-row-totals'), label: resultLabel, value: formattedResultValue }));
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { ChartTooltip, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../../types';
|
|
3
|
+
type Props = {
|
|
4
|
+
hovered: TooltipDataChunk[];
|
|
5
|
+
totals?: ChartTooltip['totals'];
|
|
6
|
+
valueFormat?: ValueFormat;
|
|
7
|
+
xAxis?: ChartXAxis | null;
|
|
8
|
+
yAxis?: ChartYAxis;
|
|
9
|
+
};
|
|
10
|
+
export declare const DefaultTooltipContent: ({ hovered, xAxis, yAxis, valueFormat, totals }: Props) => React.JSX.Element;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { Divider } from '@gravity-ui/uikit';
|
|
3
|
+
import get from 'lodash/get';
|
|
4
|
+
import { block } from '../../../utils';
|
|
5
|
+
import { getFormattedValue } from '../../../utils/chart/format';
|
|
6
|
+
import { Row } from './Row';
|
|
7
|
+
import { RowTotals } from './RowTotals';
|
|
8
|
+
import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getXRowData, } from './utils';
|
|
9
|
+
const b = block('tooltip');
|
|
10
|
+
export const DefaultTooltipContent = ({ hovered, xAxis, yAxis, valueFormat, totals }) => {
|
|
11
|
+
const measureValue = getMeasureValue({ data: hovered, xAxis, yAxis });
|
|
12
|
+
const hoveredValues = getHoveredValues({ hovered, xAxis, yAxis });
|
|
13
|
+
return (React.createElement("div", { className: b('content') },
|
|
14
|
+
measureValue && React.createElement("div", { className: b('series-name') }, measureValue),
|
|
15
|
+
// eslint-disable-next-line complexity
|
|
16
|
+
hovered.map((seriesItem, i) => {
|
|
17
|
+
var _a;
|
|
18
|
+
const { data, series, closest } = seriesItem;
|
|
19
|
+
const id = `${get(series, 'id')}_${i}`;
|
|
20
|
+
const color = get(series, 'color');
|
|
21
|
+
const active = closest && hovered.length > 1;
|
|
22
|
+
const striped = (i + 1) % 2 === 0;
|
|
23
|
+
switch (series.type) {
|
|
24
|
+
case 'scatter':
|
|
25
|
+
case 'line':
|
|
26
|
+
case 'area':
|
|
27
|
+
case 'bar-x': {
|
|
28
|
+
const format = valueFormat || getDefaultValueFormat({ axis: yAxis });
|
|
29
|
+
const formattedValue = getFormattedValue({
|
|
30
|
+
value: hoveredValues[i],
|
|
31
|
+
format,
|
|
32
|
+
});
|
|
33
|
+
return (React.createElement(Row, { key: id, active: active, color: color, label: series.name, striped: striped, value: formattedValue }));
|
|
34
|
+
}
|
|
35
|
+
case 'waterfall': {
|
|
36
|
+
const isTotal = get(data, 'total', false);
|
|
37
|
+
const subTotalValue = (_a = seriesItem.subTotal) !== null && _a !== void 0 ? _a : 0;
|
|
38
|
+
const format = valueFormat || getDefaultValueFormat({ axis: yAxis });
|
|
39
|
+
const subTotal = getFormattedValue({
|
|
40
|
+
value: subTotalValue,
|
|
41
|
+
format,
|
|
42
|
+
});
|
|
43
|
+
const formattedValue = getFormattedValue({
|
|
44
|
+
value: hoveredValues[i],
|
|
45
|
+
format,
|
|
46
|
+
});
|
|
47
|
+
return (React.createElement(React.Fragment, { key: id },
|
|
48
|
+
!isTotal && (React.createElement(React.Fragment, null,
|
|
49
|
+
React.createElement("div", { className: b('series-name') }, getXRowData(data, xAxis)),
|
|
50
|
+
React.createElement(Row, { label: series.name, value: formattedValue }))),
|
|
51
|
+
React.createElement(Row, { label: isTotal ? 'Total' : 'Subtotal', value: subTotal })));
|
|
52
|
+
}
|
|
53
|
+
case 'bar-y': {
|
|
54
|
+
const format = valueFormat || getDefaultValueFormat({ axis: xAxis });
|
|
55
|
+
const formattedValue = getFormattedValue({
|
|
56
|
+
value: hoveredValues[i],
|
|
57
|
+
format,
|
|
58
|
+
});
|
|
59
|
+
return (React.createElement(Row, { key: id, active: active, color: color, label: series.name, striped: striped, value: formattedValue }));
|
|
60
|
+
}
|
|
61
|
+
case 'pie':
|
|
62
|
+
case 'treemap': {
|
|
63
|
+
const seriesData = data;
|
|
64
|
+
const formattedValue = getFormattedValue({
|
|
65
|
+
value: hoveredValues[i],
|
|
66
|
+
format: valueFormat || { type: 'number' },
|
|
67
|
+
});
|
|
68
|
+
return (React.createElement(Row, { key: id, color: color, label: React.createElement("span", { dangerouslySetInnerHTML: {
|
|
69
|
+
__html: [seriesData.name || seriesData.id]
|
|
70
|
+
.flat()
|
|
71
|
+
.join('\n'),
|
|
72
|
+
} }), value: formattedValue }));
|
|
73
|
+
}
|
|
74
|
+
case 'sankey': {
|
|
75
|
+
const { target, data: source } = seriesItem;
|
|
76
|
+
const formattedValue = getFormattedValue({
|
|
77
|
+
value: hoveredValues[i],
|
|
78
|
+
format: valueFormat || { type: 'number' },
|
|
79
|
+
});
|
|
80
|
+
return (React.createElement(Row, { key: id, color: source.color, label: React.createElement("span", null,
|
|
81
|
+
source.name,
|
|
82
|
+
" \u2192 ", target === null || target === void 0 ? void 0 :
|
|
83
|
+
target.name,
|
|
84
|
+
":"), value: formattedValue }));
|
|
85
|
+
}
|
|
86
|
+
case 'radar': {
|
|
87
|
+
const radarSeries = series;
|
|
88
|
+
const formattedValue = getFormattedValue({
|
|
89
|
+
value: hoveredValues[i],
|
|
90
|
+
format: valueFormat || { type: 'number' },
|
|
91
|
+
});
|
|
92
|
+
return (React.createElement(Row, { key: id, active: active, color: color, label: radarSeries.name || radarSeries.id, value: formattedValue }));
|
|
93
|
+
}
|
|
94
|
+
default: {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}),
|
|
99
|
+
(totals === null || totals === void 0 ? void 0 : totals.enabled) && hovered.length > 1 && (React.createElement(React.Fragment, null,
|
|
100
|
+
React.createElement(Divider, { className: b('content-row-totals-divider') }),
|
|
101
|
+
React.createElement(RowTotals, { aggregation: getPreparedAggregation({ hovered, totals, xAxis, yAxis }), label: totals.label, values: hoveredValues, valueFormat: valueFormat })))));
|
|
102
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChartSeriesData, ChartTooltip, ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../../types';
|
|
2
|
+
export type HoveredValue = string | number | null | undefined;
|
|
3
|
+
export declare function getXRowData(data: ChartSeriesData, xAxis?: ChartXAxis | null): string | number | undefined;
|
|
4
|
+
export declare function getDefaultValueFormat({ axis, }: {
|
|
5
|
+
axis?: ChartXAxis | ChartYAxis | null;
|
|
6
|
+
}): ValueFormat | undefined;
|
|
7
|
+
export declare const getMeasureValue: ({ data, xAxis, yAxis, valueFormat, }: {
|
|
8
|
+
data: TooltipDataChunk[];
|
|
9
|
+
xAxis?: ChartXAxis | null;
|
|
10
|
+
yAxis?: ChartYAxis;
|
|
11
|
+
valueFormat?: ValueFormat;
|
|
12
|
+
}) => string | null;
|
|
13
|
+
export declare function getHoveredValues(args: {
|
|
14
|
+
hovered: TooltipDataChunk[];
|
|
15
|
+
xAxis?: ChartXAxis | null;
|
|
16
|
+
yAxis?: ChartYAxis;
|
|
17
|
+
}): HoveredValue[];
|
|
18
|
+
export declare function getBuiltInAggregatedValue(args: {
|
|
19
|
+
aggregation: ChartTooltipTotalsBuiltInAggregation;
|
|
20
|
+
values: HoveredValue[];
|
|
21
|
+
}): number | undefined;
|
|
22
|
+
export declare function getBuiltInAggregationLabel(args: {
|
|
23
|
+
aggregation: ChartTooltipTotalsBuiltInAggregation;
|
|
24
|
+
}): string;
|
|
25
|
+
export declare function getPreparedAggregation(args: {
|
|
26
|
+
hovered: TooltipDataChunk[];
|
|
27
|
+
totals?: ChartTooltip['totals'];
|
|
28
|
+
xAxis?: ChartXAxis | null;
|
|
29
|
+
yAxis?: ChartYAxis;
|
|
30
|
+
}): ChartTooltipTotalsBuiltInAggregation | (() => ChartTooltipTotalsAggregationValue);
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import get from 'lodash/get';
|
|
2
|
+
import { i18n } from '../../../i18n';
|
|
3
|
+
import { getDataCategoryValue } from '../../../utils';
|
|
4
|
+
import { getFormattedValue } from '../../../utils/chart/format';
|
|
5
|
+
const DEFAULT_DATE_FORMAT = 'DD.MM.YY';
|
|
6
|
+
function getRowData(fieldName, data, axis) {
|
|
7
|
+
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
8
|
+
case 'category': {
|
|
9
|
+
const categories = get(axis, 'categories', []);
|
|
10
|
+
return getDataCategoryValue({ axisDirection: fieldName, categories, data });
|
|
11
|
+
}
|
|
12
|
+
default: {
|
|
13
|
+
return get(data, fieldName);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function getXRowData(data, xAxis) {
|
|
18
|
+
return getRowData('x', data, xAxis);
|
|
19
|
+
}
|
|
20
|
+
function getYRowData(data, yAxis) {
|
|
21
|
+
return getRowData('y', data, yAxis);
|
|
22
|
+
}
|
|
23
|
+
export function getDefaultValueFormat({ axis, }) {
|
|
24
|
+
switch (axis === null || axis === void 0 ? void 0 : axis.type) {
|
|
25
|
+
case 'linear':
|
|
26
|
+
case 'logarithmic': {
|
|
27
|
+
return {
|
|
28
|
+
type: 'number',
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
case 'datetime': {
|
|
32
|
+
return {
|
|
33
|
+
type: 'date',
|
|
34
|
+
format: DEFAULT_DATE_FORMAT,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
default:
|
|
38
|
+
return undefined;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export const getMeasureValue = ({ data, xAxis, yAxis, valueFormat, }) => {
|
|
42
|
+
var _a, _b, _c, _d;
|
|
43
|
+
if (data.every((item) => ['pie', 'treemap', 'waterfall', 'sankey'].includes(item.series.type))) {
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
if (data.some((item) => item.series.type === 'radar')) {
|
|
47
|
+
return (_b = (_a = data[0].category) === null || _a === void 0 ? void 0 : _a.key) !== null && _b !== void 0 ? _b : null;
|
|
48
|
+
}
|
|
49
|
+
if (data.some((item) => item.series.type === 'bar-y')) {
|
|
50
|
+
const format = valueFormat !== null && valueFormat !== void 0 ? valueFormat : getDefaultValueFormat({ axis: yAxis });
|
|
51
|
+
return getFormattedValue({
|
|
52
|
+
value: getYRowData((_c = data[0]) === null || _c === void 0 ? void 0 : _c.data, yAxis),
|
|
53
|
+
format,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
const format = valueFormat !== null && valueFormat !== void 0 ? valueFormat : getDefaultValueFormat({ axis: xAxis });
|
|
57
|
+
return getFormattedValue({
|
|
58
|
+
value: getXRowData((_d = data[0]) === null || _d === void 0 ? void 0 : _d.data, xAxis),
|
|
59
|
+
format,
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
export function getHoveredValues(args) {
|
|
63
|
+
const { hovered, xAxis, yAxis } = args;
|
|
64
|
+
return hovered.map((seriesItem) => {
|
|
65
|
+
var _a;
|
|
66
|
+
const { data, series } = seriesItem;
|
|
67
|
+
switch (series.type) {
|
|
68
|
+
case 'area':
|
|
69
|
+
case 'line':
|
|
70
|
+
case 'bar-x':
|
|
71
|
+
case 'scatter': {
|
|
72
|
+
return getYRowData(data, yAxis);
|
|
73
|
+
}
|
|
74
|
+
case 'bar-y': {
|
|
75
|
+
return getXRowData(data, xAxis);
|
|
76
|
+
}
|
|
77
|
+
case 'pie':
|
|
78
|
+
case 'radar':
|
|
79
|
+
case 'treemap': {
|
|
80
|
+
const seriesData = data;
|
|
81
|
+
return seriesData.value;
|
|
82
|
+
}
|
|
83
|
+
case 'sankey': {
|
|
84
|
+
const { target, data: source } = seriesItem;
|
|
85
|
+
return (_a = source.links.find((d) => d.name === (target === null || target === void 0 ? void 0 : target.name))) === null || _a === void 0 ? void 0 : _a.value;
|
|
86
|
+
}
|
|
87
|
+
case 'waterfall': {
|
|
88
|
+
return getYRowData(data, yAxis);
|
|
89
|
+
}
|
|
90
|
+
default: {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
export function getBuiltInAggregatedValue(args) {
|
|
97
|
+
const { aggregation, values } = args;
|
|
98
|
+
switch (aggregation) {
|
|
99
|
+
case 'sum':
|
|
100
|
+
return values.reduce((acc, value) => {
|
|
101
|
+
return acc + (typeof value === 'number' ? value : 0);
|
|
102
|
+
}, 0);
|
|
103
|
+
default:
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
export function getBuiltInAggregationLabel(args) {
|
|
108
|
+
const { aggregation } = args;
|
|
109
|
+
switch (aggregation) {
|
|
110
|
+
case 'sum':
|
|
111
|
+
return i18n('tooltip', 'label_totals_sum');
|
|
112
|
+
default:
|
|
113
|
+
return '';
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
export function getPreparedAggregation(args) {
|
|
117
|
+
const { hovered, totals, xAxis, yAxis } = args;
|
|
118
|
+
const aggregation = totals === null || totals === void 0 ? void 0 : totals.aggregation;
|
|
119
|
+
if (typeof aggregation === 'string') {
|
|
120
|
+
return aggregation;
|
|
121
|
+
}
|
|
122
|
+
if (typeof aggregation === 'function') {
|
|
123
|
+
return () => aggregation({ hovered, xAxis, yAxis });
|
|
124
|
+
}
|
|
125
|
+
return 'sum';
|
|
126
|
+
}
|
|
@@ -23,5 +23,5 @@ export const Tooltip = (props) => {
|
|
|
23
23
|
}, [left, top]);
|
|
24
24
|
return (hovered === null || hovered === void 0 ? void 0 : hovered.length) ? (React.createElement(Popup, { anchorElement: anchor, className: b({ pinned: tooltipPinned }), disableTransition: true, floatingStyles: tooltipPinned ? undefined : { pointerEvents: 'none' }, offset: { mainAxis: 20 }, onOpenChange: tooltipPinned ? handleOnOpenChange : undefined, open: true, placement: ['right', 'left', 'top', 'bottom'] },
|
|
25
25
|
React.createElement("div", { className: b('popup-content') },
|
|
26
|
-
React.createElement(ChartTooltipContent, { hovered: hovered, xAxis: xAxis, yAxis: yAxis, renderer: tooltip.renderer, valueFormat: tooltip.valueFormat })))) : null;
|
|
26
|
+
React.createElement(ChartTooltipContent, { hovered: hovered, xAxis: xAxis, yAxis: yAxis, renderer: tooltip.renderer, valueFormat: tooltip.valueFormat, totals: tooltip.totals })))) : null;
|
|
27
27
|
};
|
|
@@ -17,18 +17,30 @@
|
|
|
17
17
|
.gcharts-tooltip__content-row {
|
|
18
18
|
display: flex;
|
|
19
19
|
align-items: center;
|
|
20
|
+
column-gap: 8px;
|
|
20
21
|
padding: 2px 14px;
|
|
21
22
|
font-size: 12px;
|
|
22
23
|
}
|
|
24
|
+
.gcharts-tooltip__content-row_striped {
|
|
25
|
+
background-color: var(--g-color-base-generic);
|
|
26
|
+
}
|
|
23
27
|
.gcharts-tooltip__content-row_active {
|
|
24
28
|
font-weight: 600;
|
|
25
29
|
background-color: var(--g-color-base-info-medium);
|
|
26
30
|
}
|
|
27
|
-
.gcharts-
|
|
31
|
+
.gcharts-tooltip__content-row-color {
|
|
28
32
|
display: inline-block;
|
|
29
33
|
width: 16px;
|
|
30
34
|
height: 8px;
|
|
31
|
-
margin-inline-end: 8px;
|
|
32
35
|
border-radius: 2px;
|
|
33
36
|
background-color: #dddddd;
|
|
37
|
+
}
|
|
38
|
+
.gcharts-tooltip__content-row-value {
|
|
39
|
+
margin-inline-start: auto;
|
|
40
|
+
}
|
|
41
|
+
.gcharts-tooltip__content-row-totals {
|
|
42
|
+
color: var(--g-color-text-complementary);
|
|
43
|
+
}
|
|
44
|
+
.gcharts-tooltip__content-row-totals-divider {
|
|
45
|
+
margin-block: 5px 5px;
|
|
34
46
|
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { ChartSeriesData, ChartTooltip, ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../types';
|
|
2
|
+
export type HoveredValue = string | number | null | undefined;
|
|
3
|
+
export declare function getXRowData(data: ChartSeriesData, xAxis?: ChartXAxis | null): string | number | undefined;
|
|
4
|
+
export declare function getDefaultValueFormat({ axis, }: {
|
|
5
|
+
axis?: ChartXAxis | ChartYAxis | null;
|
|
6
|
+
}): ValueFormat | undefined;
|
|
7
|
+
export declare const getMeasureValue: ({ data, xAxis, yAxis, valueFormat, }: {
|
|
8
|
+
data: TooltipDataChunk[];
|
|
9
|
+
xAxis?: ChartXAxis | null;
|
|
10
|
+
yAxis?: ChartYAxis;
|
|
11
|
+
valueFormat?: ValueFormat;
|
|
12
|
+
}) => string | null;
|
|
13
|
+
export declare function getHoveredValues(args: {
|
|
14
|
+
hovered: TooltipDataChunk[];
|
|
15
|
+
xAxis?: ChartXAxis | null;
|
|
16
|
+
yAxis?: ChartYAxis;
|
|
17
|
+
}): HoveredValue[];
|
|
18
|
+
export declare function getBuiltInAggregatedValue(args: {
|
|
19
|
+
aggregation: ChartTooltipTotalsBuiltInAggregation;
|
|
20
|
+
values: HoveredValue[];
|
|
21
|
+
}): number | undefined;
|
|
22
|
+
export declare function getBuiltInAggregationLabel(args: {
|
|
23
|
+
aggregation: ChartTooltipTotalsBuiltInAggregation;
|
|
24
|
+
}): string;
|
|
25
|
+
export declare function getPreparedAggregation(args: {
|
|
26
|
+
hovered: TooltipDataChunk[];
|
|
27
|
+
totals?: ChartTooltip['totals'];
|
|
28
|
+
xAxis?: ChartXAxis | null;
|
|
29
|
+
yAxis?: ChartYAxis;
|
|
30
|
+
}): ChartTooltipTotalsBuiltInAggregation | (() => ChartTooltipTotalsAggregationValue);
|