diff --git a/packages/charts/src/hooks/useObserveXAxisHeights.ts b/packages/charts/src/hooks/useObserveXAxisHeights.ts index 808949af12c..ba4cfe2979c 100644 --- a/packages/charts/src/hooks/useObserveXAxisHeights.ts +++ b/packages/charts/src/hooks/useObserveXAxisHeights.ts @@ -1,48 +1,65 @@ -import { debounce } from '@ui5/webcomponents-react-base/internal/utils'; -import type { RefObject } from 'react'; +import { useIsomorphicLayoutEffect } from '@ui5/webcomponents-react-base/internal/hooks'; +import type { MutableRefObject, RefObject } from 'react'; import { useEffect, useRef, useState } from 'react'; +// recharts default axis height -> is changed when labels are rotated const defaultAxisHeight = 30; +/** + * Measure x-axis height(s) - defaults to `defaultAxisHeight` + */ +function measure(container: Element | null, axisCount: number, prevHeightsRef: MutableRefObject) { + const heights = Array(axisCount).fill(defaultAxisHeight); + container?.querySelectorAll('.xAxis').forEach((xAxis, index) => { + const height = xAxis?.getBBox()?.height; + if (height > defaultAxisHeight) { + heights[index] = height; + } + }); + + const prevHeights = prevHeightsRef.current; + const same = prevHeights.length === heights.length && prevHeights.every((value, index) => value === heights[index]); + if (!same) { + prevHeightsRef.current = heights; + return heights; + } + // no change + return null; +} + export const useObserveXAxisHeights = (chartRef: RefObject, axisCount) => { const [xAxisHeights, setXAxisHeights] = useState(Array(axisCount).fill(defaultAxisHeight)); - const mostRecentXAxisHeights = useRef(xAxisHeights); + const prevHeightsRef = useRef(xAxisHeights); + + // check on every render if height changed + useIsomorphicLayoutEffect(() => { + const result = measure(chartRef.current, axisCount, prevHeightsRef); + if (result) { + setXAxisHeights(result); + } + }); + // check on every component DOM subtree change (catches internal rerender) useEffect(() => { - const debouncedObserverFn = debounce(() => { - const defaultHeights = Array(axisCount).fill(defaultAxisHeight); - chartRef.current?.querySelectorAll('.xAxis').forEach((xAxis, index) => { - const currentAxisHeight = xAxis?.getBBox()?.height; - if (currentAxisHeight > 30) { - defaultHeights[index] = currentAxisHeight; - } - }); - - const arraysHaveTheSameLength = mostRecentXAxisHeights.current.length === defaultHeights.length; - const arrayContentIsIdentical = mostRecentXAxisHeights.current.every( - (value, index) => defaultHeights[index] === value, - ); - if (!(arraysHaveTheSameLength && arrayContentIsIdentical)) { - mostRecentXAxisHeights.current = defaultHeights; - setXAxisHeights(defaultHeights); - } - }, 75); - const mutationObserver = new MutationObserver(debouncedObserverFn); - - if (chartRef.current) { - mutationObserver.observe(chartRef.current, { - characterData: false, - characterDataOldValue: false, - attributes: false, - childList: true, - subtree: true, - }); + const container = chartRef.current; + if (!container) { + return; } - return () => { - debouncedObserverFn.cancel(); - mutationObserver.disconnect(); - }; - }, [chartRef, setXAxisHeights, mostRecentXAxisHeights]); + + const observer = new MutationObserver(() => { + const result = measure(container, axisCount, prevHeightsRef); + if (result) { + setXAxisHeights(result); + } + }); + observer.observe(container, { + attributes: false, + childList: true, + subtree: true, + }); + + return () => observer.disconnect(); + }, [chartRef, axisCount]); return xAxisHeights; };