refactor(viewport): Remove resize detector and optimize viewport resizing logic (#5006)

This commit is contained in:
Alireza 2025-05-05 11:27:26 -04:00 committed by GitHub
parent 6337d2e9cb
commit 383f45823c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 38 additions and 46 deletions

View File

@ -1,5 +1,4 @@
import React, { useEffect, useRef, useCallback, useState } from 'react';
import { useResizeDetector } from 'react-resize-detector';
import * as cs3DTools from '@cornerstonejs/tools';
import { Enums, eventTarget, getEnabledElement } from '@cornerstonejs/core';
import { MeasurementService } from '@ohif/core';
@ -110,7 +109,23 @@ const OHIFCornerstoneViewport = React.memo(
cornerstoneViewportService.resize();
setImageScrollBarHeight();
}
}, [elementRef]);
}, [elementRef, cornerstoneViewportService, setImageScrollBarHeight]);
useEffect(() => {
const element = elementRef.current;
if (!element) {
return;
}
const resizeObserver = new ResizeObserver(onResize);
resizeObserver.observe(element);
// Cleanup function
return () => {
resizeObserver.unobserve(element);
resizeObserver.disconnect();
};
}, [onResize]);
const cleanUpServices = useCallback(
viewportInfo => {
@ -350,10 +365,6 @@ const OHIFCornerstoneViewport = React.memo(
}
}, [displaySets, viewportId, viewportActionCornersService, servicesManager, commandsManager]);
const { ref: resizeRef } = useResizeDetector({
onResize,
});
const Notification = customizationService.getCustomization('ui.notificationComponent');
return (
@ -364,10 +375,7 @@ const OHIFCornerstoneViewport = React.memo(
style={{ height: '100%', width: '100%' }}
onContextMenu={e => e.preventDefault()}
onMouseDown={e => e.preventDefault()}
ref={el => {
resizeRef.current = el;
elementRef.current = el;
}}
ref={elementRef}
></div>
<CornerstoneOverlays
viewportId={viewportId}

View File

@ -232,16 +232,6 @@ export default async function init({
}
);
// resize the cornerstone viewport service when the grid size changes
// IMPORTANT: this should happen outside of the OHIFCornerstoneViewport
// since it will trigger a rerender of each viewport and each resizing
// the offscreen canvas which would result in a performance hit, this should
// done only once per grid resize here. Doing it once here, allows us to reduce
// the refreshRage(in ms) to 10 from 50. I tried with even 1 or 5 ms it worked fine
viewportGridService.subscribe(viewportGridService.EVENTS.GRID_SIZE_CHANGED, () => {
cornerstoneViewportService.resize(true);
});
initContextMenu({
cornerstoneViewportService,
customizationService,

View File

@ -38,6 +38,9 @@ const EVENTS = {
VIEWPORT_VOLUMES_CHANGED: 'event::cornerstoneViewportService:viewportVolumesChanged',
};
const MIN_STACK_VIEWPORTS_TO_ENQUEUE_RESIZE = 12;
const MIN_VOLUME_VIEWPORTS_TO_ENQUEUE_RESIZE = 6;
export const WITH_NAVIGATION = { withNavigation: true, withOrientation: false };
/**
@ -62,9 +65,6 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
beforeResizePositionPresentations: Map<string, PositionPresentation> = new Map();
// Some configs
enableResizeDetector: true;
resizeRefreshRateMs: 200;
resizeRefreshMode: 'debounce';
servicesManager: AppTypes.ServicesManager = null;
resizeQueue = [];
@ -125,13 +125,8 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
/**
* It triggers the resize on the rendering engine, and renders the viewports
*
* @param isGridResize - if the resize is triggered by a grid resize
* this is used to avoid double resize of the viewports since if the
* grid is resized, all viewports will be resized so there is no need
* to resize them individually which will get triggered by their
* individual resize observers
*/
public resize(isGridResize = false) {
public resize() {
// https://stackoverflow.com/a/26279685
// This resize() call, among other things, rerenders the viewports. But when the entire viewer is
// display: none'd, it makes the size of all hidden elements 0, including the viewport canvas and its containers.
@ -147,12 +142,24 @@ class CornerstoneViewportService extends PubSubService implements IViewportServi
return;
}
const numStackViewportsInViewportGrid = Array.from(this.viewportsById.values()).filter(
viewportInfo => viewportInfo.getViewportType() === csEnums.ViewportType.STACK
).length;
const numVolumeViewportsInViewportGrid = Array.from(this.viewportsById.values()).filter(
viewportInfo => viewportInfo.getViewportType() === csEnums.ViewportType.ORTHOGRAPHIC
).length;
const isEasyResize =
numStackViewportsInViewportGrid <= MIN_STACK_VIEWPORTS_TO_ENQUEUE_RESIZE &&
numVolumeViewportsInViewportGrid <= MIN_VOLUME_VIEWPORTS_TO_ENQUEUE_RESIZE;
// if there is a grid resize happening, it means the viewport grid
// has been manipulated (e.g., panels closed, added, etc.) and we need
// to resize all viewports, so we will add a timeout here to make sure
// we don't double resize the viewports when viewports in the grid are
// resized individually
if (isGridResize) {
if (isEasyResize) {
this.performResize();
this.resetGridResizeTimeout();
this.resizeQueue = [];

View File

@ -35,9 +35,8 @@ export interface IViewportService {
/**
* It creates a resize observer for the viewport element, and observes
* the element for resizing events
* @param {*} elementRef
*/
resize(isGridResize: boolean): void;
resize(): void;
/**
* Removes the viewport from cornerstone, and destroys the rendering engine
*/

View File

@ -1,5 +1,4 @@
import React, { useEffect, useCallback, useRef, useMemo } from 'react';
import { useResizeDetector } from 'react-resize-detector';
import React, { useEffect, useCallback, useRef } from 'react';
import { Types, MeasurementService } from '@ohif/core';
import { ViewportGrid, ViewportPane } from '@ohif/ui-next';
import { useViewportGrid } from '@ohif/ui-next';
@ -13,14 +12,6 @@ function ViewerViewportGrid(props: withAppTypes) {
const { layout, activeViewportId, viewports, isHangingProtocolLayout } = viewportGrid;
const { numCols, numRows } = layout;
const { ref: resizeRef } = useResizeDetector({
refreshMode: 'debounce',
refreshRate: 7,
refreshOptions: { leading: true },
onResize: () => {
viewportGridService.setViewportGridSizeChanged();
},
});
const layoutHash = useRef(null);
const {
@ -444,10 +435,7 @@ function ViewerViewportGrid(props: withAppTypes) {
}
return (
<div
ref={resizeRef}
className="border-input h-[calc(100%-0.25rem)] w-full border"
>
<div className="border-input h-[calc(100%-0.25rem)] w-full border">
<ViewportGrid
numRows={numRows}
numCols={numCols}