@gravity-ui/charts 1.38.2 → 1.38.3

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.
@@ -4,7 +4,7 @@ import get from 'lodash/get';
4
4
  import isEqual from 'lodash/isEqual';
5
5
  import { usePrevious } from '../../../hooks';
6
6
  import { i18n } from '../../../i18n';
7
- import { block, hasVerticalScrollbar } from '../../../utils';
7
+ import { block } from '../../../utils';
8
8
  import { getFormattedValue } from '../../../utils/chart/format';
9
9
  import { Row } from './Row';
10
10
  import { RowWithAggregation } from './RowWithAggregation';
@@ -52,30 +52,17 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
52
52
  if (!contentRowsRef.current) {
53
53
  return;
54
54
  }
55
- if (!hasVerticalScrollbar(contentRowsRef.current)) {
55
+ if (isEqual(hoveredValues, prevHoveredValues)) {
56
56
  return;
57
57
  }
58
- if (!isEqual(hoveredValues, prevHoveredValues)) {
59
- const { clientHeight } = contentRowsRef.current;
60
- const { top: containerTop } = contentRowsRef.current.getBoundingClientRect();
61
- const rows = contentRowsRef.current.querySelectorAll(`.${b('content-row')}`);
62
- let nextVisibleRows = 0;
63
- let nextMaxContentRowsHeight = 0;
64
- for (let i = 0; i < rows.length; i++) {
65
- const row = rows[i];
66
- const { top, height } = row.getBoundingClientRect();
67
- if (top - containerTop + height <= clientHeight) {
68
- nextVisibleRows += 1;
69
- nextMaxContentRowsHeight += height;
70
- }
71
- else {
72
- break;
73
- }
74
- }
75
- setVisibleRows(nextVisibleRows - 1);
76
- setMaxContentRowsHeight(nextMaxContentRowsHeight);
58
+ const { scrollHeight, clientHeight } = contentRowsRef.current;
59
+ if (scrollHeight <= clientHeight) {
60
+ return;
77
61
  }
78
- }, [hoveredValues, prevHoveredValues]);
62
+ const nextVisibleRows = Math.floor(hovered.length * (clientHeight / scrollHeight));
63
+ setVisibleRows(Math.max(nextVisibleRows - 1, 1));
64
+ setMaxContentRowsHeight((scrollHeight / hovered.length) * nextVisibleRows);
65
+ }, [hovered.length, hoveredValues, prevHoveredValues]);
79
66
  React.useEffect(() => {
80
67
  if (!contentRowsRef.current) {
81
68
  return;
@@ -91,7 +78,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
91
78
  return (React.createElement("div", { className: b('content'), "data-qa": qa },
92
79
  formattedHeadValue && (React.createElement("div", { className: b('series-name') },
93
80
  React.createElement("div", { className: b('series-name-text'), dangerouslySetInnerHTML: { __html: formattedHeadValue } }))),
94
- React.createElement("div", { className: b('content-rows', { pinned }), ref: contentRowsRef, style: { maxHeight: maxContentRowsHeight } },
81
+ React.createElement("div", { className: b('content-rows', { pinned }), ref: contentRowsRef, style: pinned ? { maxHeight: maxContentRowsHeight } : undefined },
95
82
  visibleHovered.map((seriesItem, i) => {
96
83
  var _a;
97
84
  const { data, series, closest } = seriesItem;
@@ -10,12 +10,12 @@ export function useAxis(props) {
10
10
  const prevAxesStateValue = React.useRef(axesState);
11
11
  const axesStateReady = React.useRef(false);
12
12
  React.useEffect(() => {
13
+ axesStateRunRef.current++;
14
+ axesStateReady.current = false;
13
15
  const shouldWaitForLegendReady = !preparedLegend || ((preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && !legendConfig);
14
16
  if (shouldWaitForLegendReady) {
15
17
  return;
16
18
  }
17
- axesStateRunRef.current++;
18
- axesStateReady.current = false;
19
19
  (async function () {
20
20
  var _a, _b;
21
21
  const currentRun = axesStateRunRef.current;
@@ -79,5 +79,10 @@ export function useAxis(props) {
79
79
  xAxis,
80
80
  yAxis,
81
81
  ]);
82
- return axesStateReady.current ? Object.assign(Object.assign({}, axesState), { setAxes }) : { xAxis: null, yAxis: [], setAxes };
82
+ const isAxesReady = axesStateReady.current;
83
+ const result = React.useMemo(() => {
84
+ return isAxesReady ? Object.assign(Object.assign({}, axesState), { setAxes }) : { xAxis: null, yAxis: [], setAxes };
85
+ }, [isAxesReady, axesState]);
86
+ prevAxesStateValue.current = result;
87
+ return result;
83
88
  }
@@ -49,6 +49,9 @@ const getLeftOffset = ({ preparedLegend, legendConfig, }) => {
49
49
  export const useChartDimensions = (args) => {
50
50
  const { height, margin, preparedLegend, preparedSeries, preparedXAxis, preparedYAxis, width, legendConfig, } = args;
51
51
  return React.useMemo(() => {
52
+ if (!preparedLegend || (!legendConfig && (preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled))) {
53
+ return { boundsWidth: 0, boundsHeight: 0 };
54
+ }
52
55
  const hasAxisRelatedSeries = preparedSeries.some(isAxisRelatedSeries);
53
56
  const boundsWidth = getBoundsWidth({ chartWidth: width, chartMargin: margin, preparedYAxis });
54
57
  const bottomOffset = getBottomOffset({
@@ -38,6 +38,9 @@ export const useShapes = (args) => {
38
38
  const countedRef = React.useRef(0);
39
39
  React.useEffect(() => {
40
40
  countedRef.current++;
41
+ if (!boundsHeight || !boundsWidth) {
42
+ return;
43
+ }
41
44
  (async () => {
42
45
  const currentRun = countedRef.current;
43
46
  const visibleSeries = getOnlyVisibleSeries(series);
@@ -32,7 +32,7 @@ export function useYAxisLabelWidth(props) {
32
32
  }
33
33
  if (runRef.current === currentRun && axisIndexesToRecalculateMap.size > 0) {
34
34
  setAxes((prevState) => {
35
- prevState.yAxis = prevState.yAxis.map((axis, i) => {
35
+ const newYAxis = prevState.yAxis.map((axis, i) => {
36
36
  const width = axisIndexesToRecalculateMap.get(i);
37
37
  if (width) {
38
38
  const axisWithRecalculatedLabels = Object.assign(Object.assign({}, axis), { labels: Object.assign(Object.assign({}, axis.labels), { width }) });
@@ -40,7 +40,7 @@ export function useYAxisLabelWidth(props) {
40
40
  }
41
41
  return axis;
42
42
  });
43
- return prevState;
43
+ return Object.assign(Object.assign({}, prevState), { yAxis: newYAxis });
44
44
  });
45
45
  }
46
46
  })();
@@ -11,4 +11,3 @@ export declare function isMacintosh(): boolean;
11
11
  export declare function measurePerformance(): {
12
12
  end(): number;
13
13
  };
14
- export declare function hasVerticalScrollbar(node: HTMLElement | null): boolean;
@@ -26,9 +26,3 @@ export function measurePerformance() {
26
26
  },
27
27
  };
28
28
  }
29
- export function hasVerticalScrollbar(node) {
30
- if (!node) {
31
- return false;
32
- }
33
- return node.scrollHeight > node.clientHeight;
34
- }
@@ -4,7 +4,7 @@ import get from 'lodash/get';
4
4
  import isEqual from 'lodash/isEqual';
5
5
  import { usePrevious } from '../../../hooks';
6
6
  import { i18n } from '../../../i18n';
7
- import { block, hasVerticalScrollbar } from '../../../utils';
7
+ import { block } from '../../../utils';
8
8
  import { getFormattedValue } from '../../../utils/chart/format';
9
9
  import { Row } from './Row';
10
10
  import { RowWithAggregation } from './RowWithAggregation';
@@ -52,30 +52,17 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
52
52
  if (!contentRowsRef.current) {
53
53
  return;
54
54
  }
55
- if (!hasVerticalScrollbar(contentRowsRef.current)) {
55
+ if (isEqual(hoveredValues, prevHoveredValues)) {
56
56
  return;
57
57
  }
58
- if (!isEqual(hoveredValues, prevHoveredValues)) {
59
- const { clientHeight } = contentRowsRef.current;
60
- const { top: containerTop } = contentRowsRef.current.getBoundingClientRect();
61
- const rows = contentRowsRef.current.querySelectorAll(`.${b('content-row')}`);
62
- let nextVisibleRows = 0;
63
- let nextMaxContentRowsHeight = 0;
64
- for (let i = 0; i < rows.length; i++) {
65
- const row = rows[i];
66
- const { top, height } = row.getBoundingClientRect();
67
- if (top - containerTop + height <= clientHeight) {
68
- nextVisibleRows += 1;
69
- nextMaxContentRowsHeight += height;
70
- }
71
- else {
72
- break;
73
- }
74
- }
75
- setVisibleRows(nextVisibleRows - 1);
76
- setMaxContentRowsHeight(nextMaxContentRowsHeight);
58
+ const { scrollHeight, clientHeight } = contentRowsRef.current;
59
+ if (scrollHeight <= clientHeight) {
60
+ return;
77
61
  }
78
- }, [hoveredValues, prevHoveredValues]);
62
+ const nextVisibleRows = Math.floor(hovered.length * (clientHeight / scrollHeight));
63
+ setVisibleRows(Math.max(nextVisibleRows - 1, 1));
64
+ setMaxContentRowsHeight((scrollHeight / hovered.length) * nextVisibleRows);
65
+ }, [hovered.length, hoveredValues, prevHoveredValues]);
79
66
  React.useEffect(() => {
80
67
  if (!contentRowsRef.current) {
81
68
  return;
@@ -91,7 +78,7 @@ export const DefaultTooltipContent = ({ hovered, pinned, rowRenderer, totals, va
91
78
  return (React.createElement("div", { className: b('content'), "data-qa": qa },
92
79
  formattedHeadValue && (React.createElement("div", { className: b('series-name') },
93
80
  React.createElement("div", { className: b('series-name-text'), dangerouslySetInnerHTML: { __html: formattedHeadValue } }))),
94
- React.createElement("div", { className: b('content-rows', { pinned }), ref: contentRowsRef, style: { maxHeight: maxContentRowsHeight } },
81
+ React.createElement("div", { className: b('content-rows', { pinned }), ref: contentRowsRef, style: pinned ? { maxHeight: maxContentRowsHeight } : undefined },
95
82
  visibleHovered.map((seriesItem, i) => {
96
83
  var _a;
97
84
  const { data, series, closest } = seriesItem;
@@ -10,12 +10,12 @@ export function useAxis(props) {
10
10
  const prevAxesStateValue = React.useRef(axesState);
11
11
  const axesStateReady = React.useRef(false);
12
12
  React.useEffect(() => {
13
+ axesStateRunRef.current++;
14
+ axesStateReady.current = false;
13
15
  const shouldWaitForLegendReady = !preparedLegend || ((preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && !legendConfig);
14
16
  if (shouldWaitForLegendReady) {
15
17
  return;
16
18
  }
17
- axesStateRunRef.current++;
18
- axesStateReady.current = false;
19
19
  (async function () {
20
20
  var _a, _b;
21
21
  const currentRun = axesStateRunRef.current;
@@ -79,5 +79,10 @@ export function useAxis(props) {
79
79
  xAxis,
80
80
  yAxis,
81
81
  ]);
82
- return axesStateReady.current ? Object.assign(Object.assign({}, axesState), { setAxes }) : { xAxis: null, yAxis: [], setAxes };
82
+ const isAxesReady = axesStateReady.current;
83
+ const result = React.useMemo(() => {
84
+ return isAxesReady ? Object.assign(Object.assign({}, axesState), { setAxes }) : { xAxis: null, yAxis: [], setAxes };
85
+ }, [isAxesReady, axesState]);
86
+ prevAxesStateValue.current = result;
87
+ return result;
83
88
  }
@@ -49,6 +49,9 @@ const getLeftOffset = ({ preparedLegend, legendConfig, }) => {
49
49
  export const useChartDimensions = (args) => {
50
50
  const { height, margin, preparedLegend, preparedSeries, preparedXAxis, preparedYAxis, width, legendConfig, } = args;
51
51
  return React.useMemo(() => {
52
+ if (!preparedLegend || (!legendConfig && (preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled))) {
53
+ return { boundsWidth: 0, boundsHeight: 0 };
54
+ }
52
55
  const hasAxisRelatedSeries = preparedSeries.some(isAxisRelatedSeries);
53
56
  const boundsWidth = getBoundsWidth({ chartWidth: width, chartMargin: margin, preparedYAxis });
54
57
  const bottomOffset = getBottomOffset({
@@ -38,6 +38,9 @@ export const useShapes = (args) => {
38
38
  const countedRef = React.useRef(0);
39
39
  React.useEffect(() => {
40
40
  countedRef.current++;
41
+ if (!boundsHeight || !boundsWidth) {
42
+ return;
43
+ }
41
44
  (async () => {
42
45
  const currentRun = countedRef.current;
43
46
  const visibleSeries = getOnlyVisibleSeries(series);
@@ -32,7 +32,7 @@ export function useYAxisLabelWidth(props) {
32
32
  }
33
33
  if (runRef.current === currentRun && axisIndexesToRecalculateMap.size > 0) {
34
34
  setAxes((prevState) => {
35
- prevState.yAxis = prevState.yAxis.map((axis, i) => {
35
+ const newYAxis = prevState.yAxis.map((axis, i) => {
36
36
  const width = axisIndexesToRecalculateMap.get(i);
37
37
  if (width) {
38
38
  const axisWithRecalculatedLabels = Object.assign(Object.assign({}, axis), { labels: Object.assign(Object.assign({}, axis.labels), { width }) });
@@ -40,7 +40,7 @@ export function useYAxisLabelWidth(props) {
40
40
  }
41
41
  return axis;
42
42
  });
43
- return prevState;
43
+ return Object.assign(Object.assign({}, prevState), { yAxis: newYAxis });
44
44
  });
45
45
  }
46
46
  })();
@@ -11,4 +11,3 @@ export declare function isMacintosh(): boolean;
11
11
  export declare function measurePerformance(): {
12
12
  end(): number;
13
13
  };
14
- export declare function hasVerticalScrollbar(node: HTMLElement | null): boolean;
@@ -26,9 +26,3 @@ export function measurePerformance() {
26
26
  },
27
27
  };
28
28
  }
29
- export function hasVerticalScrollbar(node) {
30
- if (!node) {
31
- return false;
32
- }
33
- return node.scrollHeight > node.clientHeight;
34
- }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/charts",
3
- "version": "1.38.2",
3
+ "version": "1.38.3",
4
4
  "description": "A flexible JavaScript library for data visualization and chart rendering using React",
5
5
  "license": "MIT",
6
6
  "main": "dist/cjs/index.js",