fix(rerendering): reduce the re-rendering of the viewport grid (#3558)
This commit is contained in:
parent
cab8d322c2
commit
d8f628b125
@ -10,13 +10,7 @@ import {
|
|||||||
utilities as csUtils,
|
utilities as csUtils,
|
||||||
} from '@cornerstonejs/core';
|
} from '@cornerstonejs/core';
|
||||||
import { MeasurementService } from '@ohif/core';
|
import { MeasurementService } from '@ohif/core';
|
||||||
import {
|
import { Notification, useViewportDialog } from '@ohif/ui';
|
||||||
CinePlayer,
|
|
||||||
useCine,
|
|
||||||
useViewportGrid,
|
|
||||||
Notification,
|
|
||||||
useViewportDialog,
|
|
||||||
} from '@ohif/ui';
|
|
||||||
import {
|
import {
|
||||||
IStackViewport,
|
IStackViewport,
|
||||||
IVolumeViewport,
|
IVolumeViewport,
|
||||||
@ -28,6 +22,7 @@ import './OHIFCornerstoneViewport.css';
|
|||||||
import CornerstoneOverlays from './Overlays/CornerstoneOverlays';
|
import CornerstoneOverlays from './Overlays/CornerstoneOverlays';
|
||||||
import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/getSOPInstanceAttributes';
|
import getSOPInstanceAttributes from '../utils/measurementServiceMappings/utils/getSOPInstanceAttributes';
|
||||||
import CornerstoneServices from '../types/CornerstoneServices';
|
import CornerstoneServices from '../types/CornerstoneServices';
|
||||||
|
import CinePlayer from '../components/CinePlayer';
|
||||||
|
|
||||||
const STACK = 'stack';
|
const STACK = 'stack';
|
||||||
|
|
||||||
@ -127,8 +122,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
||||||
const [{ isCineEnabled, cines }, cineService] = useCine();
|
|
||||||
const [{ activeViewportIndex }] = useViewportGrid();
|
|
||||||
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
||||||
const elementRef = useRef();
|
const elementRef = useRef();
|
||||||
|
|
||||||
@ -145,74 +138,6 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
} = servicesManager.services as CornerstoneServices;
|
} = servicesManager.services as CornerstoneServices;
|
||||||
|
|
||||||
const [viewportDialogState] = useViewportDialog();
|
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
|
// useCallback for scroll bar height calculation
|
||||||
const setImageScrollBarHeight = useCallback(() => {
|
const setImageScrollBarHeight = useCallback(() => {
|
||||||
const scrollbarHeight = `${elementRef.current.clientHeight - 20}px`;
|
const scrollbarHeight = `${elementRef.current.clientHeight - 20}px`;
|
||||||
@ -482,6 +407,8 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
};
|
};
|
||||||
}, [displaySets, elementRef, viewportIndex]);
|
}, [displaySets, elementRef, viewportIndex]);
|
||||||
|
|
||||||
|
console.debug('OHIFCornerstoneViewport rendering');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="viewport-wrapper">
|
<div className="viewport-wrapper">
|
||||||
@ -505,25 +432,11 @@ const OHIFCornerstoneViewport = React.memo(props => {
|
|||||||
scrollbarHeight={scrollbarHeight}
|
scrollbarHeight={scrollbarHeight}
|
||||||
servicesManager={servicesManager}
|
servicesManager={servicesManager}
|
||||||
/>
|
/>
|
||||||
{isCineEnabled && (
|
<CinePlayer
|
||||||
<CinePlayer
|
enabledVPElement={enabledVPElement}
|
||||||
className="absolute left-1/2 -translate-x-1/2 bottom-3"
|
viewportIndex={viewportIndex}
|
||||||
isPlaying={isPlaying}
|
servicesManager={servicesManager}
|
||||||
onClose={handleCineClose}
|
/>
|
||||||
onPlayPauseChange={isPlaying =>
|
|
||||||
cineService.setCine({
|
|
||||||
id: activeViewportIndex,
|
|
||||||
isPlaying,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
onFrameRateChange={frameRate =>
|
|
||||||
cineService.setCine({
|
|
||||||
id: activeViewportIndex,
|
|
||||||
frameRate,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute w-full">
|
<div className="absolute w-full">
|
||||||
{viewportDialogState.viewportIndex === viewportIndex && (
|
{viewportDialogState.viewportIndex === viewportIndex && (
|
||||||
|
|||||||
107
extensions/cornerstone/src/components/CinePlayer/CinePlayer.tsx
Normal file
107
extensions/cornerstone/src/components/CinePlayer/CinePlayer.tsx
Normal file
@ -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;
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
import CinePlayer from './CinePlayer';
|
||||||
|
|
||||||
|
export default CinePlayer;
|
||||||
@ -36,7 +36,7 @@ ContextMenu.propTypes = {
|
|||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
action: PropTypes.func.isRequired,
|
action: PropTypes.func.isRequired,
|
||||||
})
|
})
|
||||||
).isRequired,
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ContextMenu;
|
export default ContextMenu;
|
||||||
|
|||||||
@ -184,7 +184,10 @@ const SplitButton = ({
|
|||||||
const listItemRenderer = renderer || DefaultListItemRenderer;
|
const listItemRenderer = renderer || DefaultListItemRenderer;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OutsideClickHandler onOutsideClick={outsideClickHandler}>
|
<OutsideClickHandler
|
||||||
|
onOutsideClick={outsideClickHandler}
|
||||||
|
disabled={!state.isExpanded}
|
||||||
|
>
|
||||||
<div name="SplitButton" className="relative">
|
<div name="SplitButton" className="relative">
|
||||||
<div
|
<div
|
||||||
className={classes.Button({
|
className={classes.Button({
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user