From d778ebe9dfeea93d5de6afeef8c5ddadf871d42c Mon Sep 17 00:00:00 2001 From: Jerry Jones Date: Mon, 2 Dec 2024 15:10:48 -0600 Subject: [PATCH] useScaleCanvas performance improvements (#67496) * Rely on containerHeight resize listener instead of iframe.documentElement.clientHeight when setting the CSS variable * Only add CSS variables if we need them (scaleValue < 1) * Remove unmounting of CSS variables in useEffect return --------- Co-authored-by: Ella --- .../src/components/iframe/use-scale-canvas.js | 124 ++++++++---------- 1 file changed, 55 insertions(+), 69 deletions(-) diff --git a/packages/block-editor/src/components/iframe/use-scale-canvas.js b/packages/block-editor/src/components/iframe/use-scale-canvas.js index 732fe583d46ac8..0b2b8d3c137ffa 100644 --- a/packages/block-editor/src/components/iframe/use-scale-canvas.js +++ b/packages/block-editor/src/components/iframe/use-scale-canvas.js @@ -6,11 +6,11 @@ import { useReducedMotion, useResizeObserver } from '@wordpress/compose'; /** * @typedef {Object} TransitionState - * @property {number} scaleValue Scale of the canvas. - * @property {number} frameSize Size of the frame/offset around the canvas. - * @property {number} clientHeight ClientHeight of the iframe. - * @property {number} scrollTop ScrollTop of the iframe. - * @property {number} scrollHeight ScrollHeight of the iframe. + * @property {number} scaleValue Scale of the canvas. + * @property {number} frameSize Size of the frame/offset around the canvas. + * @property {number} containerHeight containerHeight of the iframe. + * @property {number} scrollTop ScrollTop of the iframe. + * @property {number} scrollHeight ScrollHeight of the iframe. */ /** @@ -44,27 +44,28 @@ function calculateScale( { */ function computeScrollTopNext( transitionFrom, transitionTo ) { const { - clientHeight: prevClientHeight, + containerHeight: prevContainerHeight, frameSize: prevFrameSize, scaleValue: prevScale, scrollTop, scrollHeight, } = transitionFrom; - const { clientHeight, frameSize, scaleValue } = transitionTo; + const { containerHeight, frameSize, scaleValue } = transitionTo; // Step 0: Start with the current scrollTop. let scrollTopNext = scrollTop; // Step 1: Undo the effects of the previous scale and frame around the // midpoint of the visible area. scrollTopNext = - ( scrollTopNext + prevClientHeight / 2 - prevFrameSize ) / prevScale - - prevClientHeight / 2; + ( scrollTopNext + prevContainerHeight / 2 - prevFrameSize ) / + prevScale - + prevContainerHeight / 2; // Step 2: Apply the new scale and frame around the midpoint of the // visible area. scrollTopNext = - ( scrollTopNext + clientHeight / 2 ) * scaleValue + + ( scrollTopNext + containerHeight / 2 ) * scaleValue + frameSize - - clientHeight / 2; + containerHeight / 2; // Step 3: Handle an edge case so that you scroll to the top of the // iframe if the top of the iframe content is visible in the container. @@ -78,7 +79,7 @@ function computeScrollTopNext( transitionFrom, transitionTo ) { const maxScrollTop = scrollHeight * ( scaleValue / prevScale ) + frameSize * 2 - - clientHeight; + containerHeight; // Step 4: Clamp the scrollTopNext between the minimum and maximum // possible scrollTop positions. Round the value to avoid subpixel @@ -146,8 +147,10 @@ export function useScaleCanvas( { } ) { const [ contentResizeListener, { height: contentHeight } ] = useResizeObserver(); - const [ containerResizeListener, { width: containerWidth } ] = - useResizeObserver(); + const [ + containerResizeListener, + { width: containerWidth, height: containerHeight }, + ] = useResizeObserver(); const initialContainerWidthRef = useRef( 0 ); const isZoomedOut = scale !== 1; @@ -186,7 +189,7 @@ export function useScaleCanvas( { const transitionFromRef = useRef( { scaleValue, frameSize, - clientHeight: 0, + containerHeight: 0, scrollTop: 0, scrollHeight: 0, } ); @@ -198,7 +201,7 @@ export function useScaleCanvas( { const transitionToRef = useRef( { scaleValue, frameSize, - clientHeight: 0, + containerHeight: 0, scrollTop: 0, scrollHeight: 0, } ); @@ -333,40 +336,41 @@ export function useScaleCanvas( { } ); } - // If we are not going to animate the transition, set the scale and frame size directly. - // If we are animating, these values will be set when the animation is finished. - // Example: Opening sidebars that reduce the scale of the canvas, but we don't want to - // animate the transition. - if ( ! startAnimationRef.current ) { + if ( scaleValue < 1 ) { + // If we are not going to animate the transition, set the scale and frame size directly. + // If we are animating, these values will be set when the animation is finished. + // Example: Opening sidebars that reduce the scale of the canvas, but we don't want to + // animate the transition. + if ( ! startAnimationRef.current ) { + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-scale', + scaleValue + ); + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-frame-size', + `${ frameSize }px` + ); + } + iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-scale', - scaleValue + '--wp-block-editor-iframe-zoom-out-content-height', + `${ contentHeight }px` ); + iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-frame-size', - `${ frameSize }px` + '--wp-block-editor-iframe-zoom-out-inner-height', + `${ containerHeight }px` ); - } - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-content-height', - `${ contentHeight }px` - ); - - const clientHeight = iframeDocument.documentElement.clientHeight; - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-inner-height', - `${ clientHeight }px` - ); - - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-container-width', - `${ containerWidth }px` - ); - iframeDocument.documentElement.style.setProperty( - '--wp-block-editor-iframe-zoom-out-scale-container-width', - `${ scaleContainerWidth }px` - ); + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-container-width', + `${ containerWidth }px` + ); + iframeDocument.documentElement.style.setProperty( + '--wp-block-editor-iframe-zoom-out-scale-container-width', + `${ scaleContainerWidth }px` + ); + } /** * Handle the zoom out animation: @@ -405,8 +409,9 @@ export function useScaleCanvas( { // the iframe at this point when we're about to animate the zoom out. // The iframe scrollTop, scrollHeight, and clientHeight will all be // the most accurate. - transitionFromRef.current.clientHeight = - transitionFromRef.current.clientHeight ?? clientHeight; + transitionFromRef.current.containerHeight = + transitionFromRef.current.containerHeight ?? + containerHeight; // Use containerHeight, as it's the previous container height value if none was set. transitionFromRef.current.scrollTop = iframeDocument.documentElement.scrollTop; transitionFromRef.current.scrollHeight = @@ -415,7 +420,8 @@ export function useScaleCanvas( { transitionToRef.current = { scaleValue, frameSize, - clientHeight, + containerHeight: + iframeDocument.documentElement.clientHeight, // use clientHeight to get the actual height of the new container, as it will be the most up-to-date. }; transitionToRef.current.scrollTop = computeScrollTopNext( transitionFromRef.current, @@ -432,27 +438,6 @@ export function useScaleCanvas( { } } } - - return () => { - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-scale' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-frame-size' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-content-height' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-inner-height' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-container-width' - ); - iframeDocument.documentElement.style.removeProperty( - '--wp-block-editor-iframe-zoom-out-scale-container-width' - ); - }; }, [ startZoomOutAnimation, finishZoomOutAnimation, @@ -463,6 +448,7 @@ export function useScaleCanvas( { iframeDocument, contentHeight, containerWidth, + containerHeight, maxContainerWidth, scaleContainerWidth, ] );