Files
ohif-viewer/extensions/cornerstone/src/init.js
T
Igor OctavianoandDanny Brown 63594d36b0 feat: 🎸 Configuration so viewer tools can nix handles (#1304)
* feat: 🎸 Configuration so viewer tools can nix handles

Adds a key to cornerstone configuration that allows to toggle on/off
handle rendering

Closes: #1223

* Update extension docs

* Update doc

* docs: include hideHandles configuration in our configuration docs

* chore: default to hiding handles for annotations

* chore: switch to drawHandlesOnHover to mimic legacy viewer functionality

* Flip logic for drawHandlesOnHover; reverse of hideHandles

* Don't hide the handles of ellipse or rectangle roi

* invert check

Co-authored-by: Danny Brown <danny.ri.brown@gmail.com>
2019-12-20 12:15:40 -05:00

183 lines
5.9 KiB
JavaScript

import OHIF from '@ohif/core';
import { SimpleDialog } from '@ohif/ui';
import cornerstone from 'cornerstone-core';
import csTools from 'cornerstone-tools';
import merge from 'lodash.merge';
import queryString from 'query-string';
import initCornerstoneTools from './initCornerstoneTools.js';
function fallbackMetaDataProvider(type, imageId) {
if (!imageId.includes('wado?requestType=WADO')) {
return;
}
// If you call for an WADO-URI imageId and get no
// metadata, try reformatting to WADO-RS imageId
const qs = queryString.parse(imageId);
const wadoRoot = window.store.getState().servers.servers[0].wadoRoot;
const wadoRsImageId = `wadors:${wadoRoot}/studies/${qs.studyUID}/series/${
qs.seriesUID
}/instances/${qs.objectUID}/frames/${qs.frame || 1}`;
return cornerstone.metaData.get(type, wadoRsImageId);
}
// Add this fallback provider with a low priority so it is handled last
cornerstone.metaData.addProvider(fallbackMetaDataProvider, -1);
/**
*
* @param {Object} servicesManager
* @param {Object} configuration
* @param {Object|Array} configuration.csToolsConfig
*/
export default function init({ servicesManager, configuration }) {
const callInputDialog = (data, event, callback) => {
const { UIDialogService } = servicesManager.services;
if (UIDialogService) {
let dialogId = UIDialogService.create({
centralize: true,
isDraggable: false,
content: SimpleDialog.InputDialog,
useLastPosition: false,
showOverlay: true,
contentProps: {
title: 'Enter your annotation',
label: 'New label',
measurementData: data ? { description: data.text } : {},
onClose: () => UIDialogService.dismiss({ id: dialogId }),
onSubmit: value => {
callback(value);
UIDialogService.dismiss({ id: dialogId });
},
},
});
}
};
const { csToolsConfig } = configuration;
const { StackManager } = OHIF.utils;
const metadataProvider = new OHIF.cornerstone.MetadataProvider();
// ~~ Set our MetadataProvider
cornerstone.metaData.addProvider(
metadataProvider.provider.bind(metadataProvider)
);
StackManager.setMetadataProvider(metadataProvider);
// ~~
const defaultCsToolsConfig = csToolsConfig || {
globalToolSyncEnabled: true,
showSVGCursors: true,
autoResizeViewports: false,
};
initCornerstoneTools(defaultCsToolsConfig);
const toolsGroupedByType = {
touch: [csTools.PanMultiTouchTool, csTools.ZoomTouchPinchTool],
annotations: [
csTools.ArrowAnnotateTool,
csTools.EraserTool,
csTools.BidirectionalTool,
csTools.LengthTool,
csTools.AngleTool,
csTools.FreehandRoiTool,
csTools.EllipticalRoiTool,
csTools.DragProbeTool,
csTools.RectangleRoiTool,
],
segmentation: [csTools.BrushTool],
other: [
csTools.PanTool,
csTools.ZoomTool,
csTools.WwwcTool,
csTools.WwwcRegionTool,
csTools.MagnifyTool,
csTools.StackScrollTool,
csTools.StackScrollMouseWheelTool,
],
};
let tools = [];
Object.keys(toolsGroupedByType).forEach(toolsGroup =>
tools.push(...toolsGroupedByType[toolsGroup])
);
/* Add extension tools configuration here. */
const internalToolsConfig = {
ArrowAnnotate: {
configuration: {
getTextCallback: (callback, eventDetails) =>
callInputDialog(null, eventDetails, callback),
changeTextCallback: (data, eventDetails, callback) =>
callInputDialog(data, eventDetails, callback),
},
},
};
/* Abstract tools configuration using extension configuration. */
const parseToolProps = (props, tool) => {
const { annotations } = toolsGroupedByType;
// An alternative approach would be to remove the `drawHandlesOnHover` config
// from the supported configuration properties in `cornerstone-tools`
const toolsWithHideableHandles = annotations.filter(
tool => !['RectangleRoiTool', 'EllipticalRoiTool'].includes(tool.name)
);
let parsedProps = { ...props };
/**
* drawHandles - Never/Always show handles
* drawHandlesOnHover - Only show handles on handle hover (pointNearHandle)
*
* Does not apply to tools where handles aren't placed in predictable
* locations.
*/
if (
configuration.hideHandles !== false &&
toolsWithHideableHandles.includes(tool)
) {
if (props.configuration) {
parsedProps.configuration.drawHandlesOnHover = true;
} else {
parsedProps.configuration = { drawHandlesOnHover: true };
}
}
return parsedProps;
};
/* Add tools with its custom props through extension configuration. */
tools.forEach(tool => {
const toolName = tool.name.replace('Tool', '');
const externalToolsConfig = configuration.tools || {};
const externalToolProps = externalToolsConfig[toolName] || {};
const internalToolProps = internalToolsConfig[toolName] || {};
const props = merge(
internalToolProps,
parseToolProps(externalToolProps, tool)
);
csTools.addTool(tool, props);
});
// TODO -> We need a better way to do this with maybe global tool state setting all tools passive.
const BaseAnnotationTool = csTools.importInternal('base/BaseAnnotationTool');
tools.forEach(tool => {
if (tool.prototype instanceof BaseAnnotationTool) {
// BaseAnnotationTool would likely come from csTools lib exports
const toolName = new tool().name;
csTools.setToolPassive(toolName); // there may be a better place to determine name; may not be on uninstantiated class
}
});
csTools.setToolActive('Pan', { mouseButtonMask: 4 });
csTools.setToolActive('Zoom', { mouseButtonMask: 2 });
csTools.setToolActive('Wwwc', { mouseButtonMask: 1 });
csTools.setToolActive('StackScrollMouseWheel', {}); // TODO: Empty options should not be required
csTools.setToolActive('PanMultiTouch', { pointers: 2 }); // TODO: Better error if no options
csTools.setToolActive('ZoomTouchPinch', {});
}