Skip to content

Commit

Permalink
fix(rerendering): reduce the re-rendering of the viewport grid (#3558)
Browse files Browse the repository at this point in the history
  • Loading branch information
sedghi authored Jul 26, 2023
1 parent cab8d32 commit d8f628b
Show file tree
Hide file tree
Showing 5 changed files with 124 additions and 98 deletions.
105 changes: 9 additions & 96 deletions extensions/cornerstone/src/Viewport/OHIFCornerstoneViewport.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,7 @@ import {
utilities as csUtils,
} from '@cornerstonejs/core';
import { MeasurementService } from '@ohif/core';
import {
CinePlayer,
useCine,
useViewportGrid,
Notification,
useViewportDialog,
} from '@ohif/ui';
import { Notification, useViewportDialog } from '@ohif/ui';
import {
IStackViewport,
IVolumeViewport,
Expand All @@ -28,6 +22,7 @@ import './OHIFCornerstoneViewport.css';
import CornerstoneOverlays from './Overlays/CornerstoneOverlays';
import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/getSOPInstanceAttributes';
import CornerstoneServices from '../types/CornerstoneServices';
import CinePlayer from '../components/CinePlayer';

const STACK = 'stack';

Expand Down Expand Up @@ -127,8 +122,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
} = props;

const [scrollbarHeight, setScrollbarHeight] = useState('100px');
const [{ isCineEnabled, cines }, cineService] = useCine();
const [{ activeViewportIndex }] = useViewportGrid();
const [enabledVPElement, setEnabledVPElement] = useState(null);
const elementRef = useRef();

Expand All @@ -145,74 +138,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
} = servicesManager.services as CornerstoneServices;

const [viewportDialogState] = useViewportDialog();

const cineHandler = () => {
if (!cines || !cines[viewportIndex] || !enabledVPElement) {
return;
}

const cine = cines[viewportIndex];
const isPlaying = cine.isPlaying || false;
const frameRate = cine.frameRate || 24;

const validFrameRate = Math.max(frameRate, 1);

if (isPlaying) {
cineService.playClip(enabledVPElement, {
framesPerSecond: validFrameRate,
});
} else {
cineService.stopClip(enabledVPElement);
}
};

useEffect(() => {
eventTarget.addEventListener(
Enums.Events.STACK_VIEWPORT_NEW_STACK,
cineHandler
);

return () => {
cineService.setCine({ id: viewportIndex, isPlaying: false });
eventTarget.removeEventListener(
Enums.Events.STACK_VIEWPORT_NEW_STACK,
cineHandler
);
};
}, [enabledVPElement]);

useEffect(() => {
if (!cines || !cines[viewportIndex] || !enabledVPElement) {
return;
}

cineHandler();

return () => {
if (enabledVPElement && cines?.[viewportIndex]?.isPlaying) {
cineService.stopClip(enabledVPElement);
}
};
}, [cines, viewportIndex, cineService, enabledVPElement, cineHandler]);

const cine = cines[viewportIndex];
const isPlaying = (cine && cine.isPlaying) || false;

const handleCineClose = () => {
toolbarService.recordInteraction({
groupId: 'MoreTools',
itemId: 'cine',
interactionType: 'toggle',
commands: [
{
commandName: 'toggleCine',
commandOptions: {},
context: 'CORNERSTONE',
},
],
});
};

// useCallback for scroll bar height calculation
const setImageScrollBarHeight = useCallback(() => {
const scrollbarHeight = `${elementRef.current.clientHeight - 20}px`;
Expand Down Expand Up @@ -482,6 +407,8 @@ const OHIFCornerstoneViewport = React.memo(props => {
};
}, [displaySets, elementRef, viewportIndex]);

console.debug('OHIFCornerstoneViewport rendering');

return (
<React.Fragment>
<div className="viewport-wrapper">
Expand All @@ -505,25 +432,11 @@ const OHIFCornerstoneViewport = React.memo(props => {
scrollbarHeight={scrollbarHeight}
servicesManager={servicesManager}
/>
{isCineEnabled && (
<CinePlayer
className="absolute left-1/2 -translate-x-1/2 bottom-3"
isPlaying={isPlaying}
onClose={handleCineClose}
onPlayPauseChange={isPlaying =>
cineService.setCine({
id: activeViewportIndex,
isPlaying,
})
}
onFrameRateChange={frameRate =>
cineService.setCine({
id: activeViewportIndex,
frameRate,
})
}
/>
)}
<CinePlayer
enabledVPElement={enabledVPElement}
viewportIndex={viewportIndex}
servicesManager={servicesManager}
/>
</div>
<div className="absolute w-full">
{viewportDialogState.viewportIndex === viewportIndex && (
Expand Down
107 changes: 107 additions & 0 deletions extensions/cornerstone/src/components/CinePlayer/CinePlayer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useEffect } from 'react';
import { CinePlayer, useCine, useViewportGrid } from '@ohif/ui';
import { Enums, eventTarget } from '@cornerstonejs/core';

function WrappedCinePlayer({
enabledVPElement,
viewportIndex,
servicesManager,
}) {
const { toolbarService, customizationService } = servicesManager.services;
const [{ isCineEnabled, cines }, cineService] = useCine();
const [{ activeViewportIndex }] = useViewportGrid();

const { component: CinePlayerComponent = CinePlayer } =
customizationService.get('cinePlayer') ?? {};

const handleCineClose = () => {
toolbarService.recordInteraction({
groupId: 'MoreTools',
itemId: 'cine',
interactionType: 'toggle',
commands: [
{
commandName: 'toggleCine',
commandOptions: {},
context: 'CORNERSTONE',
},
],
});
};

const cineHandler = () => {
if (!cines || !cines[viewportIndex] || !enabledVPElement) {
return;
}

const cine = cines[viewportIndex];
const isPlaying = cine.isPlaying || false;
const frameRate = cine.frameRate || 24;

const validFrameRate = Math.max(frameRate, 1);

if (isPlaying) {
cineService.playClip(enabledVPElement, {
framesPerSecond: validFrameRate,
});
} else {
cineService.stopClip(enabledVPElement);
}
};

useEffect(() => {
eventTarget.addEventListener(
Enums.Events.STACK_VIEWPORT_NEW_STACK,
cineHandler
);

return () => {
cineService.setCine({ id: viewportIndex, isPlaying: false });
eventTarget.removeEventListener(
Enums.Events.STACK_VIEWPORT_NEW_STACK,
cineHandler
);
};
}, [enabledVPElement]);

useEffect(() => {
if (!cines || !cines[viewportIndex] || !enabledVPElement) {
return;
}

cineHandler();

return () => {
if (enabledVPElement && cines?.[viewportIndex]?.isPlaying) {
cineService.stopClip(enabledVPElement);
}
};
}, [cines, viewportIndex, cineService, enabledVPElement, cineHandler]);

const cine = cines[viewportIndex];
const isPlaying = (cine && cine.isPlaying) || false;

return (
isCineEnabled && (
<CinePlayerComponent
className="absolute left-1/2 -translate-x-1/2 bottom-3"
isPlaying={isPlaying}
onClose={handleCineClose}
onPlayPauseChange={isPlaying =>
cineService.setCine({
id: activeViewportIndex,
isPlaying,
})
}
onFrameRateChange={frameRate =>
cineService.setCine({
id: activeViewportIndex,
frameRate,
})
}
/>
)
);
}

export default WrappedCinePlayer;
3 changes: 3 additions & 0 deletions extensions/cornerstone/src/components/CinePlayer/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import CinePlayer from './CinePlayer';

export default CinePlayer;
2 changes: 1 addition & 1 deletion platform/ui/src/components/ContextMenu/ContextMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ ContextMenu.propTypes = {
label: PropTypes.string.isRequired,
action: PropTypes.func.isRequired,
})
).isRequired,
),
};

export default ContextMenu;
5 changes: 4 additions & 1 deletion platform/ui/src/components/SplitButton/SplitButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,10 @@ const SplitButton = ({
const listItemRenderer = renderer || DefaultListItemRenderer;

return (
<OutsideClickHandler onOutsideClick={outsideClickHandler}>
<OutsideClickHandler
onOutsideClick={outsideClickHandler}
disabled={!state.isExpanded}
>
<div name="SplitButton" className="relative">
<div
className={classes.Button({
Expand Down

0 comments on commit d8f628b

Please sign in to comment.