@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.
Files changed (65) hide show
  1. package/dist/cjs/components/Tooltip/ChartTooltipContent.d.ts +4 -2
  2. package/dist/cjs/components/Tooltip/ChartTooltipContent.js +2 -2
  3. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.d.ts +2 -1
  4. package/dist/cjs/components/Tooltip/DefaultTooltipContent/Row.js +3 -3
  5. package/dist/cjs/components/Tooltip/DefaultTooltipContent/{RowTotals.d.ts → RowWithAggregation.d.ts} +2 -1
  6. package/dist/cjs/components/Tooltip/DefaultTooltipContent/{RowTotals.js → RowWithAggregation.js} +3 -3
  7. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.d.ts +4 -2
  8. package/dist/cjs/components/Tooltip/DefaultTooltipContent/index.js +171 -114
  9. package/dist/cjs/components/Tooltip/index.js +1 -1
  10. package/dist/cjs/components/Tooltip/styles.css +11 -1
  11. package/dist/cjs/hooks/useSeries/prepare-area.js +1 -0
  12. package/dist/cjs/hooks/useSeries/prepare-bar-x.js +1 -0
  13. package/dist/cjs/hooks/useSeries/prepare-bar-y.d.ts +1 -0
  14. package/dist/cjs/hooks/useSeries/prepare-bar-y.js +1 -0
  15. package/dist/cjs/hooks/useSeries/prepare-line.js +1 -0
  16. package/dist/cjs/hooks/useSeries/prepare-pie.js +1 -0
  17. package/dist/cjs/hooks/useSeries/prepare-radar.js +1 -0
  18. package/dist/cjs/hooks/useSeries/prepare-sankey.js +1 -0
  19. package/dist/cjs/hooks/useSeries/prepare-scatter.js +1 -0
  20. package/dist/cjs/hooks/useSeries/prepare-treemap.js +1 -0
  21. package/dist/cjs/hooks/useSeries/prepare-waterfall.js +1 -0
  22. package/dist/cjs/hooks/useSeries/types.d.ts +2 -1
  23. package/dist/cjs/i18n/keysets/en.json +2 -1
  24. package/dist/cjs/i18n/keysets/ru.json +2 -1
  25. package/dist/cjs/types/chart/base.d.ts +13 -0
  26. package/dist/cjs/types/chart/tooltip.d.ts +5 -1
  27. package/dist/cjs/utils/chart/format.d.ts +9 -2
  28. package/dist/cjs/utils/chart/format.js +39 -5
  29. package/dist/cjs/utils/chart/index.d.ts +6 -10
  30. package/dist/cjs/utils/chart/index.js +6 -26
  31. package/dist/cjs/utils/misc.d.ts +1 -0
  32. package/dist/cjs/utils/misc.js +6 -0
  33. package/dist/esm/components/Tooltip/ChartTooltipContent.d.ts +4 -2
  34. package/dist/esm/components/Tooltip/ChartTooltipContent.js +2 -2
  35. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.d.ts +2 -1
  36. package/dist/esm/components/Tooltip/DefaultTooltipContent/Row.js +3 -3
  37. package/dist/esm/components/Tooltip/DefaultTooltipContent/{RowTotals.d.ts → RowWithAggregation.d.ts} +2 -1
  38. package/dist/esm/components/Tooltip/DefaultTooltipContent/{RowTotals.js → RowWithAggregation.js} +3 -3
  39. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.d.ts +4 -2
  40. package/dist/esm/components/Tooltip/DefaultTooltipContent/index.js +171 -114
  41. package/dist/esm/components/Tooltip/index.js +1 -1
  42. package/dist/esm/components/Tooltip/styles.css +11 -1
  43. package/dist/esm/hooks/useSeries/prepare-area.js +1 -0
  44. package/dist/esm/hooks/useSeries/prepare-bar-x.js +1 -0
  45. package/dist/esm/hooks/useSeries/prepare-bar-y.d.ts +1 -0
  46. package/dist/esm/hooks/useSeries/prepare-bar-y.js +1 -0
  47. package/dist/esm/hooks/useSeries/prepare-line.js +1 -0
  48. package/dist/esm/hooks/useSeries/prepare-pie.js +1 -0
  49. package/dist/esm/hooks/useSeries/prepare-radar.js +1 -0
  50. package/dist/esm/hooks/useSeries/prepare-sankey.js +1 -0
  51. package/dist/esm/hooks/useSeries/prepare-scatter.js +1 -0
  52. package/dist/esm/hooks/useSeries/prepare-treemap.js +1 -0
  53. package/dist/esm/hooks/useSeries/prepare-waterfall.js +1 -0
  54. package/dist/esm/hooks/useSeries/types.d.ts +2 -1
  55. package/dist/esm/i18n/keysets/en.json +2 -1
  56. package/dist/esm/i18n/keysets/ru.json +2 -1
  57. package/dist/esm/types/chart/base.d.ts +13 -0
  58. package/dist/esm/types/chart/tooltip.d.ts +5 -1
  59. package/dist/esm/utils/chart/format.d.ts +9 -2
  60. package/dist/esm/utils/chart/format.js +39 -5
  61. package/dist/esm/utils/chart/index.d.ts +6 -10
  62. package/dist/esm/utils/chart/index.js +6 -26
  63. package/dist/esm/utils/misc.d.ts +1 -0
  64. package/dist/esm/utils/misc.js +6 -0
  65. 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
- xAxis?: ChartXAxis | null;
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, xAxis: xAxis, yAxis: yAxis, valueFormat: valueFormat, totals: totals, rowRenderer: rowRenderer })) : (customTooltip);
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
  }
@@ -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 RowTotals(props: {
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;
@@ -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 RowTotals(props) {
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, xAxis, yAxis, valueFormat, totals, rowRenderer, }: Props) => React.JSX.Element;
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 { block } from '../../../utils';
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 { RowTotals } from './RowTotals';
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, xAxis, yAxis, valueFormat, totals, rowRenderer, }) => {
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
- return (React.createElement("div", { className: b('content') },
30
- measureValue && (React.createElement("div", { className: b('series-name'), dangerouslySetInnerHTML: { __html: measureValue } })),
31
- // eslint-disable-next-line complexity
32
- hovered.map((seriesItem, i) => {
33
- var _a;
34
- const { data, series, closest } = seriesItem;
35
- const id = `${get(series, 'id')}_${i}`;
36
- const color = get(data, 'color') || get(series, 'color');
37
- const active = closest && hovered.length > 1;
38
- const striped = (i + 1) % 2 === 0;
39
- switch (series.type) {
40
- case 'scatter':
41
- case 'line':
42
- case 'area':
43
- case 'bar-x': {
44
- const format = valueFormat || getDefaultValueFormat({ axis: yAxis });
45
- const formattedValue = getFormattedValue({
46
- value: hoveredValues[i],
47
- format,
48
- });
49
- return renderRow({
50
- id,
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
- default: {
138
- return null;
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(RowTotals, { aggregation: getPreparedAggregation({ hovered, totals, xAxis, yAxis }), label: totals.label, values: hoveredValues, valueFormat: valueFormat })))));
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, xAxis: xAxis, yAxis: yAxis, renderer: tooltip.renderer, rowRenderer: tooltip.rowRenderer, valueFormat: tooltip.valueFormat, totals: tooltip.totals })))) : null;
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
- padding: var(--gcharts-tooltip-content-padding, 8px 0);
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;
@@ -59,6 +59,7 @@ export function prepareArea(args) {
59
59
  marker: prepareMarker(series, seriesOptions),
60
60
  cursor: get(series, 'cursor', null),
61
61
  yAxis: get(series, 'yAxis', 0),
62
+ tooltip: series.tooltip,
62
63
  };
63
64
  return prepared;
64
65
  }, []);
@@ -36,6 +36,7 @@ export function prepareBarXSeries(args) {
36
36
  cursor: get(series, 'cursor', null),
37
37
  yAxis: get(series, 'yAxis', 0),
38
38
  borderRadius: get(series, 'borderRadius', get(seriesOptions, 'bar-x.borderRadius', 0)),
39
+ tooltip: series.tooltip,
39
40
  };
40
41
  }, []);
41
42
  }
@@ -35,5 +35,6 @@ export declare function prepareBarYSeries(args: PrepareBarYSeriesArgs): Promise<
35
35
  symbol: import("./types").PreparedLegendSymbol;
36
36
  };
37
37
  cursor: string | null;
38
+ tooltip: import("../../types").ChartSeries["tooltip"];
38
39
  })[]>;
39
40
  export {};
@@ -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
  }
@@ -77,6 +77,7 @@ export function prepareLineSeries(args) {
77
77
  opacity: get(series, 'opacity', null),
78
78
  cursor: get(series, 'cursor', null),
79
79
  yAxis: get(series, 'yAxis', 0),
80
+ tooltip: series.tooltip,
80
81
  };
81
82
  return prepared;
82
83
  }, []);
@@ -57,6 +57,7 @@ export function preparePieSeries(args) {
57
57
  renderCustomShape: series.renderCustomShape,
58
58
  opacity: get(dataItem, 'opacity', null),
59
59
  cursor: get(series, 'cursor', null),
60
+ tooltip: series.tooltip,
60
61
  };
61
62
  return result;
62
63
  });
@@ -58,6 +58,7 @@ export function prepareRadarSeries(args) {
58
58
  },
59
59
  cursor: get(series, 'cursor', null),
60
60
  marker: prepareMarker(series, seriesOptions),
61
+ tooltip: series.tooltip,
61
62
  };
62
63
  return preparedSeries;
63
64
  });
@@ -33,6 +33,7 @@ export function prepareSankeySeries(args) {
33
33
  symbol: prepareLegendSymbol(s),
34
34
  },
35
35
  cursor: get(s, 'cursor', null),
36
+ tooltip: s.tooltip,
36
37
  };
37
38
  return preparedSeries;
38
39
  });
@@ -40,6 +40,7 @@ export function prepareScatterSeries(args) {
40
40
  marker: prepareMarker(s, seriesOptions, index),
41
41
  cursor: get(s, 'cursor', null),
42
42
  yAxis: get(s, 'yAxis', 0),
43
+ tooltip: s.tooltip,
43
44
  };
44
45
  return prepared;
45
46
  }, []);
@@ -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
  }