diff --git a/LesionTracker/client/components/toolbarSection/toolbarSection.js b/LesionTracker/client/components/toolbarSection/toolbarSection.js index d4f049c3f..b9abdc9c6 100644 --- a/LesionTracker/client/components/toolbarSection/toolbarSection.js +++ b/LesionTracker/client/components/toolbarSection/toolbarSection.js @@ -78,15 +78,6 @@ Template.toolbarSection.helpers({ disabled: isToolDisabled }); - // Disabling this on Lesion Tracker - // targetSubTools.push({ - // id: 'targetEX', - // title: 'EX Target', - // classes: 'imageViewerTool', - // svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-measure-target-ex', - // disabled: isToolDisabled - // }); - const extraTools = []; extraTools.push({ @@ -145,14 +136,6 @@ Template.toolbarSection.helpers({ svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-elliptical-roi' }); - extraTools.push({ - id: 'linkStackScroll', - title: 'Link Scroll', - classes: 'imageViewerCommand nonAutoDisableState', - svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-link-stack-scroll', - disableFunction: isStackScrollLinkingDisabled - }); - extraTools.push({ id: 'toggleCineDialog', title: 'CINE', @@ -184,15 +167,13 @@ Template.toolbarSection.helpers({ svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-pan' }); - /* - TODO: design the link functionality - Commenting this out until we build this tool buttonData.push({ id: 'link', title: 'Link', - classes: 'imageViewerCommand', - svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-link' - });*/ + classes: 'imageViewerCommand toolbarSectionButton nonAutoDisableState', + svgLink: '/packages/ohif_viewerbase/assets/icons.svg#icon-tools-link', + disableFunction: isStackScrollLinkingDisabled + }); buttonData.push({ id: 'toggleTarget', diff --git a/LesionTracker/client/components/viewer/viewer.js b/LesionTracker/client/components/viewer/viewer.js index 1d7158353..dc3858fc0 100644 --- a/LesionTracker/client/components/viewer/viewer.js +++ b/LesionTracker/client/components/viewer/viewer.js @@ -40,7 +40,7 @@ Template.viewer.onCreated(() => { flipH, rotateL, rotateR, - linkStackScroll + link }); if (ViewerData[contentId].loadedSeriesData) { diff --git a/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.html b/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.html index 0d772c81d..5e0d582c9 100644 --- a/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.html +++ b/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.html @@ -9,6 +9,13 @@
{{studyDescription}}
{{formatDA studyDate}} {{formatTM studyTime}}
+ {{#if linked}} + + {{/if}}
{{#if zoom}}Zoom: {{formatNumberPrecision zoom 0}}%{{/if}}
diff --git a/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.js b/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.js index 3ae7a9a4f..aad9ba92a 100644 --- a/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.js +++ b/Packages/ohif-measurements/client/components/longitudinal/longitudinalViewportOverlay/longitudinalViewportOverlay.js @@ -25,5 +25,10 @@ Template[defaultTemplate].helpers({ const timepoint = timepoints[0]; return timepointApi.name(timepoint); + }, + + linked: function() { + const linkedViewports = Session.get('StackImagePositionOffsetSynchronizerLinkedViewports') || []; + return (linkedViewports.indexOf(this.viewportIndex) !== -1); } }); \ No newline at end of file diff --git a/Packages/ohif-viewerbase/assets/icons.svg b/Packages/ohif-viewerbase/assets/icons.svg index 59a205cdc..2b513ea4c 100644 --- a/Packages/ohif-viewerbase/assets/icons.svg +++ b/Packages/ohif-viewerbase/assets/icons.svg @@ -262,11 +262,11 @@ - + - Stack Scroll Sync + Viewport Link - + diff --git a/Packages/ohif-viewerbase/client/components/viewer/toolbarSectionButton/toolbarSectionButton.js b/Packages/ohif-viewerbase/client/components/viewer/toolbarSectionButton/toolbarSectionButton.js index a565356f3..c9f70e912 100644 --- a/Packages/ohif-viewerbase/client/components/viewer/toolbarSectionButton/toolbarSectionButton.js +++ b/Packages/ohif-viewerbase/client/components/viewer/toolbarSectionButton/toolbarSectionButton.js @@ -13,9 +13,11 @@ Template.toolbarSectionButton.onCreated(() => { const currentId = instance.data.id; const isCurrentTool = currentId === activeToolId; const isSubTool = subTools && _.findWhere(subTools, { id: activeToolId }); + const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || []; + const isActiveCommandButton = activeCommandButtons.indexOf(instance.data.id) !== -1; - // Check if the current tool or a sub tool is the active one - return isCurrentTool || isSubTool; + // Check if the current tool, a sub tool or a command button is active + return isCurrentTool || isSubTool || isActiveCommandButton; }; instance.getActiveToolSubProperty = (propertyName, activeToolId) => { diff --git a/Packages/ohif-viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.styl b/Packages/ohif-viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.styl index 2ffa3e29e..f967130c6 100644 --- a/Packages/ohif-viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.styl +++ b/Packages/ohif-viewerbase/client/components/viewer/viewportOverlay/viewportOverlay.styl @@ -39,3 +39,12 @@ $viewportTagPadding = 20px &.controlsVisible .topright, .bottomright right: "calc(%s + 19px)" % $viewportTagPadding + + svg + theme('color', '$defaultColor') + theme('fill', '$defaultColor') + theme('stroke', '$defaultColor') + background-color: transparent + margin: 2px + width: 18px + height: 18px diff --git a/Packages/ohif-viewerbase/client/lib/stackImagePositionOffsetSynchronizer.js b/Packages/ohif-viewerbase/client/lib/stackImagePositionOffsetSynchronizer.js index 6e046d19a..83959e46d 100644 --- a/Packages/ohif-viewerbase/client/lib/stackImagePositionOffsetSynchronizer.js +++ b/Packages/ohif-viewerbase/client/lib/stackImagePositionOffsetSynchronizer.js @@ -5,7 +5,7 @@ import { $ } from 'meteor/jquery'; class StackImagePositionOffsetSynchronizer { constructor() { this.active = false; - this.syncedViewportElements = []; + this.syncedViewports = []; this.synchronizer = new cornerstoneTools.Synchronizer("CornerstoneNewImage", cornerstoneTools.stackImagePositionOffsetSynchronizer) } @@ -22,16 +22,24 @@ class StackImagePositionOffsetSynchronizer { return; } - const viewportElements = this.getLinkableViewports(); + const viewports = this.getLinkableViewports(); + const viewportIndexes = []; - viewportElements.forEach((viewportElement, index) => { - this.synchronizer.add(viewportElement); - this.syncedViewportElements.push(viewportElement); + if(viewports.length <= 1) { + return; + } + + viewports.forEach((viewport, index) => { + this.synchronizer.add(viewport.element); + this.syncedViewports.push(viewport); + viewportIndexes.push(viewport.index) - $(viewportElement).on(StackImagePositionOffsetSynchronizer.ELEMENT_DISABLED_EVENT, this.elementDisabledHandler(this)); + $(viewport.element).on(StackImagePositionOffsetSynchronizer.ELEMENT_DISABLED_EVENT, this.elementDisabledHandler(this)); }); this.active = true; + toolManager.activateCommandButton('link'); + Session.set('StackImagePositionOffsetSynchronizerLinkedViewports', viewportIndexes); } deactivate() { @@ -39,12 +47,13 @@ class StackImagePositionOffsetSynchronizer { return; } - while(this.syncedViewportElements.length) { - const viewportElement = this.syncedViewportElements[0]; - this.removeViewportElement(viewportElement); + while(this.syncedViewports.length) { + const viewport = this.syncedViewports[0]; + this.removeViewport(viewport); } this.active = false; + toolManager.deactivateCommandButton('link'); } update() { @@ -62,43 +71,68 @@ class StackImagePositionOffsetSynchronizer { this.activate(); } + isViewportSynced(viewportElement) { + return !!this.getViewportByElement(viewportElement); + } + getActiveViewportElement() { const viewportIndex = Session.get('activeViewport') || 0; return $('.imageViewerViewport').get(viewportIndex); } - isViewportSynced(viewportElement) { - let isSynced = false; - - this.syncedViewportElements.forEach(syncedViewportElement => { - isSynced = isSynced || (syncedViewportElement === viewportElement); - }); - - return isSynced; - } - - removeViewportElement(viewportElement) { - const index = this.syncedViewportElements.indexOf(viewportElement); + removeViewport(viewport) { + const index = this.syncedViewports.indexOf(viewport); if(index === -1) { return; } - this.syncedViewportElements.splice(index, 1); - this.synchronizer.remove(viewportElement); - $(viewportElement).off(StackImagePositionOffsetSynchronizer.ELEMENT_DISABLED_EVENT); + this.syncedViewports.splice(index, 1); + this.synchronizer.remove(viewport.element); + this.removeLinkedViewportFromSession(viewport); + $(viewport.element).off(StackImagePositionOffsetSynchronizer.ELEMENT_DISABLED_EVENT); + } + + getViewportByElement(viewportElement) { + const length = this.syncedViewports.length; + + for(let i = 0; i < length; i++) { + const viewport = this.syncedViewports[i]; + + if(viewport.element === viewportElement) { + return viewport; + } + } + } + + removeViewportByElement(viewportElement) { + let viewport = this.getViewportByElement(viewportElement); + + if(viewport) { + this.removeViewport(viewport); + } + } + + removeLinkedViewportFromSession(viewport) { + const linkedViewports = Session.get('StackImagePositionOffsetSynchronizerLinkedViewports'); + const index = linkedViewports.indexOf(viewport.index); + + if(index !== -1) { + linkedViewports.splice(index, 1); + Session.set('StackImagePositionOffsetSynchronizerLinkedViewports', linkedViewports); + } } elementDisabledHandler(context) { return (e, eventData) => { - context.removeViewportElement(eventData.element); + context.removeViewportByElement(eventData.element); } } getLinkableViewports() { const activeViewportElement = this.getActiveViewportElement(); const activeViewportImageNormal = this.getViewportImageNormal(activeViewportElement); - const viewportElements = []; + const viewports = []; $('.imageViewerViewport').each((index, viewportElement) => { const viewportImageNormal = this.getViewportImageNormal(viewportElement); @@ -109,12 +143,15 @@ class StackImagePositionOffsetSynchronizer { // Pi / 12 radians = 15 degrees // If the angle between two vectors is Pi, it means they are just inverted if (angleInRadians < Math.PI / 12 || angleInRadians === Math.PI) { - viewportElements.push(viewportElement) + viewports.push({ + index: index, + element: viewportElement + }); } } }); - return viewportElements; + return viewports; } getViewportImageNormal(element) { diff --git a/Packages/ohif-viewerbase/client/lib/toolManager.js b/Packages/ohif-viewerbase/client/lib/toolManager.js index 3fbc0b8e0..d55c2b0ba 100644 --- a/Packages/ohif-viewerbase/client/lib/toolManager.js +++ b/Packages/ohif-viewerbase/client/lib/toolManager.js @@ -276,6 +276,23 @@ toolManager = { }, getDefaultTool() { return defaultTool; + }, + activateCommandButton(button) { + const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || []; + + if(activeCommandButtons.indexOf(button) === -1) { + activeCommandButtons.push('link'); + Session.set('ToolManagerActiveCommandButtons', activeCommandButtons); + } + }, + deactivateCommandButton(button) { + const activeCommandButtons = Session.get('ToolManagerActiveCommandButtons') || []; + const index = activeCommandButtons.indexOf(button); + + if(index !== -1) { + activeCommandButtons.splice(index, 1); + Session.set('ToolManagerActiveCommandButtons', activeCommandButtons); + } } }; diff --git a/Packages/ohif-viewerbase/client/lib/viewportFunctions.js b/Packages/ohif-viewerbase/client/lib/viewportFunctions.js index 1c9928b9b..95cb19e99 100644 --- a/Packages/ohif-viewerbase/client/lib/viewportFunctions.js +++ b/Packages/ohif-viewerbase/client/lib/viewportFunctions.js @@ -115,7 +115,7 @@ clearTools = () => { cornerstone.updateImage(element); }; -linkStackScroll = () => { +link = () => { const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer; if(synchronizer.isActive()) { diff --git a/Packages/ohif-viewerbase/package.js b/Packages/ohif-viewerbase/package.js index 1c7c5c162..a39d9481e 100644 --- a/Packages/ohif-viewerbase/package.js +++ b/Packages/ohif-viewerbase/package.js @@ -297,5 +297,5 @@ Package.onUse(function(api) { api.export('flipH', 'client'); api.export('rotateR', 'client'); api.export('rotateL', 'client'); - api.export('linkStackScroll', 'client'); + api.export('link', 'client'); });