@gravity-ui/charts 1.15.0 → 1.16.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/Tooltip/ChartTooltipContent.d.ts +4 -2
- package/dist/cjs/components/Tooltip/ChartTooltipContent.js +2 -2
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.d.ts +2 -1
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +3 -3
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/{RowTotals.d.ts → RowWithAggregation.d.ts} +2 -1
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/{RowTotals.js → RowWithAggregation.js} +3 -3
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +4 -2
- package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +171 -114
- package/dist/cjs/components/Tooltip/index.js +1 -1
- package/dist/cjs/components/Tooltip/styles.css +11 -1
- package/dist/cjs/hooks/useSeries/prepare-area.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-bar-x.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +1 -0
- package/dist/cjs/hooks/useSeries/prepare-bar-y.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-line.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-pie.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-radar.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-sankey.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-scatter.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-treemap.js +1 -0
- package/dist/cjs/hooks/useSeries/prepare-waterfall.js +1 -0
- package/dist/cjs/hooks/useSeries/types.d.ts +2 -1
- package/dist/cjs/i18n/keysets/en.json +2 -1
- package/dist/cjs/i18n/keysets/ru.json +2 -1
- package/dist/cjs/types/chart/base.d.ts +13 -0
- package/dist/cjs/types/chart/tooltip.d.ts +5 -1
- package/dist/cjs/utils/chart/format.d.ts +9 -2
- package/dist/cjs/utils/chart/format.js +39 -5
- package/dist/cjs/utils/chart/index.d.ts +6 -10
- package/dist/cjs/utils/chart/index.js +6 -26
- package/dist/cjs/utils/misc.d.ts +1 -0
- package/dist/cjs/utils/misc.js +6 -0
- package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +4 -2
- package/dist/esm/components/Tooltip/ChartTooltipContent.js +2 -2
- package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.d.ts +2 -1
- package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +3 -3
- package/dist/esm/components/Tooltip/DefaultTooltipContent/{RowTotals.d.ts → RowWithAggregation.d.ts} +2 -1
- package/dist/esm/components/Tooltip/DefaultTooltipContent/{RowTotals.js → RowWithAggregation.js} +3 -3
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +4 -2
- package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +171 -114
- package/dist/esm/components/Tooltip/index.js +1 -1
- package/dist/esm/components/Tooltip/styles.css +11 -1
- package/dist/esm/hooks/useSeries/prepare-area.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-bar-x.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +1 -0
- package/dist/esm/hooks/useSeries/prepare-bar-y.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-line.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-pie.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-radar.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-sankey.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-scatter.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-treemap.js +1 -0
- package/dist/esm/hooks/useSeries/prepare-waterfall.js +1 -0
- package/dist/esm/hooks/useSeries/types.d.ts +2 -1
- package/dist/esm/i18n/keysets/en.json +2 -1
- package/dist/esm/i18n/keysets/ru.json +2 -1
- package/dist/esm/types/chart/base.d.ts +13 -0
- package/dist/esm/types/chart/tooltip.d.ts +5 -1
- package/dist/esm/utils/chart/format.d.ts +9 -2
- package/dist/esm/utils/chart/format.js +39 -5
- package/dist/esm/utils/chart/index.d.ts +6 -10
- package/dist/esm/utils/chart/index.js +6 -26
- package/dist/esm/utils/misc.d.ts +1 -0
- package/dist/esm/utils/misc.js +6 -0
- package/package.json +1 -1
|
@@ -2,11 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import type { ChartTooltip, ChartXAxis, ChartYAxis, TooltipDataChunk } from '../../types';
|
|
3
3
|
export interface ChartTooltipContentProps {
|
|
4
4
|
hovered?: TooltipDataChunk[];
|
|
5
|
-
|
|
6
|
-
yAxis?: ChartYAxis;
|
|
5
|
+
pinned?: boolean;
|
|
7
6
|
renderer?: ChartTooltip['renderer'];
|
|
8
7
|
rowRenderer?: ChartTooltip['rowRenderer'];
|
|
9
8
|
valueFormat?: ChartTooltip['valueFormat'];
|
|
9
|
+
headerFormat?: ChartTooltip['headerFormat'];
|
|
10
10
|
totals?: ChartTooltip['totals'];
|
|
11
|
+
xAxis?: ChartXAxis | null;
|
|
12
|
+
yAxis?: ChartYAxis;
|
|
11
13
|
}
|
|
12
14
|
export declare const ChartTooltipContent: (props: ChartTooltipContentProps) => React.JSX.Element | null;
|
|
@@ -2,10 +2,10 @@ import React from 'react';
|
|
|
2
2
|
import isNil from 'lodash/isNil';
|
|
3
3
|
import { DefaultTooltipContent } from './DefaultTooltipContent';
|
|
4
4
|
export const ChartTooltipContent = (props) => {
|
|
5
|
-
const { hovered, xAxis, yAxis, renderer, rowRenderer, valueFormat, totals } = props;
|
|
5
|
+
const { hovered, xAxis, yAxis, renderer, rowRenderer, valueFormat, headerFormat, totals, pinned, } = 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(DefaultTooltipContent, { hovered: hovered,
|
|
10
|
+
return isNil(customTooltip) ? (React.createElement(DefaultTooltipContent, { hovered: hovered, pinned: pinned, rowRenderer: rowRenderer, totals: totals, valueFormat: valueFormat, headerFormat: headerFormat, xAxis: xAxis, yAxis: yAxis })) : (customTooltip);
|
|
11
11
|
};
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
export declare function Row(props: {
|
|
3
3
|
label: React.ReactNode;
|
|
4
|
-
value: React.ReactNode;
|
|
5
4
|
active?: boolean;
|
|
6
5
|
className?: string;
|
|
7
6
|
color?: string;
|
|
8
7
|
striped?: boolean;
|
|
8
|
+
style?: React.CSSProperties;
|
|
9
|
+
value?: React.ReactNode;
|
|
9
10
|
}): React.JSX.Element;
|
|
@@ -2,9 +2,9 @@ import React from 'react';
|
|
|
2
2
|
import { block } from '../../../utils';
|
|
3
3
|
const b = block('tooltip');
|
|
4
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) },
|
|
5
|
+
const { label, value, active, color, className, striped, style } = props;
|
|
6
|
+
return (React.createElement("div", { className: b('content-row', { active, striped }, className), style: style },
|
|
7
7
|
color && React.createElement("div", { className: b('content-row-color'), style: { backgroundColor: color } }),
|
|
8
8
|
label,
|
|
9
|
-
React.createElement("span", { className: b('content-row-value') }, value)));
|
|
9
|
+
value && React.createElement("span", { className: b('content-row-value') }, value)));
|
|
10
10
|
}
|
package/dist/cjs/components/Tooltip/DefaultTooltipContent/{RowTotals.d.ts → RowWithAggregation.d.ts}
RENAMED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { ChartTooltipTotalsAggregationValue, ChartTooltipTotalsBuiltInAggregation, ValueFormat } from '../../../types';
|
|
3
3
|
import type { HoveredValue } from './utils';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function RowWithAggregation(props: {
|
|
5
5
|
aggregation: ChartTooltipTotalsBuiltInAggregation | (() => ChartTooltipTotalsAggregationValue);
|
|
6
6
|
values: HoveredValue[];
|
|
7
7
|
label?: string;
|
|
8
|
+
style?: React.CSSProperties;
|
|
8
9
|
valueFormat?: ValueFormat;
|
|
9
10
|
}): React.JSX.Element;
|
package/dist/cjs/components/Tooltip/DefaultTooltipContent/{RowTotals.js → RowWithAggregation.js}
RENAMED
|
@@ -4,8 +4,8 @@ import { getFormattedValue } from '../../../utils/chart/format';
|
|
|
4
4
|
import { Row } from './Row';
|
|
5
5
|
import { getBuiltInAggregatedValue, getBuiltInAggregationLabel } from './utils';
|
|
6
6
|
const b = block('tooltip');
|
|
7
|
-
export function
|
|
8
|
-
const { aggregation, label, valueFormat, values } = props;
|
|
7
|
+
export function RowWithAggregation(props) {
|
|
8
|
+
const { aggregation, label, style, valueFormat, values } = props;
|
|
9
9
|
let resultLabel = label;
|
|
10
10
|
if (!resultLabel && typeof aggregation === 'string') {
|
|
11
11
|
resultLabel = getBuiltInAggregationLabel({ aggregation });
|
|
@@ -19,5 +19,5 @@ export function RowTotals(props) {
|
|
|
19
19
|
format: valueFormat || { type: 'number' },
|
|
20
20
|
})
|
|
21
21
|
: resultValue;
|
|
22
|
-
return (React.createElement(Row, { className: b('content-row-totals'), label: resultLabel, value: formattedResultValue }));
|
|
22
|
+
return (React.createElement(Row, { className: b('content-row-totals'), label: resultLabel, style: style, value: formattedResultValue }));
|
|
23
23
|
}
|
|
@@ -2,11 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import type { ChartTooltip, ChartXAxis, ChartYAxis, TooltipDataChunk, ValueFormat } from '../../../types';
|
|
3
3
|
type Props = {
|
|
4
4
|
hovered: TooltipDataChunk[];
|
|
5
|
+
pinned?: boolean;
|
|
6
|
+
rowRenderer?: ChartTooltip['rowRenderer'];
|
|
5
7
|
totals?: ChartTooltip['totals'];
|
|
6
8
|
valueFormat?: ValueFormat;
|
|
9
|
+
headerFormat?: ChartTooltip['headerFormat'];
|
|
7
10
|
xAxis?: ChartXAxis | null;
|
|
8
11
|
yAxis?: ChartYAxis;
|
|
9
|
-
rowRenderer?: ChartTooltip['rowRenderer'];
|
|
10
12
|
};
|
|
11
|
-
export declare const DefaultTooltipContent: ({ hovered,
|
|
13
|
+
export declare const DefaultTooltipContent: ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, }: Props) => React.JSX.Element;
|
|
12
14
|
export {};
|
|
@@ -1,15 +1,26 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { Divider } from '@gravity-ui/uikit';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
|
-
import
|
|
4
|
+
import isEqual from 'lodash/isEqual';
|
|
5
|
+
import { usePrevious } from '../../../hooks';
|
|
6
|
+
import { i18n } from '../../../i18n';
|
|
7
|
+
import { block, hasVerticalScrollbar } from '../../../utils';
|
|
5
8
|
import { getFormattedValue } from '../../../utils/chart/format';
|
|
6
9
|
import { Row } from './Row';
|
|
7
|
-
import {
|
|
10
|
+
import { RowWithAggregation } from './RowWithAggregation';
|
|
8
11
|
import { getDefaultValueFormat, getHoveredValues, getMeasureValue, getPreparedAggregation, getXRowData, } from './utils';
|
|
9
12
|
const b = block('tooltip');
|
|
10
|
-
export const DefaultTooltipContent = ({ hovered,
|
|
13
|
+
export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, valueFormat, headerFormat, xAxis, yAxis, }) => {
|
|
14
|
+
var _a;
|
|
15
|
+
const [visibleRows, setVisibleRows] = React.useState();
|
|
16
|
+
const [maxContentRowsHeight, setMaxContentRowsHeight] = React.useState();
|
|
17
|
+
const [scrollBarWidth, setScrollBarWidth] = React.useState(0);
|
|
18
|
+
const contentRowsRef = React.useRef(null);
|
|
11
19
|
const measureValue = getMeasureValue({ data: hovered, xAxis, yAxis });
|
|
12
20
|
const hoveredValues = getHoveredValues({ hovered, xAxis, yAxis });
|
|
21
|
+
const prevHoveredValues = usePrevious(hoveredValues);
|
|
22
|
+
const visibleHovered = pinned || !visibleRows ? hovered : hovered.slice(0, visibleRows);
|
|
23
|
+
const restHoveredValues = pinned || !visibleRows ? [] : hoveredValues.slice(visibleRows);
|
|
13
24
|
const renderRow = ({ id, name, color, active, striped, value, formattedValue, }) => {
|
|
14
25
|
if (typeof rowRenderer === 'function') {
|
|
15
26
|
return rowRenderer({
|
|
@@ -26,120 +37,166 @@ export const DefaultTooltipContent = ({ hovered, xAxis, yAxis, valueFormat, tota
|
|
|
26
37
|
}
|
|
27
38
|
return (React.createElement(Row, { key: id, active: active, color: color, label: React.createElement("span", { dangerouslySetInnerHTML: { __html: name } }), striped: striped, value: formattedValue }));
|
|
28
39
|
};
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
active,
|
|
52
|
-
color,
|
|
53
|
-
name: series.name,
|
|
54
|
-
striped,
|
|
55
|
-
value: hoveredValues[i],
|
|
56
|
-
formattedValue,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
case 'waterfall': {
|
|
60
|
-
const isTotal = get(data, 'total', false);
|
|
61
|
-
const subTotalValue = (_a = seriesItem.subTotal) !== null && _a !== void 0 ? _a : 0;
|
|
62
|
-
const format = valueFormat || getDefaultValueFormat({ axis: yAxis });
|
|
63
|
-
const subTotal = getFormattedValue({
|
|
64
|
-
value: subTotalValue,
|
|
65
|
-
format,
|
|
66
|
-
});
|
|
67
|
-
const formattedValue = getFormattedValue({
|
|
68
|
-
value: hoveredValues[i],
|
|
69
|
-
format,
|
|
70
|
-
});
|
|
71
|
-
return (React.createElement(React.Fragment, { key: id },
|
|
72
|
-
!isTotal && (React.createElement(React.Fragment, null,
|
|
73
|
-
React.createElement("div", { className: b('series-name') }, getXRowData(data, xAxis)),
|
|
74
|
-
React.createElement(Row, { label: series.name, value: formattedValue }))),
|
|
75
|
-
React.createElement(Row, { label: isTotal ? 'Total' : 'Subtotal', value: subTotal })));
|
|
76
|
-
}
|
|
77
|
-
case 'bar-y': {
|
|
78
|
-
const format = valueFormat || getDefaultValueFormat({ axis: xAxis });
|
|
79
|
-
const formattedValue = getFormattedValue({
|
|
80
|
-
value: hoveredValues[i],
|
|
81
|
-
format,
|
|
82
|
-
});
|
|
83
|
-
return renderRow({
|
|
84
|
-
id,
|
|
85
|
-
active,
|
|
86
|
-
color,
|
|
87
|
-
name: series.name,
|
|
88
|
-
striped,
|
|
89
|
-
value: hoveredValues[i],
|
|
90
|
-
formattedValue,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
case 'pie':
|
|
94
|
-
case 'treemap': {
|
|
95
|
-
const seriesData = data;
|
|
96
|
-
const formattedValue = getFormattedValue({
|
|
97
|
-
value: hoveredValues[i],
|
|
98
|
-
format: valueFormat || { type: 'number' },
|
|
99
|
-
});
|
|
100
|
-
return renderRow({
|
|
101
|
-
id,
|
|
102
|
-
color,
|
|
103
|
-
name: [seriesData.name || seriesData.id].flat().join('\n'),
|
|
104
|
-
value: hoveredValues[i],
|
|
105
|
-
formattedValue,
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
case 'sankey': {
|
|
109
|
-
const { target, data: source } = seriesItem;
|
|
110
|
-
const formattedValue = getFormattedValue({
|
|
111
|
-
value: hoveredValues[i],
|
|
112
|
-
format: valueFormat || { type: 'number' },
|
|
113
|
-
});
|
|
114
|
-
return renderRow({
|
|
115
|
-
id,
|
|
116
|
-
color,
|
|
117
|
-
name: `${source.name} → ${target === null || target === void 0 ? void 0 : target.name}`,
|
|
118
|
-
value: hoveredValues[i],
|
|
119
|
-
formattedValue,
|
|
120
|
-
});
|
|
121
|
-
}
|
|
122
|
-
case 'radar': {
|
|
123
|
-
const radarSeries = series;
|
|
124
|
-
const formattedValue = getFormattedValue({
|
|
125
|
-
value: hoveredValues[i],
|
|
126
|
-
format: valueFormat || { type: 'number' },
|
|
127
|
-
});
|
|
128
|
-
return renderRow({
|
|
129
|
-
id,
|
|
130
|
-
color,
|
|
131
|
-
active,
|
|
132
|
-
name: radarSeries.name || radarSeries.id,
|
|
133
|
-
value: hoveredValues[i],
|
|
134
|
-
formattedValue,
|
|
135
|
-
});
|
|
40
|
+
const formattedHeadValue = headerFormat
|
|
41
|
+
? getFormattedValue({ value: measureValue, format: headerFormat })
|
|
42
|
+
: measureValue;
|
|
43
|
+
React.useEffect(() => {
|
|
44
|
+
if (!contentRowsRef.current) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (!hasVerticalScrollbar(contentRowsRef.current)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (!isEqual(hoveredValues, prevHoveredValues)) {
|
|
51
|
+
const { clientHeight } = contentRowsRef.current;
|
|
52
|
+
const { top: containerTop } = contentRowsRef.current.getBoundingClientRect();
|
|
53
|
+
const rows = contentRowsRef.current.querySelectorAll(`.${b('content-row')}`);
|
|
54
|
+
let nextVisibleRows = 0;
|
|
55
|
+
let nextMaxContentRowsHeight = 0;
|
|
56
|
+
for (let i = 0; i < rows.length; i++) {
|
|
57
|
+
const row = rows[i];
|
|
58
|
+
const { top, height } = row.getBoundingClientRect();
|
|
59
|
+
if (top - containerTop + height <= clientHeight) {
|
|
60
|
+
nextVisibleRows += 1;
|
|
61
|
+
nextMaxContentRowsHeight += height;
|
|
136
62
|
}
|
|
137
|
-
|
|
138
|
-
|
|
63
|
+
else {
|
|
64
|
+
break;
|
|
139
65
|
}
|
|
140
66
|
}
|
|
141
|
-
|
|
67
|
+
setVisibleRows(nextVisibleRows - 1);
|
|
68
|
+
setMaxContentRowsHeight(nextMaxContentRowsHeight);
|
|
69
|
+
}
|
|
70
|
+
}, [hoveredValues, prevHoveredValues]);
|
|
71
|
+
React.useEffect(() => {
|
|
72
|
+
if (!contentRowsRef.current) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
if (pinned) {
|
|
76
|
+
const { offsetWidth, clientWidth } = contentRowsRef.current;
|
|
77
|
+
setScrollBarWidth(offsetWidth - clientWidth);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
setScrollBarWidth(0);
|
|
81
|
+
}
|
|
82
|
+
}, [pinned]);
|
|
83
|
+
return (React.createElement("div", { className: b('content') },
|
|
84
|
+
formattedHeadValue && (React.createElement("div", { className: b('series-name'), dangerouslySetInnerHTML: { __html: formattedHeadValue } })),
|
|
85
|
+
React.createElement("div", { className: b('content-rows', { pinned }), ref: contentRowsRef, style: { maxHeight: maxContentRowsHeight } },
|
|
86
|
+
visibleHovered.map((seriesItem, i) => {
|
|
87
|
+
var _a;
|
|
88
|
+
const { data, series, closest } = seriesItem;
|
|
89
|
+
const id = `${get(series, 'id')}_${i}`;
|
|
90
|
+
const color = get(data, 'color') || get(series, 'color');
|
|
91
|
+
// TODO: improve action item display https://github.com/gravity-ui/charts/issues/208
|
|
92
|
+
const active = closest && hovered.length > 1;
|
|
93
|
+
const striped = (i + 1) % 2 === 0;
|
|
94
|
+
const rowValueFormat = get(series, 'tooltip.valueFormat', valueFormat);
|
|
95
|
+
switch (series.type) {
|
|
96
|
+
case 'scatter':
|
|
97
|
+
case 'line':
|
|
98
|
+
case 'area':
|
|
99
|
+
case 'bar-x': {
|
|
100
|
+
const format = rowValueFormat || getDefaultValueFormat({ axis: yAxis });
|
|
101
|
+
const formattedValue = getFormattedValue({
|
|
102
|
+
value: hoveredValues[i],
|
|
103
|
+
format,
|
|
104
|
+
});
|
|
105
|
+
return renderRow({
|
|
106
|
+
id,
|
|
107
|
+
active,
|
|
108
|
+
color,
|
|
109
|
+
name: series.name,
|
|
110
|
+
striped,
|
|
111
|
+
value: hoveredValues[i],
|
|
112
|
+
formattedValue,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
case 'waterfall': {
|
|
116
|
+
const isTotal = get(data, 'total', false);
|
|
117
|
+
const subTotalValue = (_a = seriesItem.subTotal) !== null && _a !== void 0 ? _a : 0;
|
|
118
|
+
const format = rowValueFormat || getDefaultValueFormat({ axis: yAxis });
|
|
119
|
+
const subTotal = getFormattedValue({
|
|
120
|
+
value: subTotalValue,
|
|
121
|
+
format,
|
|
122
|
+
});
|
|
123
|
+
const formattedValue = getFormattedValue({
|
|
124
|
+
value: hoveredValues[i],
|
|
125
|
+
format,
|
|
126
|
+
});
|
|
127
|
+
return (React.createElement(React.Fragment, { key: id },
|
|
128
|
+
!isTotal && (React.createElement(React.Fragment, null,
|
|
129
|
+
React.createElement("div", { className: b('series-name') }, getXRowData(data, xAxis)),
|
|
130
|
+
React.createElement(Row, { label: series.name, value: formattedValue }))),
|
|
131
|
+
React.createElement(Row, { label: isTotal ? 'Total' : 'Subtotal', value: subTotal })));
|
|
132
|
+
}
|
|
133
|
+
case 'bar-y': {
|
|
134
|
+
const format = rowValueFormat || getDefaultValueFormat({ axis: xAxis });
|
|
135
|
+
const formattedValue = getFormattedValue({
|
|
136
|
+
value: hoveredValues[i],
|
|
137
|
+
format,
|
|
138
|
+
});
|
|
139
|
+
return renderRow({
|
|
140
|
+
id,
|
|
141
|
+
active,
|
|
142
|
+
color,
|
|
143
|
+
name: series.name,
|
|
144
|
+
striped,
|
|
145
|
+
value: hoveredValues[i],
|
|
146
|
+
formattedValue,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
case 'pie':
|
|
150
|
+
case 'treemap': {
|
|
151
|
+
const seriesData = data;
|
|
152
|
+
const formattedValue = getFormattedValue({
|
|
153
|
+
value: hoveredValues[i],
|
|
154
|
+
format: rowValueFormat || { type: 'number' },
|
|
155
|
+
});
|
|
156
|
+
return renderRow({
|
|
157
|
+
id,
|
|
158
|
+
color,
|
|
159
|
+
name: [seriesData.name || seriesData.id].flat().join('\n'),
|
|
160
|
+
value: hoveredValues[i],
|
|
161
|
+
formattedValue,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
case 'sankey': {
|
|
165
|
+
const { target, data: source } = seriesItem;
|
|
166
|
+
const formattedValue = getFormattedValue({
|
|
167
|
+
value: hoveredValues[i],
|
|
168
|
+
format: rowValueFormat || { type: 'number' },
|
|
169
|
+
});
|
|
170
|
+
return renderRow({
|
|
171
|
+
id,
|
|
172
|
+
color,
|
|
173
|
+
name: `${source.name} → ${target === null || target === void 0 ? void 0 : target.name}`,
|
|
174
|
+
value: hoveredValues[i],
|
|
175
|
+
formattedValue,
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
case 'radar': {
|
|
179
|
+
const radarSeries = series;
|
|
180
|
+
const formattedValue = getFormattedValue({
|
|
181
|
+
value: hoveredValues[i],
|
|
182
|
+
format: rowValueFormat || { type: 'number' },
|
|
183
|
+
});
|
|
184
|
+
return renderRow({
|
|
185
|
+
id,
|
|
186
|
+
color,
|
|
187
|
+
active,
|
|
188
|
+
name: radarSeries.name || radarSeries.id,
|
|
189
|
+
value: hoveredValues[i],
|
|
190
|
+
formattedValue,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
default: {
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}),
|
|
198
|
+
Boolean(restHoveredValues.length) && (React.createElement(Row, { label: i18n('tooltip', 'label_more', { count: restHoveredValues.length }), striped: (visibleHovered.length + 1) % 2 === 0 }))),
|
|
142
199
|
(totals === null || totals === void 0 ? void 0 : totals.enabled) && hovered.length > 1 && (React.createElement(React.Fragment, null,
|
|
143
200
|
React.createElement(Divider, { className: b('content-row-totals-divider') }),
|
|
144
|
-
React.createElement(
|
|
201
|
+
React.createElement(RowWithAggregation, { aggregation: getPreparedAggregation({ hovered, totals, xAxis, yAxis }), label: totals.label, style: { marginRight: scrollBarWidth }, values: hoveredValues, valueFormat: (_a = totals.valueFormat) !== null && _a !== void 0 ? _a : valueFormat })))));
|
|
145
202
|
};
|
|
@@ -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,
|
|
26
|
+
React.createElement(ChartTooltipContent, { hovered: hovered, pinned: tooltipPinned, renderer: tooltip.renderer, rowRenderer: tooltip.rowRenderer, totals: tooltip.totals, valueFormat: tooltip.valueFormat, headerFormat: tooltip.headerFormat, xAxis: xAxis, yAxis: yAxis })))) : null;
|
|
27
27
|
};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
.gcharts-tooltip {
|
|
2
|
+
padding: var(--gcharts-tooltip-content-padding, 8px 0);
|
|
2
3
|
box-shadow: 0 2px 12px var(--g-color-sfx-shadow);
|
|
3
4
|
}
|
|
4
5
|
.gcharts-tooltip__popup-content {
|
|
@@ -7,7 +8,16 @@
|
|
|
7
8
|
background-color: var(--g-color-infographics-tooltip-bg);
|
|
8
9
|
}
|
|
9
10
|
.gcharts-tooltip__content {
|
|
10
|
-
|
|
11
|
+
display: flex;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
flex-direction: column;
|
|
14
|
+
max-height: 90vh;
|
|
15
|
+
}
|
|
16
|
+
.gcharts-tooltip__content-rows {
|
|
17
|
+
overflow: hidden;
|
|
18
|
+
}
|
|
19
|
+
.gcharts-tooltip__content-rows_pinned {
|
|
20
|
+
overflow: auto;
|
|
11
21
|
}
|
|
12
22
|
.gcharts-tooltip__series-name {
|
|
13
23
|
padding: 2px 14px 6px;
|
|
@@ -52,6 +52,7 @@ export function prepareBarYSeries(args) {
|
|
|
52
52
|
borderRadius: (_c = (_a = series.borderRadius) !== null && _a !== void 0 ? _a : (_b = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _b === void 0 ? void 0 : _b.borderRadius) !== null && _c !== void 0 ? _c : 0,
|
|
53
53
|
borderWidth: (_f = (_d = series.borderWidth) !== null && _d !== void 0 ? _d : (_e = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _e === void 0 ? void 0 : _e.borderWidth) !== null && _f !== void 0 ? _f : 0,
|
|
54
54
|
borderColor: (_j = (_g = series.borderColor) !== null && _g !== void 0 ? _g : (_h = seriesOptions === null || seriesOptions === void 0 ? void 0 : seriesOptions['bar-y']) === null || _h === void 0 ? void 0 : _h.borderColor) !== null && _j !== void 0 ? _j : 'var(--gcharts-shape-border-color)',
|
|
55
|
+
tooltip: series.tooltip,
|
|
55
56
|
};
|
|
56
57
|
}));
|
|
57
58
|
}
|
|
@@ -34,6 +34,7 @@ export function prepareTreemap(args) {
|
|
|
34
34
|
layoutAlgorithm: get(s, 'layoutAlgorithm', LayoutAlgorithm.Binary),
|
|
35
35
|
cursor: get(s, 'cursor', null),
|
|
36
36
|
sorting: Object.assign({ enabled: false, direction: 'desc' }, s.sorting),
|
|
37
|
+
tooltip: s.tooltip,
|
|
37
38
|
};
|
|
38
39
|
return preparedSeries;
|
|
39
40
|
});
|
|
@@ -28,6 +28,7 @@ export function prepareWaterfallSeries(args) {
|
|
|
28
28
|
},
|
|
29
29
|
cursor: get(series, 'cursor', null),
|
|
30
30
|
data: [],
|
|
31
|
+
tooltip: series.tooltip,
|
|
31
32
|
};
|
|
32
33
|
const positive = Object.assign(Object.assign({}, common), { name: (_g = (_f = (_e = series.legend) === null || _e === void 0 ? void 0 : _e.itemText) === null || _f === void 0 ? void 0 : _f.positive) !== null && _g !== void 0 ? _g : `${series.name} ↑`, id: getUniqId(), color: series.positiveColor || positiveColor, data: [] });
|
|
33
34
|
const negative = Object.assign(Object.assign({}, common), { name: (_k = (_j = (_h = series.legend) === null || _h === void 0 ? void 0 : _h.itemText) === null || _j === void 0 ? void 0 : _j.negative) !== null && _k !== void 0 ? _k : `${series.name} ↓`, id: getUniqId(), color: series.negativeColor || negativeColor, data: [] });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { DashStyle, LayoutAlgorithm, LineCap, SeriesOptionsDefaults, SymbolType } from '../../constants';
|
|
2
|
-
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
2
|
+
import type { AreaSeries, AreaSeriesData, BarXSeries, BarXSeriesData, BarYSeries, BarYSeriesData, BaseTextStyle, ChartLegend, ChartSeries, ConnectorCurve, ConnectorShape, LineSeries, LineSeriesData, PathLegendSymbolOptions, PieSeries, PieSeriesData, RadarSeries, RadarSeriesCategory, RadarSeriesData, RectLegendSymbolOptions, SankeySeries, SankeySeriesData, ScatterSeries, ScatterSeriesData, SymbolLegendSymbolOptions, TreemapSeries, TreemapSeriesData, ValueFormat, WaterfallSeries, WaterfallSeriesData } from '../../types';
|
|
3
3
|
export type RectLegendSymbol = {
|
|
4
4
|
shape: 'rect';
|
|
5
5
|
} & Required<RectLegendSymbolOptions>;
|
|
@@ -76,6 +76,7 @@ type BasePreparedSeries = {
|
|
|
76
76
|
symbol: PreparedLegendSymbol;
|
|
77
77
|
};
|
|
78
78
|
cursor: string | null;
|
|
79
|
+
tooltip: ChartSeries['tooltip'];
|
|
79
80
|
};
|
|
80
81
|
export type PreparedScatterSeries = {
|
|
81
82
|
type: ScatterSeries['type'];
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"label_invalid-axis-labels-html-not-supported-axis-type": "It seems you are trying to use \"labels.html\" property for an axis with an unsupported type. This property is supported only for \"category\" axis."
|
|
22
22
|
},
|
|
23
23
|
"tooltip": {
|
|
24
|
-
"label_totals_sum": "Sum"
|
|
24
|
+
"label_totals_sum": "Sum",
|
|
25
|
+
"label_more": "{{count}} more"
|
|
25
26
|
}
|
|
26
27
|
}
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"label_invalid-axis-labels-html-not-supported-axis-type": "Похоже, что вы пытаетесь использовать свойство \"labels.html\" для оси с неподдерживаемым типом. Это свойство поддерживается только для оси типа \"category\"."
|
|
22
22
|
},
|
|
23
23
|
"tooltip": {
|
|
24
|
-
"label_totals_sum": "Сумма"
|
|
24
|
+
"label_totals_sum": "Сумма",
|
|
25
|
+
"label_more": "Еще {{count}}"
|
|
25
26
|
}
|
|
26
27
|
}
|
|
@@ -7,6 +7,12 @@ type DateFormat = {
|
|
|
7
7
|
type: 'date';
|
|
8
8
|
format?: string;
|
|
9
9
|
};
|
|
10
|
+
export type CustomFormat = {
|
|
11
|
+
type: 'custom';
|
|
12
|
+
formatter: (args: {
|
|
13
|
+
value: unknown;
|
|
14
|
+
}) => string;
|
|
15
|
+
};
|
|
10
16
|
export type ValueFormat = NumberFormat | DateFormat;
|
|
11
17
|
export interface BaseSeries {
|
|
12
18
|
/** Initial visibility of the series */
|
|
@@ -41,6 +47,13 @@ export interface BaseSeries {
|
|
|
41
47
|
};
|
|
42
48
|
/** You can set the cursor to "pointer" if you have click events attached to the series, to signal to the user that the points and lines can be clicked. */
|
|
43
49
|
cursor?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Options for the tooltip that appears when the user hovers over a series or point.
|
|
52
|
+
*/
|
|
53
|
+
tooltip?: {
|
|
54
|
+
/** Formatting settings for tooltip value. */
|
|
55
|
+
valueFormat?: ValueFormat;
|
|
56
|
+
};
|
|
44
57
|
}
|
|
45
58
|
export interface BaseSeriesData<T = MeaningfulAny> {
|
|
46
59
|
/**
|
|
@@ -4,7 +4,7 @@ import type { AreaSeries, AreaSeriesData } from './area';
|
|
|
4
4
|
import type { ChartXAxis, ChartYAxis } from './axis';
|
|
5
5
|
import type { BarXSeries, BarXSeriesData } from './bar-x';
|
|
6
6
|
import type { BarYSeries, BarYSeriesData } from './bar-y';
|
|
7
|
-
import type { ValueFormat } from './base';
|
|
7
|
+
import type { CustomFormat, ValueFormat } from './base';
|
|
8
8
|
import type { LineSeries, LineSeriesData } from './line';
|
|
9
9
|
import type { PieSeries, PieSeriesData } from './pie';
|
|
10
10
|
import type { RadarSeries, RadarSeriesCategory, RadarSeriesData } from './radar';
|
|
@@ -110,6 +110,8 @@ export interface ChartTooltip<T = MeaningfulAny> {
|
|
|
110
110
|
throttle?: number;
|
|
111
111
|
/** Formatting settings for tooltip value. */
|
|
112
112
|
valueFormat?: ValueFormat;
|
|
113
|
+
/** Formatting settings for tooltip header row. */
|
|
114
|
+
headerFormat?: ValueFormat | CustomFormat;
|
|
113
115
|
/** Settings for totals block in tooltip */
|
|
114
116
|
totals?: {
|
|
115
117
|
/**
|
|
@@ -125,5 +127,7 @@ export interface ChartTooltip<T = MeaningfulAny> {
|
|
|
125
127
|
enabled?: boolean;
|
|
126
128
|
/** The label text for the totals. For built-in aggregations, the label can be omitted. */
|
|
127
129
|
label?: string;
|
|
130
|
+
/** Formatting settings for totals tooltip value. */
|
|
131
|
+
valueFormat?: ValueFormat;
|
|
128
132
|
};
|
|
129
133
|
}
|