From bacfa24216c7577499d935a9962d954df80cc311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Botelho=20Almeida?= Date: Wed, 27 Sep 2017 16:55:14 -0300 Subject: [PATCH] OHIF-110: creating the context-menu for measurements in the viewport for desktop and mobile. Coded action delete (#112) --- .../client/components/base/mixins/dropdown.js | 13 +++- .../viewer/toolContextMenu/toolContextMenu.js | 70 +++++++++++++++++++ .../ohif-viewerbase/client/lib/toolManager.js | 46 ++++++++++++ Packages/ohif-viewerbase/package.js | 2 + 4 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 Packages/ohif-viewerbase/client/components/viewer/toolContextMenu/toolContextMenu.js diff --git a/Packages/ohif-core/client/components/base/mixins/dropdown.js b/Packages/ohif-core/client/components/base/mixins/dropdown.js index 1ab8ad6bf..f640d4d44 100644 --- a/Packages/ohif-core/client/components/base/mixins/dropdown.js +++ b/Packages/ohif-core/client/components/base/mixins/dropdown.js @@ -105,11 +105,20 @@ OHIF.mixins.dropdown = new OHIF.Mixin({ // Change the dropdown position if mouse event was given if (event) { + const originalEventTouches = event.originalEvent.touches; const position = { - left: event.clientX, - top: event.clientY + left: 0, + top: 0 }; + if (originalEventTouches && originalEventTouches.length > 0) { + position.left = originalEventTouches[0].pageX; + position.top = originalEventTouches[0].pageY; + } else { + position.left = event.clientX; + position.top = event.clientY + } + if (centered) { // Center the dropdown menu based on the event mouse position position.left -= $dropdownMenu.outerWidth() / 2; diff --git a/Packages/ohif-viewerbase/client/components/viewer/toolContextMenu/toolContextMenu.js b/Packages/ohif-viewerbase/client/components/viewer/toolContextMenu/toolContextMenu.js new file mode 100644 index 000000000..9e76781d7 --- /dev/null +++ b/Packages/ohif-viewerbase/client/components/viewer/toolContextMenu/toolContextMenu.js @@ -0,0 +1,70 @@ +import { Template } from 'meteor/templating'; +import { ReactiveVar } from 'meteor/reactive-var'; +import { toolManager } from '../../../lib/toolManager'; + +const toolTypes = ['length', 'simpleAngle', 'probe', 'ellipticalRoi', 'rectangleRoi', 'arrowAnnotate']; +const TypeToLabelMap = { + length: 'Length', + simpleAngle: 'Angle', + probe: 'Probe', + ellipticalRoi: 'Elliptical ROI', + rectangleRoi: 'Rectangle ROI', + arrowAnnotate: 'Annotation' +}; +let dropdownItems = [{ + actionType: 'Delete', + action: ({nearbyToolData, eventData}) => { + const element = eventData.element + + cornerstoneTools.removeToolState(element, nearbyToolData.toolType, nearbyToolData.tool); + cornerstone.updateImage(element); + } +}]; +let timer = 0; + +const getTypeText = function(toolData, actionType) { + const toolType = toolData.toolType; + let message = `${TypeToLabelMap[toolType]}`; + + if (toolType === 'arrowAnnotate') { + message = `${message} "${toolData.tool.text}"` + } + + return `${actionType} ${message}`; +}; + +const createDropdown = function (event, eventData, isTouchEvent = false) { + const nearbyToolData = toolManager.getNearbyToolData(eventData.element, eventData.currentPoints.canvas, toolTypes); + + // Annotate tools for touch events already have a press handle to edit it, has a better UX for deleting it + if (isTouchEvent && nearbyToolData.toolType === 'arrowAnnotate') { + return; + } + + if (nearbyToolData) { + dropdownItems.forEach(function(item) { + item.params = { + eventData, + nearbyToolData + }; + item.text = getTypeText(nearbyToolData, item.actionType); + }); + + OHIF.ui.showDropdown(dropdownItems, { + menuClasses: 'dropdown-menu-left', + event: eventData.event + }); + } +}; + +Template.viewerMain.events({ + 'CornerstoneToolsMouseClick .imageViewerViewport'(event, instance, eventData) { + if (event.which === 3) { + createDropdown(event, eventData); + } + }, + + 'CornerstoneToolsTouchPress .imageViewerViewport'(event, instance, eventData) { + createDropdown(event, eventData, true); + } +}); \ No newline at end of file diff --git a/Packages/ohif-viewerbase/client/lib/toolManager.js b/Packages/ohif-viewerbase/client/lib/toolManager.js index eeb5ad0fd..04c9baaac 100644 --- a/Packages/ohif-viewerbase/client/lib/toolManager.js +++ b/Packages/ohif-viewerbase/client/lib/toolManager.js @@ -6,6 +6,7 @@ import { updateCrosshairsSynchronizer } from './updateCrosshairsSynchronizer'; import { crosshairsSynchronizers } from './crosshairsSynchronizers'; import { annotateTextUtils } from './annotateTextUtils'; import { textMarkerUtils } from './textMarkerUtils'; +import { isTouchDevice } from './helpers/isTouchDevice'; let defaultTool = 'wwwc'; let activeTool; @@ -446,6 +447,51 @@ export const toolManager = { Session.set('ToolManagerActiveTool', tool); }, + getNearbyToolData(element, coords, toolTypes) { + const allTools = this.getTools(); + const touchDevice = isTouchDevice(); + const nearbyTool = {}; + let pointNearTool = false; + + toolTypes.forEach(function(toolType) { + const toolData = cornerstoneTools.getToolState(element, toolType); + if (!toolData) { + return; + } + + toolData.data.forEach(function(data, index) { + let toolInterfaceName = toolType; + let toolInterface; + + // Edge cases where the tool is not the same as the typeName + if (toolType === 'simpleAngle') { + toolInterfaceName = 'angle'; + } else if (toolType === 'arrowAnnotate') { + toolInterfaceName = 'annotate'; + } + + if (touchDevice) { + toolInterface = allTools[toolInterfaceName].touch; + } else { + toolInterface = allTools[toolInterfaceName].mouse; + } + + if (toolInterface.pointNearTool(element, data, coords)) { + pointNearTool = true; + nearbyTool.tool = data; + nearbyTool.index = index; + nearbyTool.toolType = toolType; + } + }); + + if (pointNearTool) { + return false; + } + }); + + return pointNearTool ? nearbyTool : undefined; + }, + getActiveTool() { if (!initialized) { toolManager.init(); diff --git a/Packages/ohif-viewerbase/package.js b/Packages/ohif-viewerbase/package.js index 695c3b6d9..f74d28b47 100644 --- a/Packages/ohif-viewerbase/package.js +++ b/Packages/ohif-viewerbase/package.js @@ -146,6 +146,8 @@ Package.onUse(function(api) { api.addFiles('client/components/viewer/viewerMain/viewerMain.js', 'client'); api.addFiles('client/components/viewer/viewerMain/viewerMain.styl', 'client'); + api.addFiles('client/components/viewer/toolContextMenu/toolContextMenu.js', 'client'); + api.addFiles('client/components/viewer/imageControls/imageControls.html', 'client'); api.addFiles('client/components/viewer/imageControls/imageControls.js', 'client'); api.addFiles('client/components/viewer/imageControls/imageControls.styl', 'client');