[OHIF-251] - Double click to maximise viewport/ revert to previous layout. (#1860)
* WIP * double click to maximise implemented at the viewport grid layer. * Remove memory of cached layout when the layout is changed, or a different displaySet is set. * WIP fix double click for cornerstone. * Update CST * Prevent maximising when double clicking the action bar * Update extensions/dicom-sr/src/OHIFCornerstoneSRViewport.js * Apply suggestions from code review * Fix conflicts. Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
This commit is contained in:
parent
5ee4598bbe
commit
4dfe144bf8
@ -33,7 +33,7 @@
|
||||
"@ohif/ui": "^0.50.0",
|
||||
"cornerstone-core": "^2.3.0",
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.14.2",
|
||||
"dicom-parser": "^1.8.3",
|
||||
|
||||
@ -38,12 +38,13 @@ export default function init({ servicesManager, configuration }) {
|
||||
],
|
||||
onSubmit: ({ action, value }) => {
|
||||
switch (action.id) {
|
||||
case 'save': callback(value.label);
|
||||
case 'save':
|
||||
callback(value.label);
|
||||
}
|
||||
UIDialogService.dismiss({ id: dialogId });
|
||||
},
|
||||
body: ({ value, setValue }) => {
|
||||
const onChangeHandler = (event) => {
|
||||
const onChangeHandler = event => {
|
||||
event.persist();
|
||||
setValue(value => ({ ...value, label: event.target.value }));
|
||||
};
|
||||
@ -93,7 +94,7 @@ export default function init({ servicesManager, configuration }) {
|
||||
// THIS
|
||||
// is a way for extensions that "depend" on this extension to notify it of
|
||||
// new cornerstone enabled elements so it's commands continue to work.
|
||||
const handleOhifCornerstoneEnabledElementEvent = function (evt) {
|
||||
const handleOhifCornerstoneEnabledElementEvent = function(evt) {
|
||||
const { viewportIndex, enabledElement } = evt.detail;
|
||||
|
||||
setEnabledElement(viewportIndex, enabledElement);
|
||||
@ -271,7 +272,10 @@ const _connectToolsToMeasurementService = measurementService => {
|
||||
const csToolsVer4MeasurementSource = _initMeasurementService(
|
||||
measurementService
|
||||
);
|
||||
_connectMeasurementServiceToTools(measurementService, csToolsVer4MeasurementSource);
|
||||
_connectMeasurementServiceToTools(
|
||||
measurementService,
|
||||
csToolsVer4MeasurementSource
|
||||
);
|
||||
const { addOrUpdate, remove } = csToolsVer4MeasurementSource;
|
||||
const elementEnabledEvt = cornerstone.EVENTS.ELEMENT_ENABLED;
|
||||
|
||||
@ -336,14 +340,18 @@ const _connectToolsToMeasurementService = measurementService => {
|
||||
});
|
||||
};
|
||||
|
||||
const _connectMeasurementServiceToTools = (measurementService, measurementSource) => {
|
||||
const { MEASUREMENTS_CLEARED, MEASUREMENT_REMOVED } = measurementService.EVENTS;
|
||||
const _connectMeasurementServiceToTools = (
|
||||
measurementService,
|
||||
measurementSource
|
||||
) => {
|
||||
const {
|
||||
MEASUREMENTS_CLEARED,
|
||||
MEASUREMENT_REMOVED,
|
||||
} = measurementService.EVENTS;
|
||||
const sourceId = measurementSource.id;
|
||||
|
||||
measurementService.subscribe(MEASUREMENTS_CLEARED, () => {
|
||||
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState(
|
||||
{}
|
||||
);
|
||||
cornerstoneTools.globalImageIdSpecificToolStateManager.restoreToolState({});
|
||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||
cornerstone.updateImage(enabledElement.element);
|
||||
});
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"dcmjs": "0.14.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.8.6",
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"dcmjs": "0.14.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.8.6",
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
"@ohif/ui": "^0.50.0",
|
||||
"cornerstone-core": "^2.3.0",
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.14.2",
|
||||
"dicom-parser": "^1.8.3",
|
||||
|
||||
@ -399,14 +399,23 @@ function OHIFCornerstoneSRViewport({
|
||||
});
|
||||
}
|
||||
|
||||
const label =
|
||||
viewports.length > 1
|
||||
? _viewportLabels[firstViewportIndexWithMatchingDisplaySetUid]
|
||||
: '';
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewportActionBar
|
||||
onDoubleClick={evt => {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}}
|
||||
onSeriesChange={onMeasurementChange}
|
||||
onHydrationClick={hydrateMeasurementService}
|
||||
showNavArrows={viewportIndex === activeViewportIndex}
|
||||
studyData={{
|
||||
label: _viewportLabels[firstViewportIndexWithMatchingDisplaySetUid],
|
||||
label,
|
||||
isTracked: false,
|
||||
isLocked: displaySet.isLocked,
|
||||
isHydrated,
|
||||
@ -432,18 +441,23 @@ function OHIFCornerstoneSRViewport({
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<CornerstoneViewport
|
||||
onElementEnabled={onElementEnabled}
|
||||
viewportIndex={viewportIndex}
|
||||
imageIds={imageIds}
|
||||
imageIdIndex={currentImageIdIndex}
|
||||
// TODO: ViewportGrid Context?
|
||||
isActive={true} // todo
|
||||
isStackPrefetchEnabled={true} // todo
|
||||
isPlaying={false}
|
||||
frameRate={24}
|
||||
isOverlayVisible={false}
|
||||
/>
|
||||
<div
|
||||
className="relative flex flex-row w-full h-full"
|
||||
onDoubleClick={_onDoubleClick}
|
||||
>
|
||||
<CornerstoneViewport
|
||||
onElementEnabled={onElementEnabled}
|
||||
viewportIndex={viewportIndex}
|
||||
imageIds={imageIds}
|
||||
imageIdIndex={currentImageIdIndex}
|
||||
// TODO: ViewportGrid Context?
|
||||
isActive={true} // todo
|
||||
isStackPrefetchEnabled={true} // todo
|
||||
isPlaying={false}
|
||||
frameRate={24}
|
||||
isOverlayVisible={false}
|
||||
/>
|
||||
</div>
|
||||
{childrenWithProps}
|
||||
</>
|
||||
);
|
||||
@ -573,4 +587,14 @@ function _addToolDataToCornerstoneTools(data, toolType, imageId) {
|
||||
toolData.data.push(data);
|
||||
}
|
||||
|
||||
function _onDoubleClick() {
|
||||
const cancelActiveManipulatorsForElement = cornerstoneTools.getModule(
|
||||
'manipulatorState'
|
||||
).setters.cancelActiveManipulatorsForElement;
|
||||
const enabledElements = cornerstoneTools.store.state.enabledElements;
|
||||
enabledElements.forEach(element => {
|
||||
cancelActiveManipulatorsForElement(element);
|
||||
});
|
||||
}
|
||||
|
||||
export default OHIFCornerstoneSRViewport;
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"dcmjs": "0.14.2",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.13.1",
|
||||
|
||||
@ -295,6 +295,10 @@ function TrackedCornerstoneViewport({
|
||||
return (
|
||||
<>
|
||||
<ViewportActionBar
|
||||
onDoubleClick={evt => {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
}}
|
||||
onSeriesChange={direction => switchMeasurement(direction)}
|
||||
showNavArrows={showNavArrows}
|
||||
studyData={{
|
||||
@ -324,7 +328,10 @@ function TrackedCornerstoneViewport({
|
||||
}}
|
||||
/>
|
||||
{/* TODO: Viewport interface to accept stack or layers of content like this? */}
|
||||
<div className="relative flex flex-row w-full h-full">
|
||||
<div
|
||||
className="relative flex flex-row w-full h-full"
|
||||
onDoubleClick={_onDoubleClick}
|
||||
>
|
||||
<CornerstoneViewport
|
||||
onElementEnabled={onElementEnabled}
|
||||
viewportIndex={viewportIndex}
|
||||
@ -406,6 +413,18 @@ function _getCornerstoneStack(displaySet, dataSource) {
|
||||
return stack;
|
||||
}
|
||||
|
||||
|
||||
function _onDoubleClick() {
|
||||
const cancelActiveManipulatorsForElement = cornerstoneTools.getModule(
|
||||
'manipulatorState'
|
||||
).setters.cancelActiveManipulatorsForElement;
|
||||
const enabledElements = cornerstoneTools.store.state.enabledElements;
|
||||
enabledElements.forEach(element => {
|
||||
cancelActiveManipulatorsForElement(element);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Builds the viewport data from a datasource and a displayset.
|
||||
*
|
||||
@ -413,6 +432,7 @@ function _getCornerstoneStack(displaySet, dataSource) {
|
||||
* @param {Object} displaySet
|
||||
* @return {Object} viewport data
|
||||
*/
|
||||
|
||||
async function _getViewportData(dataSource, displaySet) {
|
||||
const stack = _getCornerstoneStack(displaySet, dataSource);
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
"@ohif/core": "^2.9.6",
|
||||
"@ohif/ui": "^2.0.0",
|
||||
"cornerstone-core": "^2.3.0",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"gh-pages": "^2.0.1",
|
||||
|
||||
12
lerna-debug.log
Normal file
12
lerna-debug.log
Normal file
@ -0,0 +1,12 @@
|
||||
0 silly argv { _: [ 'run' ],
|
||||
0 silly argv stream: true,
|
||||
0 silly argv lernaVersion: '3.22.0',
|
||||
0 silly argv '$0':
|
||||
0 silly argv '/Users/jamesapetts/cornerstonejs/Viewers/node_modules/.bin/lerna',
|
||||
0 silly argv script: 'dev:viewer' }
|
||||
1 notice cli v3.22.0
|
||||
2 verbose rootPath /Users/jamesapetts/cornerstonejs/Viewers
|
||||
3 info versioning independent
|
||||
4 error JSONError: Unexpected token < in JSON at position 871 while parsing near '...ne-core": "^2.3.0",<<<<<<< HEAD "co...' in platform/core/package.json
|
||||
4 error at module.exports (/Users/jamesapetts/cornerstonejs/Viewers/node_modules/parse-json/index.js:26:19)
|
||||
4 error at parse (/Users/jamesapetts/cornerstonejs/Viewers/node_modules/load-json-file/index.js:15:9)
|
||||
@ -31,7 +31,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"cornerstone-core": "^2.3.0",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dicom-parser": "^1.8.3"
|
||||
},
|
||||
|
||||
@ -6,14 +6,18 @@ const publicAPI = {
|
||||
setActiveViewportIndex: _setActiveViewportIndex,
|
||||
setDisplaysetForViewport: _setDisplaysetForViewport,
|
||||
setLayout: _setLayout,
|
||||
setCachedLayout: _setCachedLayout,
|
||||
setServiceImplementation,
|
||||
};
|
||||
|
||||
const serviceImplementation = {
|
||||
_getState: () => console.warn('getState() NOT IMPLEMENTED'),
|
||||
_setActiveViewportIndex: () => console.warn('setActiveViewportIndex() NOT IMPLEMENTED'),
|
||||
_setDisplaysetForViewport: () => console.warn('setDisplaysetForViewport() NOT IMPLEMENTED'),
|
||||
_setActiveViewportIndex: () =>
|
||||
console.warn('setActiveViewportIndex() NOT IMPLEMENTED'),
|
||||
_setDisplaysetForViewport: () =>
|
||||
console.warn('setDisplaysetForViewport() NOT IMPLEMENTED'),
|
||||
_setLayout: () => console.warn('setLayout() NOT IMPLEMENTED'),
|
||||
_setCachedLayout: () => console.warn('setCachedLayout() NOT IMPLEMENTED'),
|
||||
};
|
||||
|
||||
function _getState() {
|
||||
@ -35,10 +39,15 @@ function _setLayout({ numCols, numRows }) {
|
||||
return serviceImplementation._setLayout({ numCols, numRows });
|
||||
}
|
||||
|
||||
function _setCachedLayout({ numCols, numRows, viewports }) {
|
||||
return serviceImplementation._setLayout({ numCols, numRows, viewports });
|
||||
}
|
||||
|
||||
function setServiceImplementation({
|
||||
getState: getStateImplementation,
|
||||
setActiveViewportIndex: setActiveViewportIndexImplementation,
|
||||
setDisplaysetForViewport: setDisplaysetForViewportImplementation,
|
||||
setCachedLayout: setCachedLayoutImplementation,
|
||||
setLayout: setLayoutImplementation,
|
||||
}) {
|
||||
if (getStateImplementation) {
|
||||
@ -53,6 +62,9 @@ function setServiceImplementation({
|
||||
if (setLayoutImplementation) {
|
||||
serviceImplementation._setLayout = setLayoutImplementation;
|
||||
}
|
||||
if (setCachedLayoutImplementation) {
|
||||
serviceImplementation._setCachedLayout = setCachedLayoutImplementation;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
|
||||
@ -16,6 +16,7 @@ const ViewportActionBar = ({
|
||||
showPatientInfo: patientInfoVisibility,
|
||||
onSeriesChange,
|
||||
onHydrationClick,
|
||||
onDoubleClick,
|
||||
}) => {
|
||||
const [showPatientInfo, setShowPatientInfo] = useState(patientInfoVisibility);
|
||||
|
||||
@ -135,7 +136,10 @@ const ViewportActionBar = ({
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center p-2 border-b select-none border-primary-light min-h-12">
|
||||
<div
|
||||
className="flex items-center p-2 border-b select-none border-primary-light min-h-12"
|
||||
onDoubleClick={onDoubleClick}
|
||||
>
|
||||
<div className="flex flex-grow">
|
||||
<div className="flex items-center">
|
||||
{renderIconStatus()}
|
||||
|
||||
@ -11,6 +11,7 @@ function ViewportPane({
|
||||
className,
|
||||
isActive,
|
||||
onDrop,
|
||||
onDoubleClick,
|
||||
onInteraction,
|
||||
acceptDropsFor,
|
||||
}) {
|
||||
@ -57,6 +58,7 @@ function ViewportPane({
|
||||
// https://reactjs.org/docs/events.html#mouse-events
|
||||
// https://stackoverflow.com/questions/8378243/catch-scrolling-event-on-overflowhidden-element
|
||||
onMouseDown={onInteractionHandler}
|
||||
onDoubleClick={onDoubleClick}
|
||||
onClick={onInteractionHandler}
|
||||
onScroll={onInteractionHandler}
|
||||
onWheel={onInteractionHandler}
|
||||
@ -95,6 +97,8 @@ ViewportPane.propTypes = {
|
||||
onDrop: PropTypes.func.isRequired,
|
||||
/** Called when the viewportPane is interacted with by the user */
|
||||
onInteraction: PropTypes.func.isRequired,
|
||||
/** Executed when the pane is double clicked */
|
||||
onDoubleClick: PropTypes.func,
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
@ -32,7 +32,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
|
||||
viewports[viewportIndex] = { displaySetInstanceUID, imageIndex };
|
||||
|
||||
return { ...state, ...{ viewports } };
|
||||
return { ...state, ...{ viewports }, cachedLayout: undefined };
|
||||
}
|
||||
case 'SET_LAYOUT': {
|
||||
const { numCols, numRows } = action.payload;
|
||||
@ -51,8 +51,12 @@ export function ViewportGridProvider({ children, service }) {
|
||||
return {
|
||||
...state,
|
||||
...{ activeViewportIndex, numCols, numRows, viewports },
|
||||
cachedLayout: undefined,
|
||||
};
|
||||
}
|
||||
case 'SET_CACHED_LAYOUT': {
|
||||
return { ...state, cachedLayout: action.payload };
|
||||
}
|
||||
default:
|
||||
return action.payload;
|
||||
}
|
||||
@ -93,6 +97,15 @@ export function ViewportGridProvider({ children, service }) {
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const setCachedLayout = useCallback(
|
||||
payload =>
|
||||
dispatch({
|
||||
type: 'SET_CACHED_LAYOUT',
|
||||
payload,
|
||||
}),
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets the implementation of a modal service that can be used by extensions.
|
||||
*
|
||||
@ -105,6 +118,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
setActiveViewportIndex,
|
||||
setDisplaysetForViewport,
|
||||
setLayout,
|
||||
setCachedLayout,
|
||||
});
|
||||
}
|
||||
}, [
|
||||
@ -113,6 +127,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
setActiveViewportIndex,
|
||||
setDisplaysetForViewport,
|
||||
setLayout,
|
||||
setCachedLayout,
|
||||
]);
|
||||
|
||||
const api = {
|
||||
@ -120,6 +135,7 @@ export function ViewportGridProvider({ children, service }) {
|
||||
setActiveViewportIndex,
|
||||
setDisplaysetForViewport,
|
||||
setLayout,
|
||||
setCachedLayout,
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -67,7 +67,7 @@
|
||||
"classnames": "^2.2.6",
|
||||
"core-js": "^3.2.1",
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.17.0",
|
||||
"cornerstone-tools": "4.18.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.14.2",
|
||||
"dicom-parser": "^1.8.3",
|
||||
|
||||
@ -11,7 +11,7 @@ const { ImageSet } = classes;
|
||||
function ViewerViewportGrid(props) {
|
||||
const { servicesManager, viewportComponents, dataSource } = props;
|
||||
const [
|
||||
{ numCols, numRows, activeViewportIndex, viewports },
|
||||
{ numCols, numRows, activeViewportIndex, viewports, cachedLayout },
|
||||
viewportGridService,
|
||||
] = useViewportGrid();
|
||||
|
||||
@ -67,6 +67,43 @@ function ViewerViewportGrid(props) {
|
||||
};
|
||||
};
|
||||
|
||||
const onDoubleClick = viewportIndex => {
|
||||
if (cachedLayout) {
|
||||
viewportGridService.setLayout({
|
||||
numCols: cachedLayout.numCols,
|
||||
numRows: cachedLayout.numRows,
|
||||
});
|
||||
|
||||
cachedLayout.viewports.forEach((viewport, viewportIndex) => {
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex,
|
||||
displaySetInstanceUID: viewport.displaySetInstanceUID,
|
||||
});
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedViewports = viewports.map(viewport => {
|
||||
return {
|
||||
displaySetInstanceUID: viewport.displaySetInstanceUID,
|
||||
};
|
||||
});
|
||||
|
||||
viewportGridService.setDisplaysetForViewport({
|
||||
viewportIndex: 0,
|
||||
displaySetInstanceUID: viewports[viewportIndex].displaySetInstanceUID,
|
||||
});
|
||||
|
||||
viewportGridService.setLayout({ numCols: 1, numRows: 1 });
|
||||
|
||||
viewportGridService.setCachedLayout({
|
||||
numCols,
|
||||
numRows,
|
||||
viewports: cachedViewports,
|
||||
});
|
||||
};
|
||||
|
||||
// TODO:
|
||||
// Hmm... Should a "displaySet" being added update the viewport based on HP?
|
||||
// I guess it might.
|
||||
@ -127,6 +164,7 @@ function ViewerViewportGrid(props) {
|
||||
acceptDropsFor="displayset"
|
||||
onDrop={onDropHandler.bind(null, viewportIndex)}
|
||||
onInteraction={onInterationHandler}
|
||||
onDoubleClick={() => onDoubleClick(viewportIndex)}
|
||||
isActive={activeViewportIndex === viewportIndex}
|
||||
>
|
||||
<ViewportComponent
|
||||
|
||||
@ -6766,10 +6766,10 @@ cornerstone-math@^0.1.8:
|
||||
resolved "https://registry.yarnpkg.com/cornerstone-math/-/cornerstone-math-0.1.8.tgz#68ab1f9e4fdcd7c5cb23a0d2eb4263f9f894f1c5"
|
||||
integrity sha512-x7NEQHBtVG7j1yeyj/aRoKTpXv1Vh2/H9zNLMyqYJDtJkNng8C4Q8M3CgZ1qer0Yr7eVq2x+Ynmj6kfOm5jXKw==
|
||||
|
||||
cornerstone-tools@4.17.0:
|
||||
version "4.17.0"
|
||||
resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-4.17.0.tgz#a97d6ebeb9745e9f226946e05329e856ebcaee1e"
|
||||
integrity sha512-UPXWPzrb+2XwAXfQLc+ifSb0qp0SBZ3ojlGqt1iq9j85oQuy93avuEN6k2R8BV4NgQFz4okIEJdyKMoBwmrZ8g==
|
||||
cornerstone-tools@4.18.0:
|
||||
version "4.18.0"
|
||||
resolved "https://registry.yarnpkg.com/cornerstone-tools/-/cornerstone-tools-4.18.0.tgz#3b9497390fe7a7479db6f480d3219cc20c97e128"
|
||||
integrity sha512-r1IslS/SaybyZq95jhaHltuYuA/c8h6C6iUMYGsuMh1laENYV9Nm0XsI0Ud+w1v5ZgvbHu52bw0rUQmWkOHszA==
|
||||
dependencies:
|
||||
"@babel/runtime" "7.1.2"
|
||||
cornerstone-math "0.1.7"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user