wip on react transition 8
This commit is contained in:
parent
9ae5dd25ce
commit
71b49e6766
@ -5,6 +5,13 @@ import { Router } from 'meteor/clinical:router';
|
|||||||
import { ReactiveVar } from 'meteor/reactive-var';
|
import { ReactiveVar } from 'meteor/reactive-var';
|
||||||
import { OHIF } from 'meteor/ohif:core';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
|
|
||||||
|
import { createStore } from 'redux';
|
||||||
|
|
||||||
|
const store = createStore(OHIF.viewerbase.redux.combinedReducer);
|
||||||
|
|
||||||
|
// TODO[react] Use a provider when the whole tree is React
|
||||||
|
window.store = store;
|
||||||
|
|
||||||
Template.ohifViewer.onCreated(() => {
|
Template.ohifViewer.onCreated(() => {
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
instance.headerClasses = new ReactiveVar('');
|
instance.headerClasses = new ReactiveVar('');
|
||||||
|
|||||||
@ -38,13 +38,10 @@ const initHangingProtocol = () => {
|
|||||||
HP.setEngine(ProtocolEngine);
|
HP.setEngine(ProtocolEngine);
|
||||||
|
|
||||||
Session.set('ViewerReady', true);
|
Session.set('ViewerReady', true);
|
||||||
|
|
||||||
Session.set('activeViewport', 0);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Meteor.startup(() => {
|
Meteor.startup(() => {
|
||||||
Session.setDefault('activeViewport', false);
|
|
||||||
Session.setDefault('leftSidebar', false);
|
Session.setDefault('leftSidebar', false);
|
||||||
Session.setDefault('rightSidebar', false);
|
Session.setDefault('rightSidebar', false);
|
||||||
|
|
||||||
@ -112,8 +109,6 @@ Template.viewer.onCreated(() => {
|
|||||||
// Store the viewer data in session for further user
|
// Store the viewer data in session for further user
|
||||||
Session.setPersistent('ViewerData', OHIF.viewer.data);
|
Session.setPersistent('ViewerData', OHIF.viewer.data);
|
||||||
|
|
||||||
Session.set('activeViewport', OHIF.viewer.data.activeViewport || 0);
|
|
||||||
|
|
||||||
// @TypeSafeStudies
|
// @TypeSafeStudies
|
||||||
// Clears OHIF.viewer.Studies collection
|
// Clears OHIF.viewer.Studies collection
|
||||||
OHIF.viewer.Studies.removeAll();
|
OHIF.viewer.Studies.removeAll();
|
||||||
|
|||||||
@ -151,7 +151,7 @@ Template.protocolEditor.helpers({
|
|||||||
return ProtocolEngine.getCurrentStageModel();
|
return ProtocolEngine.getCurrentStageModel();
|
||||||
},
|
},
|
||||||
activeViewportUndefined() {
|
activeViewportUndefined() {
|
||||||
const viewportIndex = Session.get('activeViewport');
|
const viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
return (viewportIndex === undefined);
|
return (viewportIndex === undefined);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -318,7 +318,7 @@ Template.ruleEntryDialog.events({
|
|||||||
rule.constraint = constraint;
|
rule.constraint = constraint;
|
||||||
|
|
||||||
// Instruct the Protocol Engine to update the Layout Manager with new data
|
// Instruct the Protocol Engine to update the Layout Manager with new data
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
ProtocolEngine.updateViewports(viewportIndex);
|
ProtocolEngine.updateViewports(viewportIndex);
|
||||||
|
|
||||||
// Close the dialog
|
// Close the dialog
|
||||||
|
|||||||
@ -6,7 +6,7 @@ Template.ruleTable.helpers({
|
|||||||
*/
|
*/
|
||||||
rulePassed: function() {
|
rulePassed: function() {
|
||||||
// Retrieve the latest match details given the active viewport index
|
// Retrieve the latest match details given the active viewport index
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
var details = ProtocolEngine.matchDetails[viewportIndex];
|
var details = ProtocolEngine.matchDetails[viewportIndex];
|
||||||
|
|
||||||
// If no match was found, stop here
|
// If no match was found, stop here
|
||||||
@ -92,7 +92,7 @@ Template.ruleTable.events({
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Instruct the Protocol Engine to update the Layout Manager with new data
|
// Instruct the Protocol Engine to update the Layout Manager with new data
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
ProtocolEngine.updateViewports(viewportIndex);
|
ProtocolEngine.updateViewports(viewportIndex);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -108,7 +108,7 @@ Template.ruleTable.events({
|
|||||||
rule.weight = $(event.currentTarget).val();
|
rule.weight = $(event.currentTarget).val();
|
||||||
|
|
||||||
// Instruct the Protocol Engine to update the Layout Manager with new data
|
// Instruct the Protocol Engine to update the Layout Manager with new data
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
ProtocolEngine.updateViewports(viewportIndex);
|
ProtocolEngine.updateViewports(viewportIndex);
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -124,7 +124,7 @@ Template.ruleTable.events({
|
|||||||
rule.required = $(event.currentTarget).prop('checked');
|
rule.required = $(event.currentTarget).prop('checked');
|
||||||
|
|
||||||
// Instruct the Protocol Engine to update the Layout Manager with new data
|
// Instruct the Protocol Engine to update the Layout Manager with new data
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
ProtocolEngine.updateViewports(viewportIndex);
|
ProtocolEngine.updateViewports(viewportIndex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -165,7 +165,7 @@ Template.settingEntryDialog.events({
|
|||||||
viewport.viewportSettings[viewportSetting.id] = viewportSetting.value;
|
viewport.viewportSettings[viewportSetting.id] = viewportSetting.value;
|
||||||
|
|
||||||
// Instruct the Protocol Engine to update the Layout Manager with new data
|
// Instruct the Protocol Engine to update the Layout Manager with new data
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
ProtocolEngine.updateViewports(viewportIndex);
|
ProtocolEngine.updateViewports(viewportIndex);
|
||||||
|
|
||||||
// Close the dialog
|
// Close the dialog
|
||||||
|
|||||||
@ -37,7 +37,7 @@ Template.settingsTable.events({
|
|||||||
delete viewport.viewportSettings[setting.key];
|
delete viewport.viewportSettings[setting.key];
|
||||||
|
|
||||||
// Instruct the Protocol Engine to update the Layout Manager with new data
|
// Instruct the Protocol Engine to update the Layout Manager with new data
|
||||||
var viewportIndex = Session.get('activeViewport');
|
var viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
ProtocolEngine.updateViewports(viewportIndex);
|
ProtocolEngine.updateViewports(viewportIndex);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,7 +11,7 @@ getActiveViewportModel = function() {
|
|||||||
var stage = ProtocolEngine.getCurrentStageModel();
|
var stage = ProtocolEngine.getCurrentStageModel();
|
||||||
|
|
||||||
// Retrieve the index of the active viewport
|
// Retrieve the index of the active viewport
|
||||||
var activeViewport = Session.get('activeViewport');
|
var activeViewport = window.store.getState().viewports.activeViewport;
|
||||||
|
|
||||||
// If the active viewport index is outside the bounds of the
|
// If the active viewport index is outside the bounds of the
|
||||||
// number of Viewports defined for this Stage, stop here
|
// number of Viewports defined for this Stage, stop here
|
||||||
|
|||||||
@ -8,7 +8,7 @@ OHIF.lesiontracker.pixelSpacingAutorunCheck = () => {
|
|||||||
const $oncologyTools = $('button#lesion, button#nonTarget');
|
const $oncologyTools = $('button#lesion, button#nonTarget');
|
||||||
|
|
||||||
// TODO: Set activeViewport for empty viewport element
|
// TODO: Set activeViewport for empty viewport element
|
||||||
const activeViewportIndex = Session.get('activeViewport');
|
const activeViewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
if (activeViewportIndex === undefined) {
|
if (activeViewportIndex === undefined) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { OHIF } from 'meteor/ohif:core';
|
|||||||
* @returns {Object} - Timepoint data for the active viewport
|
* @returns {Object} - Timepoint data for the active viewport
|
||||||
*/
|
*/
|
||||||
OHIF.measurements.getActiveTimepoint = () => {
|
OHIF.measurements.getActiveTimepoint = () => {
|
||||||
const activeViewportIndex = Session.get('activeViewport');
|
const activeViewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
const { studyInstanceUid } = OHIF.viewerbase.layoutManager.viewportData[activeViewportIndex];
|
const { studyInstanceUid } = OHIF.viewerbase.layoutManager.viewportData[activeViewportIndex];
|
||||||
return OHIF.viewer.timepointApi.study(studyInstanceUid)[0];
|
return OHIF.viewer.timepointApi.study(studyInstanceUid)[0];
|
||||||
};
|
};
|
||||||
|
|||||||
@ -48,7 +48,7 @@ Template.thumbnailEntry.events({
|
|||||||
// Get the viewport index
|
// Get the viewport index
|
||||||
let { viewportIndex } = instance.data;
|
let { viewportIndex } = instance.data;
|
||||||
if (_.isUndefined(viewportIndex)) {
|
if (_.isUndefined(viewportIndex)) {
|
||||||
viewportIndex = Session.get('activeViewport') || 0;
|
viewportIndex = window.store.getState().viewports.activeViewport || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rerender the viewport using the clicked thumbnail data
|
// Rerender the viewport using the clicked thumbnail data
|
||||||
@ -61,7 +61,7 @@ Template.thumbnailEntry.events({
|
|||||||
|
|
||||||
// Get the active viewport index and total number of viewports...
|
// Get the active viewport index and total number of viewports...
|
||||||
const viewportCount = OHIF.viewerbase.layoutManager.getNumberOfViewports();
|
const viewportCount = OHIF.viewerbase.layoutManager.getNumberOfViewports();
|
||||||
let viewportIndex = Session.get('activeViewport') || 0;
|
let viewportIndex = window.store.getState().viewports.activeViewport || 0;
|
||||||
if (viewportIndex >= viewportCount) {
|
if (viewportIndex >= viewportCount) {
|
||||||
viewportIndex = viewportCount > 0 ? viewportCount - 1 : 0;
|
viewportIndex = viewportCount > 0 ? viewportCount - 1 : 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +1,43 @@
|
|||||||
import { Component } from 'react';
|
import {
|
||||||
|
Component,
|
||||||
|
} from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import cloneDeep from 'lodash.clonedeep';
|
import { OHIF } from 'meteor/ohif:core';
|
||||||
import debounce from 'lodash.debounce';
|
import debounce from 'lodash.debounce';
|
||||||
|
// import * as cornerstone from 'cornerstone-core';
|
||||||
|
// import * as cornerstoneTools from 'cornerstone-tools';
|
||||||
|
|
||||||
//import * as cornerstone from 'cornerstone-core';
|
import {
|
||||||
//import * as cornerstoneTools from 'cornerstone-tools';
|
cornerstone,
|
||||||
|
cornerstoneTools,
|
||||||
import { cornerstone, cornerstoneTools } from 'meteor/ohif:cornerstone';
|
} from 'meteor/ohif:cornerstone';
|
||||||
//import './lib/initCornerstone.js';
|
import './CornerstoneViewport.styl';
|
||||||
|
// import './lib/initCornerstone.js';
|
||||||
import ImageScrollbar from '../ImageScrollbar/ImageScrollbar.js';
|
import ImageScrollbar from '../ImageScrollbar/ImageScrollbar.js';
|
||||||
import ViewportOverlay from '../ViewportOverlay/ViewportOverlay.js';
|
import ViewportOverlay from '../ViewportOverlay/ViewportOverlay.js';
|
||||||
import ToolContextMenu from '../ToolContextMenu/ToolContextMenu.js';
|
import ToolContextMenu from '../ToolContextMenu/ToolContextMenu.js';
|
||||||
import LoadingIndicator from '../LoadingIndicator/LoadingIndicator.js';
|
import LoadingIndicator from '../LoadingIndicator/LoadingIndicator.js';
|
||||||
import ViewportOrientationMarkers from '../ViewportOrientationMarkers/ViewportOrientationMarkers.js';
|
import ViewportOrientationMarkers from '../ViewportOrientationMarkers/ViewportOrientationMarkers.js';
|
||||||
import { StackManager } from "../../../lib/StackManager";
|
import {
|
||||||
|
StackManager,
|
||||||
|
} from '../../../lib/StackManager';
|
||||||
import './CornerstoneViewport.styl';
|
import './CornerstoneViewport.styl';
|
||||||
|
|
||||||
const EVENT_RESIZE = 'resize';
|
const EVENT_RESIZE = 'resize';
|
||||||
const loadIndicatorDelay = 45;
|
const loadIndicatorDelay = 45;
|
||||||
const { loadHandlerManager } = cornerstoneTools;
|
const {
|
||||||
|
loadHandlerManager,
|
||||||
|
} = cornerstoneTools;
|
||||||
|
|
||||||
function setToolsPassive(tools) {
|
function setToolsPassive(tools) {
|
||||||
tools.forEach(tool => {
|
tools.forEach((tool) => {
|
||||||
cornerstoneTools.setToolPassive(tool);
|
cornerstoneTools.setToolPassive(tool);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeTools(tools) {
|
function initializeTools(tools) {
|
||||||
Array.from(tools).forEach(tool => {
|
Array.from(tools).forEach((tool) => {
|
||||||
const apiTool = cornerstoneTools[`${tool.name}Tool`];
|
const apiTool = cornerstoneTools[`${tool.name}Tool`];
|
||||||
if (apiTool) {
|
if (apiTool) {
|
||||||
cornerstoneTools.addTool(apiTool, tool.configuration);
|
cornerstoneTools.addTool(apiTool, tool.configuration);
|
||||||
@ -39,12 +48,17 @@ function initializeTools(tools) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getCornerstoneStack(viewportData) {
|
function getCornerstoneStack(viewportData) {
|
||||||
const { displaySetInstanceUid, studyInstanceUid } = viewportData;
|
const {
|
||||||
|
displaySetInstanceUid,
|
||||||
|
studyInstanceUid,
|
||||||
|
} = viewportData;
|
||||||
|
|
||||||
// Create shortcut to displaySet
|
// Create shortcut to displaySet
|
||||||
const study = OHIF.viewer.Studies.findBy({ studyInstanceUid });
|
const study = OHIF.viewer.Studies.findBy({
|
||||||
|
studyInstanceUid,
|
||||||
|
});
|
||||||
|
|
||||||
const displaySet = study.displaySets.find(set => {
|
const displaySet = study.displaySets.find((set) => {
|
||||||
return set.displaySetInstanceUid === displaySetInstanceUid;
|
return set.displaySetInstanceUid === displaySetInstanceUid;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -52,7 +66,7 @@ function getCornerstoneStack(viewportData) {
|
|||||||
const stack = StackManager.findOrCreateStack(study, displaySet);
|
const stack = StackManager.findOrCreateStack(study, displaySet);
|
||||||
stack.currentImageIdIndex = 0;
|
stack.currentImageIdIndex = 0;
|
||||||
|
|
||||||
return stack
|
return stack;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -62,7 +76,7 @@ class CornerstoneViewport extends Component {
|
|||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
const stack = getCornerstoneStack(this.props.viewportData)
|
const stack = getCornerstoneStack(this.props.viewportData);
|
||||||
|
|
||||||
// TODO: Allow viewport as a prop
|
// TODO: Allow viewport as a prop
|
||||||
this.state = {
|
this.state = {
|
||||||
@ -70,9 +84,9 @@ class CornerstoneViewport extends Component {
|
|||||||
displaySetInstanceUid: this.props.viewportData.displaySetInstanceUid,
|
displaySetInstanceUid: this.props.viewportData.displaySetInstanceUid,
|
||||||
imageId: stack.imageIds[0],
|
imageId: stack.imageIds[0],
|
||||||
viewportHeight: '100%',
|
viewportHeight: '100%',
|
||||||
isLoading: false,//true,
|
isLoading: false, // true,
|
||||||
imageScrollbarValue: 0,
|
imageScrollbarValue: 0,
|
||||||
numImagesLoaded: 0
|
numImagesLoaded: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.displayScrollbar = stack.imageIds.length > 1;
|
this.displayScrollbar = stack.imageIds.length > 1;
|
||||||
@ -87,17 +101,21 @@ class CornerstoneViewport extends Component {
|
|||||||
this.doneLoadingHandler = this.doneLoadingHandler.bind(this);
|
this.doneLoadingHandler = this.doneLoadingHandler.bind(this);
|
||||||
this.onMouseClick = this.onMouseClick.bind(this);
|
this.onMouseClick = this.onMouseClick.bind(this);
|
||||||
this.onTouchPress = this.onTouchPress.bind(this);
|
this.onTouchPress = this.onTouchPress.bind(this);
|
||||||
|
this.onTouchStart = this.onTouchStart.bind(this);
|
||||||
this.onMeasurementAddedOrRemoved = this.onMeasurementAddedOrRemoved.bind(
|
this.onMeasurementAddedOrRemoved = this.onMeasurementAddedOrRemoved.bind(
|
||||||
this
|
this,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.setViewportActive = this.setViewportActive.bind(this);
|
||||||
|
|
||||||
this.onCloseToolContextMenu = this.onCloseToolContextMenu.bind(this);
|
this.onCloseToolContextMenu = this.onCloseToolContextMenu.bind(this);
|
||||||
this.imageSliderOnInputCallback = this.imageSliderOnInputCallback.bind(
|
this.imageSliderOnInputCallback = this.imageSliderOnInputCallback.bind(
|
||||||
this
|
this,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.loadHandlerTimeout = 25;
|
this.loadHandlerTimeout = 25;
|
||||||
//loadHandlerManager.setStartLoadHandler(this.startLoadingHandler);
|
// loadHandlerManager.setStartLoadHandler(this.startLoadingHandler);
|
||||||
//loadHandlerManager.setEndLoadHandler(this.doneLoadingHandler);
|
// loadHandlerManager.setEndLoadHandler(this.doneLoadingHandler);
|
||||||
|
|
||||||
this.debouncedResize = debounce(() => {
|
this.debouncedResize = debounce(() => {
|
||||||
try {
|
try {
|
||||||
@ -110,7 +128,7 @@ class CornerstoneViewport extends Component {
|
|||||||
cornerstone.resize(this.element, true);
|
cornerstone.resize(this.element, true);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
viewportHeight: `${this.element.clientHeight - 20}px`
|
viewportHeight: `${this.element.clientHeight - 20}px`,
|
||||||
});
|
});
|
||||||
}, 300);
|
}, 300);
|
||||||
|
|
||||||
@ -118,50 +136,74 @@ class CornerstoneViewport extends Component {
|
|||||||
this.slideTimeout = null;
|
this.slideTimeout = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
static defaultProps = {
|
||||||
const isLoading =
|
activeTool: 'Wwwc',
|
||||||
this.state.isLoading ||
|
}
|
||||||
this.state.numImagesLoaded / this.state.stack.imageIds.length < 0.1;
|
|
||||||
|
|
||||||
return (
|
render() {
|
||||||
<>
|
const isLoading = this.state.isLoading || this.state.numImagesLoaded / this.state.stack.imageIds.length < 0.1;
|
||||||
|
|
||||||
|
return (<div className="CornerstoneViewport" >
|
||||||
<ToolContextMenu
|
<ToolContextMenu
|
||||||
toolContextMenuData={this.state.toolContextMenuData}
|
toolContextMenuData={
|
||||||
onClose={this.onCloseToolContextMenu}
|
this.state.toolContextMenuData
|
||||||
/>
|
}
|
||||||
<div
|
onClose={
|
||||||
className="CornerstoneViewport viewportElement"
|
this.onCloseToolContextMenu
|
||||||
onContextMenu={this.onContextMenu}
|
}
|
||||||
tabIndex='0'
|
/> <div
|
||||||
ref={input => {
|
className="viewport-element"
|
||||||
|
onContextMenu={
|
||||||
|
this.onContextMenu
|
||||||
|
}
|
||||||
|
ref={
|
||||||
|
(input) => {
|
||||||
this.element = input;
|
this.element = input;
|
||||||
}}
|
}
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{isLoading ? <LoadingIndicator /> : ''}
|
{
|
||||||
<canvas className="cornerstone-canvas" />
|
isLoading ? <LoadingIndicator /> : ''
|
||||||
|
} <canvas className="cornerstone-canvas" />
|
||||||
<ViewportOverlay
|
<ViewportOverlay
|
||||||
stack={this.state.stack}
|
stack={
|
||||||
viewport={this.state.viewport}
|
this.state.stack
|
||||||
imageId={this.state.imageId}
|
}
|
||||||
numImagesLoaded={this.state.numImagesLoaded}
|
viewport={
|
||||||
|
this.state.viewport
|
||||||
|
}
|
||||||
|
imageId={
|
||||||
|
this.state.imageId
|
||||||
|
}
|
||||||
|
numImagesLoaded={
|
||||||
|
this.state.numImagesLoaded
|
||||||
|
}
|
||||||
|
/> <ViewportOrientationMarkers
|
||||||
|
imageId={
|
||||||
|
this.state.imageId
|
||||||
|
}
|
||||||
|
viewport={
|
||||||
|
this.state.viewport
|
||||||
|
}
|
||||||
|
/> </div > <div className="viewportInstructions" >
|
||||||
|
Please drag a stack here to view images. </div> {
|
||||||
|
this.displayScrollbar && (<ImageScrollbar
|
||||||
|
onInputCallback={
|
||||||
|
this.imageSliderOnInputCallback
|
||||||
|
}
|
||||||
|
max={
|
||||||
|
this.state.stack.imageIds.length - 1
|
||||||
|
}
|
||||||
|
value={
|
||||||
|
this.state.imageScrollbarValue
|
||||||
|
}
|
||||||
|
height={
|
||||||
|
this.state.viewportHeight
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
<ViewportOrientationMarkers
|
)
|
||||||
imageId={this.state.imageId}
|
} {
|
||||||
viewport={this.state.viewport}
|
/* this.state.bidirectionalAddLabelShow && (
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='viewportInstructions'>
|
|
||||||
Please drag a stack here to view images.
|
|
||||||
</div>
|
|
||||||
{this.displayScrollbar && (
|
|
||||||
<ImageScrollbar
|
|
||||||
onInputCallback={this.imageSliderOnInputCallback}
|
|
||||||
max={this.state.stack.imageIds.length - 1}
|
|
||||||
value={this.state.imageScrollbarValue}
|
|
||||||
height={this.state.viewportHeight}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{/*this.state.bidirectionalAddLabelShow && (
|
|
||||||
<Labelling
|
<Labelling
|
||||||
measurementData={this.bidirectional.measurementData}
|
measurementData={this.bidirectional.measurementData}
|
||||||
eventData={this.bidirectional.eventData}
|
eventData={this.bidirectional.eventData}
|
||||||
@ -169,17 +211,17 @@ class CornerstoneViewport extends Component {
|
|||||||
skipButton={this.bidirectional.skipButton}
|
skipButton={this.bidirectional.skipButton}
|
||||||
editDescription={this.bidirectional.editDescription}
|
editDescription={this.bidirectional.editDescription}
|
||||||
/>
|
/>
|
||||||
)*/}
|
)*/
|
||||||
</>
|
} </div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bidirectionalToolLabellingCallback = (
|
bidirectionalToolLabellingCallback = (
|
||||||
measurementData,
|
measurementData,
|
||||||
eventData,
|
eventData,
|
||||||
doneCallback,
|
doneCallback,
|
||||||
options = {}
|
options = {},
|
||||||
) => {
|
) => {
|
||||||
const labellingDoneCallback = () => {
|
const labellingDoneCallback = () => {
|
||||||
this.hideExtraButtons();
|
this.hideExtraButtons();
|
||||||
return doneCallback();
|
return doneCallback();
|
||||||
@ -190,41 +232,41 @@ class CornerstoneViewport extends Component {
|
|||||||
eventData,
|
eventData,
|
||||||
labellingDoneCallback,
|
labellingDoneCallback,
|
||||||
skipButton: options.skipButton,
|
skipButton: options.skipButton,
|
||||||
editDescription: options.editDescription
|
editDescription: options.editDescription,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
bidirectionalAddLabelShow: true
|
bidirectionalAddLabelShow: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onContextMenu(event) {
|
onContextMenu(event) {
|
||||||
// Preventing the default behaviour for right-click is essential to
|
// Preventing the default behaviour for right-click is essential to
|
||||||
// allow right-click tools to work.
|
// allow right-click tools to work.
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
onWindowResize() {
|
onWindowResize() {
|
||||||
this.debouncedResize();
|
this.debouncedResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
onImageRendered() {
|
onImageRendered() {
|
||||||
const viewport = cornerstone.getViewport(this.element);
|
const viewport = cornerstone.getViewport(this.element);
|
||||||
|
|
||||||
/*this.setState({
|
this.setState({
|
||||||
viewport
|
viewport,
|
||||||
});*/
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onNewImage() {
|
onNewImage() {
|
||||||
const image = cornerstone.getImage(this.element);
|
const image = cornerstone.getImage(this.element);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
imageId: image.imageId
|
imageId: image.imageId,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const element = this.element;
|
const element = this.element;
|
||||||
|
|
||||||
// Enable the DOM Element for use with Cornerstone
|
// Enable the DOM Element for use with Cornerstone
|
||||||
@ -232,11 +274,11 @@ class CornerstoneViewport extends Component {
|
|||||||
|
|
||||||
cornerstone.events.addEventListener(
|
cornerstone.events.addEventListener(
|
||||||
cornerstone.EVENTS.IMAGE_LOADED,
|
cornerstone.EVENTS.IMAGE_LOADED,
|
||||||
this.onImageLoaded
|
this.onImageLoaded,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Load the first image in the stack
|
// Load the first image in the stack
|
||||||
cornerstone.loadAndCacheImage(this.state.imageId).then(image => {
|
cornerstone.loadAndCacheImage(this.state.imageId).then((image) => {
|
||||||
try {
|
try {
|
||||||
cornerstone.getEnabledElement(element);
|
cornerstone.getEnabledElement(element);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -249,7 +291,7 @@ class CornerstoneViewport extends Component {
|
|||||||
const viewport = cornerstone.getDefaultViewportForImage(element, image);
|
const viewport = cornerstone.getDefaultViewportForImage(element, image);
|
||||||
viewport.voi = {
|
viewport.voi = {
|
||||||
windowWidth: 400,
|
windowWidth: 400,
|
||||||
windowCenter: 40
|
windowCenter: 40,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Display the first image
|
// Display the first image
|
||||||
@ -267,31 +309,44 @@ class CornerstoneViewport extends Component {
|
|||||||
cornerstoneTools.addToolState(element, 'stack', stack);
|
cornerstoneTools.addToolState(element, 'stack', stack);
|
||||||
cornerstoneTools.stackPrefetch.enable(this.element);
|
cornerstoneTools.stackPrefetch.enable(this.element);
|
||||||
|
|
||||||
const tools = [
|
const tools = [{
|
||||||
{
|
|
||||||
name: 'Bidirectional',
|
name: 'Bidirectional',
|
||||||
configuration: {
|
configuration: {
|
||||||
getMeasurementLocationCallback: this
|
getMeasurementLocationCallback: this
|
||||||
.bidirectionalToolLabellingCallback,
|
.bidirectionalToolLabellingCallback,
|
||||||
shadow: true,
|
shadow: true,
|
||||||
drawHandlesOnHover: true
|
drawHandlesOnHover: true,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Wwwc',
|
||||||
},
|
},
|
||||||
{ name: 'Wwwc' },
|
|
||||||
{
|
{
|
||||||
name: 'Zoom',
|
name: 'Zoom',
|
||||||
configuration: {
|
configuration: {
|
||||||
minScale: 0.3,
|
minScale: 0.3,
|
||||||
maxScale: 25,
|
maxScale: 25,
|
||||||
preventZoomOutsideImage: true
|
preventZoomOutsideImage: true,
|
||||||
}
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Pan',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'StackScroll',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'PanMultiTouch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'ZoomTouchPinch',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'StackScrollMouseWheel',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'StackScrollMultiTouch',
|
||||||
},
|
},
|
||||||
{ name: 'Pan' },
|
|
||||||
{ name: 'StackScroll' },
|
|
||||||
{ name: 'PanMultiTouch' },
|
|
||||||
{ name: 'ZoomTouchPinch' },
|
|
||||||
{ name: 'StackScrollMouseWheel' },
|
|
||||||
{ name: 'StackScrollMultiTouch' }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
initializeTools(tools);
|
initializeTools(tools);
|
||||||
@ -305,22 +360,22 @@ class CornerstoneViewport extends Component {
|
|||||||
*/
|
*/
|
||||||
cornerstoneTools.setToolActive('PanMultiTouch', {
|
cornerstoneTools.setToolActive('PanMultiTouch', {
|
||||||
mouseButtonMask: 0,
|
mouseButtonMask: 0,
|
||||||
isTouchActive: true
|
isTouchActive: true,
|
||||||
});
|
});
|
||||||
cornerstoneTools.setToolActive('ZoomTouchPinch', {
|
cornerstoneTools.setToolActive('ZoomTouchPinch', {
|
||||||
mouseButtonMask: 0,
|
mouseButtonMask: 0,
|
||||||
isTouchActive: true
|
isTouchActive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
cornerstoneTools.setToolActive('StackScrollMultiTouch', {
|
cornerstoneTools.setToolActive('StackScrollMultiTouch', {
|
||||||
mouseButtonMask: 0,
|
mouseButtonMask: 0,
|
||||||
isTouchActive: true
|
isTouchActive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
cornerstoneTools.stackPrefetch.setConfiguration({
|
cornerstoneTools.stackPrefetch.setConfiguration({
|
||||||
maxImagesToPrefetch: Infinity,
|
maxImagesToPrefetch: Infinity,
|
||||||
preserveExistingPool: false,
|
preserveExistingPool: false,
|
||||||
maxSimultaneousRequests: 6
|
maxSimultaneousRequests: 6,
|
||||||
});
|
});
|
||||||
|
|
||||||
/* For mouse devices, by default we turn on:
|
/* For mouse devices, by default we turn on:
|
||||||
@ -332,81 +387,91 @@ class CornerstoneViewport extends Component {
|
|||||||
|
|
||||||
cornerstoneTools.setToolActive('StackScrollMouseWheel', {
|
cornerstoneTools.setToolActive('StackScrollMouseWheel', {
|
||||||
mouseButtonMask: 0,
|
mouseButtonMask: 0,
|
||||||
isTouchActive: true
|
isTouchActive: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
cornerstone.EVENTS.IMAGE_RENDERED,
|
cornerstone.EVENTS.IMAGE_RENDERED,
|
||||||
this.onImageRendered
|
this.onImageRendered,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.addEventListener(cornerstone.EVENTS.NEW_IMAGE, this.onNewImage);
|
element.addEventListener(cornerstone.EVENTS.NEW_IMAGE, this.onNewImage);
|
||||||
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
cornerstoneTools.EVENTS.STACK_SCROLL,
|
cornerstoneTools.EVENTS.STACK_SCROLL,
|
||||||
this.onStackScroll
|
this.onStackScroll,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
cornerstoneTools.EVENTS.MEASUREMENT_ADDED,
|
cornerstoneTools.EVENTS.MEASUREMENT_ADDED,
|
||||||
this.onMeasurementAddedOrRemoved
|
this.onMeasurementAddedOrRemoved,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
cornerstoneTools.EVENTS.MEASUREMENT_REMOVED,
|
cornerstoneTools.EVENTS.MEASUREMENT_REMOVED,
|
||||||
this.onMeasurementAddedOrRemoved
|
this.onMeasurementAddedOrRemoved,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
cornerstoneTools.EVENTS.MOUSE_CLICK,
|
cornerstoneTools.EVENTS.MOUSE_CLICK,
|
||||||
this.onMouseClick
|
this.onMouseClick,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.addEventListener(
|
element.addEventListener(
|
||||||
cornerstoneTools.EVENTS.TOUCH_PRESS,
|
cornerstoneTools.EVENTS.TOUCH_PRESS,
|
||||||
this.onTouchPress
|
this.onTouchPress,
|
||||||
|
);
|
||||||
|
|
||||||
|
element.addEventListener(
|
||||||
|
cornerstoneTools.EVENTS.TOUCH_START,
|
||||||
|
this.onTouchStart,
|
||||||
);
|
);
|
||||||
|
|
||||||
window.addEventListener(EVENT_RESIZE, this.onWindowResize);
|
window.addEventListener(EVENT_RESIZE, this.onWindowResize);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
viewportHeight: `${this.element.clientHeight - 20}px`
|
viewportHeight: `${this.element.clientHeight - 20}px`,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
const element = this.element;
|
const element = this.element;
|
||||||
element.removeEventListener(
|
element.removeEventListener(
|
||||||
cornerstone.EVENTS.IMAGE_RENDERED,
|
cornerstone.EVENTS.IMAGE_RENDERED,
|
||||||
this.onImageRendered
|
this.onImageRendered,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.removeEventListener(cornerstone.EVENTS.NEW_IMAGE, this.onNewImage);
|
element.removeEventListener(cornerstone.EVENTS.NEW_IMAGE, this.onNewImage);
|
||||||
|
|
||||||
element.removeEventListener(
|
element.removeEventListener(
|
||||||
cornerstoneTools.EVENTS.STACK_SCROLL,
|
cornerstoneTools.EVENTS.STACK_SCROLL,
|
||||||
this.onStackScroll
|
this.onStackScroll,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.removeEventListener(
|
element.removeEventListener(
|
||||||
cornerstoneTools.EVENTS.MEASUREMENT_ADDED,
|
cornerstoneTools.EVENTS.MEASUREMENT_ADDED,
|
||||||
this.onMeasurementAddedOrRemoved
|
this.onMeasurementAddedOrRemoved,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.removeEventListener(
|
element.removeEventListener(
|
||||||
cornerstoneTools.EVENTS.MEASUREMENT_REMOVED,
|
cornerstoneTools.EVENTS.MEASUREMENT_REMOVED,
|
||||||
this.onMeasurementAddedOrRemoved
|
this.onMeasurementAddedOrRemoved,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.removeEventListener(
|
element.removeEventListener(
|
||||||
cornerstoneTools.EVENTS.MOUSE_CLICK,
|
cornerstoneTools.EVENTS.MOUSE_CLICK,
|
||||||
this.onMouseClick
|
this.onMouseClick,
|
||||||
);
|
);
|
||||||
|
|
||||||
element.removeEventListener(
|
element.removeEventListener(
|
||||||
cornerstoneTools.EVENTS.TOUCH_PRESS,
|
cornerstoneTools.EVENTS.TOUCH_PRESS,
|
||||||
this.onTouchPress
|
this.onTouchPress,
|
||||||
|
);
|
||||||
|
|
||||||
|
element.removeEventListener(
|
||||||
|
cornerstoneTools.EVENTS.TOUCH_START,
|
||||||
|
this.onTouchStart,
|
||||||
);
|
);
|
||||||
|
|
||||||
window.removeEventListener(EVENT_RESIZE, this.onWindowResize);
|
window.removeEventListener(EVENT_RESIZE, this.onWindowResize);
|
||||||
@ -415,21 +480,27 @@ class CornerstoneViewport extends Component {
|
|||||||
|
|
||||||
cornerstone.events.removeEventListener(
|
cornerstone.events.removeEventListener(
|
||||||
cornerstone.EVENTS.IMAGE_LOADED,
|
cornerstone.EVENTS.IMAGE_LOADED,
|
||||||
this.onImageLoaded
|
this.onImageLoaded,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
// TODO: Add a real object shallow comparison here?
|
// TODO: Add a real object shallow comparison here?
|
||||||
if (
|
if (
|
||||||
this.state.displaySetInstanceUid !== this.props.viewportData.displaySetInstanceUid
|
this.state.displaySetInstanceUid !== this.props.viewportData.displaySetInstanceUid
|
||||||
) {
|
) {
|
||||||
const { displaySetInstanceUid, studyInstanceUid, currentImageIdIndex } = this.props.viewportData;
|
const {
|
||||||
|
displaySetInstanceUid,
|
||||||
|
studyInstanceUid,
|
||||||
|
currentImageIdIndex,
|
||||||
|
} = this.props.viewportData;
|
||||||
|
|
||||||
// Create shortcut to displaySet
|
// Create shortcut to displaySet
|
||||||
const study = OHIF.viewer.Studies.findBy({ studyInstanceUid });
|
const study = OHIF.viewer.Studies.findBy({
|
||||||
|
studyInstanceUid,
|
||||||
|
});
|
||||||
|
|
||||||
const displaySet = study.displaySets.find(set => {
|
const displaySet = study.displaySets.find((set) => {
|
||||||
return set.displaySetInstanceUid === displaySetInstanceUid;
|
return set.displaySetInstanceUid === displaySetInstanceUid;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -441,7 +512,7 @@ class CornerstoneViewport extends Component {
|
|||||||
if (!currentStack) {
|
if (!currentStack) {
|
||||||
currentStack = {
|
currentStack = {
|
||||||
currentImageIdIndex,
|
currentImageIdIndex,
|
||||||
imageIds: stack.imageIds
|
imageIds: stack.imageIds,
|
||||||
};
|
};
|
||||||
|
|
||||||
cornerstoneTools.addStackStateManager(this.element, ['stack']);
|
cornerstoneTools.addStackStateManager(this.element, ['stack']);
|
||||||
@ -458,11 +529,11 @@ class CornerstoneViewport extends Component {
|
|||||||
displaySetInstanceUid,
|
displaySetInstanceUid,
|
||||||
studyInstanceUid,
|
studyInstanceUid,
|
||||||
stack,
|
stack,
|
||||||
imageId
|
imageId,
|
||||||
});
|
});
|
||||||
|
|
||||||
cornerstoneTools.stackPrefetch.disable(this.element);
|
cornerstoneTools.stackPrefetch.disable(this.element);
|
||||||
cornerstone.loadAndCacheImage(imageId).then(image => {
|
cornerstone.loadAndCacheImage(imageId).then((image) => {
|
||||||
try {
|
try {
|
||||||
cornerstone.getEnabledElement(this.element);
|
cornerstone.getEnabledElement(this.element);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -476,8 +547,8 @@ class CornerstoneViewport extends Component {
|
|||||||
// Workaround for Cornerstone issue #304
|
// Workaround for Cornerstone issue #304
|
||||||
viewport.displayedArea.brhc = {
|
viewport.displayedArea.brhc = {
|
||||||
x: image.width,
|
x: image.width,
|
||||||
y: image.height
|
y: image.height,
|
||||||
}
|
};
|
||||||
|
|
||||||
cornerstone.displayImage(this.element, image, viewport);
|
cornerstone.displayImage(this.element, image, viewport);
|
||||||
|
|
||||||
@ -491,15 +562,15 @@ class CornerstoneViewport extends Component {
|
|||||||
// TODO: Why do we need to do this in v3?
|
// TODO: Why do we need to do this in v3?
|
||||||
cornerstoneTools.setToolActive('StackScrollMouseWheel', {
|
cornerstoneTools.setToolActive('StackScrollMouseWheel', {
|
||||||
mouseButtonMask: 0,
|
mouseButtonMask: 0,
|
||||||
isTouchActive: true
|
isTouchActive: true,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Check this, causes infinite loop
|
// TODO: Check this, causes infinite loop
|
||||||
//this.debouncedResize();
|
// this.debouncedResize();
|
||||||
}
|
}
|
||||||
|
|
||||||
setActiveTool = activeTool => {
|
setActiveTool = (activeTool) => {
|
||||||
const leftMouseTools = ['Bidirectional', 'Wwwc', 'StackScroll'];
|
const leftMouseTools = ['Bidirectional', 'Wwwc', 'StackScroll'];
|
||||||
|
|
||||||
setToolsPassive(leftMouseTools);
|
setToolsPassive(leftMouseTools);
|
||||||
@ -508,7 +579,7 @@ class CornerstoneViewport extends Component {
|
|||||||
const isPanToolActive = activeTool === 'Pan';
|
const isPanToolActive = activeTool === 'Pan';
|
||||||
const panOptions = {
|
const panOptions = {
|
||||||
mouseButtonMask: isPanToolActive ? [1, 4] : [4],
|
mouseButtonMask: isPanToolActive ? [1, 4] : [4],
|
||||||
isTouchActive: isPanToolActive
|
isTouchActive: isPanToolActive,
|
||||||
};
|
};
|
||||||
cornerstoneTools.setToolActive('Pan', panOptions);
|
cornerstoneTools.setToolActive('Pan', panOptions);
|
||||||
|
|
||||||
@ -516,17 +587,19 @@ class CornerstoneViewport extends Component {
|
|||||||
const isZoomToolActive = activeTool === 'Zoom';
|
const isZoomToolActive = activeTool === 'Zoom';
|
||||||
const zoomOptions = {
|
const zoomOptions = {
|
||||||
mouseButtonMask: isZoomToolActive ? [1, 2] : [2],
|
mouseButtonMask: isZoomToolActive ? [1, 2] : [2],
|
||||||
isTouchActive: isZoomToolActive
|
isTouchActive: isZoomToolActive,
|
||||||
};
|
};
|
||||||
cornerstoneTools.setToolActive('Zoom', zoomOptions);
|
cornerstoneTools.setToolActive('Zoom', zoomOptions);
|
||||||
|
|
||||||
cornerstoneTools.setToolActive(activeTool, {
|
cornerstoneTools.setToolActive(activeTool, {
|
||||||
mouseButtonMask: 1,
|
mouseButtonMask: 1,
|
||||||
isTouchActive: true
|
isTouchActive: true,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onStackScroll(event) {
|
||||||
|
this.setViewportActive();
|
||||||
|
|
||||||
onStackScroll(event) {
|
|
||||||
const element = event.currentTarget;
|
const element = event.currentTarget;
|
||||||
const stackData = cornerstoneTools.getToolState(element, 'stack');
|
const stackData = cornerstoneTools.getToolState(element, 'stack');
|
||||||
const stack = stackData.data[0];
|
const stack = stackData.data[0];
|
||||||
@ -535,36 +608,36 @@ class CornerstoneViewport extends Component {
|
|||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
stack,
|
stack,
|
||||||
imageScrollbarValue: stack.currentImageIdIndex
|
imageScrollbarValue: stack.currentImageIdIndex,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onImageLoaded(event) {
|
onImageLoaded() {
|
||||||
this.setState({
|
this.setState({
|
||||||
numImagesLoaded: this.state.numImagesLoaded + 1
|
numImagesLoaded: this.state.numImagesLoaded + 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
startLoadingHandler() {
|
startLoadingHandler() {
|
||||||
//console.log('startLoadingHandler');
|
// console.log('startLoadingHandler');
|
||||||
clearTimeout(this.loadHandlerTimeout);
|
clearTimeout(this.loadHandlerTimeout);
|
||||||
this.loadHandlerTimeout = setTimeout(() => {
|
this.loadHandlerTimeout = setTimeout(() => {
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoading: true
|
isLoading: true,
|
||||||
});
|
});
|
||||||
}, loadIndicatorDelay);
|
}, loadIndicatorDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
doneLoadingHandler() {
|
doneLoadingHandler() {
|
||||||
clearTimeout(this.loadHandlerTimeout);
|
clearTimeout(this.loadHandlerTimeout);
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoading: false
|
isLoading: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onMeasurementAddedOrRemoved(event) {
|
onMeasurementAddedOrRemoved() {
|
||||||
console.log('onMeasurementAddedOrRemoved');
|
console.log('onMeasurementAddedOrRemoved');
|
||||||
/*const { toolType, measurementData } = event.detail;
|
/* const { toolType, measurementData } = event.detail;
|
||||||
|
|
||||||
// TODO: Pass in as prop?
|
// TODO: Pass in as prop?
|
||||||
const toolsOfInterest = ['Bidirectional'];
|
const toolsOfInterest = ['Bidirectional'];
|
||||||
@ -593,64 +666,87 @@ class CornerstoneViewport extends Component {
|
|||||||
measurementData
|
measurementData
|
||||||
);
|
);
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setViewportActive() {
|
||||||
|
const {
|
||||||
|
viewportIndex,
|
||||||
|
} = this.props.viewportData;
|
||||||
|
const activeViewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
|
if (viewportIndex !== activeViewportIndex) {
|
||||||
|
window.store.dispatch({
|
||||||
|
type: 'SET_VIEWPORT_ACTIVE',
|
||||||
|
viewportIndex,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onMouseClick(event) {
|
||||||
|
this.setViewportActive();
|
||||||
|
|
||||||
onMouseClick(event) {
|
|
||||||
if (event.detail.event.which === 3) {
|
if (event.detail.event.which === 3) {
|
||||||
this.setState({
|
this.setState({
|
||||||
toolContextMenuData: {
|
toolContextMenuData: {
|
||||||
eventData: event.detail,
|
eventData: event.detail,
|
||||||
isTouchEvent: false
|
isTouchEvent: false,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onTouchPress(event) {
|
||||||
|
this.setViewportActive();
|
||||||
|
|
||||||
onTouchPress(event) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
toolContextMenuData: {
|
toolContextMenuData: {
|
||||||
eventData: event.detail,
|
eventData: event.detail,
|
||||||
isTouchEvent: true
|
isTouchEvent: true,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onCloseToolContextMenu() {
|
onTouchStart() {
|
||||||
|
this.setViewportActive();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseToolContextMenu() {
|
||||||
this.setState({
|
this.setState({
|
||||||
toolContextMenuData: null
|
toolContextMenuData: null,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
imageSliderOnInputCallback(value) {
|
||||||
|
this.setViewportActive();
|
||||||
|
|
||||||
imageSliderOnInputCallback(value) {
|
|
||||||
this.setState({
|
this.setState({
|
||||||
imageScrollbarValue: value
|
imageScrollbarValue: value,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Note that we throttle requests to prevent the
|
// Note that we throttle requests to prevent the
|
||||||
// user's ultrafast scrolling from firing requests too quickly.
|
// user's ultrafast scrolling from firing requests too quickly.
|
||||||
//clearTimeout(this.slideTimeout);
|
// clearTimeout(this.slideTimeout);
|
||||||
//this.slideTimeout = setTimeout(() => {
|
// this.slideTimeout = setTimeout(() => {
|
||||||
scrollToIndex(this.element, value);
|
scrollToIndex(this.element, value);
|
||||||
//}, this.slideTimeoutTime);
|
// }, this.slideTimeoutTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
hideExtraButtons = () => {
|
hideExtraButtons = () => {
|
||||||
if (this.state.bidirectionalAddLabelShow === true) {
|
if (this.state.bidirectionalAddLabelShow === true) {
|
||||||
this.setState({
|
this.setState({
|
||||||
bidirectionalAddLabelShow: false
|
bidirectionalAddLabelShow: false,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
toolContextMenuData: null
|
toolContextMenuData: null,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
CornerstoneViewport.propTypes = {
|
CornerstoneViewport.propTypes = {
|
||||||
measurementsAddedOrRemoved: PropTypes.func,
|
measurementsAddedOrRemoved: PropTypes.func,
|
||||||
measurementsChanged: PropTypes.func,
|
measurementsChanged: PropTypes.func,
|
||||||
activeTool: PropTypes.string,
|
activeTool: PropTypes.string,
|
||||||
viewportData: PropTypes.object.isRequired
|
viewportData: PropTypes.object.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CornerstoneViewport;
|
export default CornerstoneViewport;
|
||||||
|
|||||||
@ -3,6 +3,10 @@
|
|||||||
.CornerstoneViewport
|
.CornerstoneViewport
|
||||||
width: 100%
|
width: 100%
|
||||||
height: 100%
|
height: 100%
|
||||||
|
|
||||||
|
.viewport-element
|
||||||
|
width: 100%
|
||||||
|
height: 100%
|
||||||
position: relative;
|
position: relative;
|
||||||
background-color: black
|
background-color: black
|
||||||
|
|
||||||
|
|||||||
@ -413,7 +413,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
|||||||
// Check if the current active viewport in the Meteor Session
|
// Check if the current active viewport in the Meteor Session
|
||||||
// Is the same as the viewport in which the activation event was fired.
|
// Is the same as the viewport in which the activation event was fired.
|
||||||
// If it was, no changes are necessary, so stop here.
|
// If it was, no changes are necessary, so stop here.
|
||||||
const activeViewportIndex = Session.get('activeViewport');
|
const activeViewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
if (viewportIndex === activeViewportIndex) return;
|
if (viewportIndex === activeViewportIndex) return;
|
||||||
|
|
||||||
$element.focus();
|
$element.focus();
|
||||||
@ -473,7 +473,7 @@ const loadDisplaySetIntoViewport = (data, templateData) => {
|
|||||||
// Set the active viewport based on the Session variable
|
// Set the active viewport based on the Session variable
|
||||||
// This is done to ensure that the active element has the current
|
// This is done to ensure that the active element has the current
|
||||||
// focus, so that keyboard events are triggered.
|
// focus, so that keyboard events are triggered.
|
||||||
if (viewportIndex === Session.get('activeViewport')) {
|
if (viewportIndex === window.store.getState().viewports.activeViewport) {
|
||||||
const viewportContainer = $element.parents('.viewportContainer');
|
const viewportContainer = $element.parents('.viewportContainer');
|
||||||
|
|
||||||
setActiveViewport(viewportContainer);
|
setActiveViewport(viewportContainer);
|
||||||
@ -563,7 +563,7 @@ Template.imageViewerViewport.onRendered(function() {
|
|||||||
|
|
||||||
// Get the current active viewport index, if this viewport has the same index,
|
// Get the current active viewport index, if this viewport has the same index,
|
||||||
// add the CSS 'active' class to highlight this viewport.
|
// add the CSS 'active' class to highlight this viewport.
|
||||||
const activeViewport = Session.get('activeViewport');
|
const activeViewport = window.store.getState().viewports.activeViewport;
|
||||||
|
|
||||||
// Focus the viewport if it's the active one
|
// Focus the viewport if it's the active one
|
||||||
if (templateData.viewportIndex === activeViewport) {
|
if (templateData.viewportIndex === activeViewport) {
|
||||||
|
|||||||
@ -2,42 +2,129 @@ import { Component } from 'react';
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import './ViewportOverlay.styl';
|
import './ViewportOverlay.styl';
|
||||||
|
import { viewportOverlayUtils } from '../../../lib/viewportOverlayUtils';
|
||||||
|
import { helpers } from '../../../lib/helpers/index.js';
|
||||||
|
const { formatPN, formatDA, formatNumberPrecision, formatTM, isValidNumber} = helpers;
|
||||||
|
|
||||||
|
function getCompression(imageId) {
|
||||||
|
const instance = cornerstone.metaData.get('instance', imageId);
|
||||||
|
if (!instance) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instance.lossyImageCompression === '01' &&
|
||||||
|
instance.lossyImageCompressionRatio !== '') {
|
||||||
|
const compressionMethod = instance.lossyImageCompressionMethod || 'Lossy: ';
|
||||||
|
const compressionRatio = formatNumberPrecision(instance.lossyImageCompressionRatio, 2);
|
||||||
|
return compressionMethod + compressionRatio + ' : 1';
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'Lossless / Uncompressed';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getImageDimensions(imageId) {
|
||||||
|
const instance = cornerstone.metaData.get('instance', imageId)
|
||||||
|
if (!instance) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${instance.columns} x ${instance.rows}`;
|
||||||
|
}
|
||||||
|
|
||||||
class ViewportOverlay extends Component {
|
class ViewportOverlay extends Component {
|
||||||
render() {
|
render() {
|
||||||
const scale = Math.round(this.props.viewport.scale * 100) / 100;
|
const zoom = this.props.viewport.scale * 100;
|
||||||
const imageId = this.props.imageId;
|
const imageId = this.props.imageId;
|
||||||
|
|
||||||
/*const patientId = cornerstone.metaData.get('00100020', imageId);
|
const patientMetadata = cornerstone.metaData.get('patient', imageId);
|
||||||
const studyDate = cornerstone.metaData.get('00080020', imageId);
|
const studyMetadata = cornerstone.metaData.get('study', imageId);
|
||||||
const collection = cornerstone.metaData.get('00131010', imageId);
|
const seriesMetadata = cornerstone.metaData.get('series', imageId);
|
||||||
const studyDescription = cornerstone.metaData.get('00081030', imageId);*/
|
const instanceMetadata = cornerstone.metaData.get('instance', imageId);
|
||||||
|
|
||||||
const windowWidth = Math.round(this.props.viewport.voi.windowWidth);
|
const patientName = patientMetadata.name;
|
||||||
const windowCenter = Math.round(this.props.viewport.voi.windowCenter);
|
const patientId = patientMetadata.id;;
|
||||||
const imagesLeft =
|
const { studyDate, studyTime, studyDescription } = studyMetadata;
|
||||||
this.props.stack.imageIds.length - this.props.numImagesLoaded;
|
const { seriesNumber, seriesDescription } = seriesMetadata;
|
||||||
|
const { instanceNumber, frameTime, thickness, spacingBetweenSlices, sliceLocation } = instanceMetadata;
|
||||||
|
const frameRate = formatNumberPrecision(1000 / frameTime, 1);
|
||||||
|
const compression = getCompression(imageId);
|
||||||
|
const windowWidth = this.props.viewport.voi.windowWidth || 0;
|
||||||
|
const windowCenter = this.props.viewport.voi.windowCenter || 0;
|
||||||
|
const wwwc = `W: ${windowWidth.toFixed(0)} L: ${windowCenter.toFixed(0)}`;
|
||||||
|
const imageIndex = this.props.stack.imageIds.indexOf(this.props.imageId) + 1;
|
||||||
|
const numImages = this.props.stack.imageIds.length;
|
||||||
|
const imageDimensions = getImageDimensions(imageId);
|
||||||
|
|
||||||
|
const normal = (<>
|
||||||
|
<div className="top-left overlay-element">
|
||||||
|
<div>{formatPN(patientName)}</div>
|
||||||
|
<div>{patientId}</div>
|
||||||
|
</div>
|
||||||
|
<div className="top-right overlay-element">
|
||||||
|
<div>{studyDescription}</div>
|
||||||
|
<div>{formatDA(studyDate)} {formatTM(studyTime)}</div>
|
||||||
|
</div>
|
||||||
|
<div className="bottom-right overlay-element">
|
||||||
|
<div>Zoom: {formatNumberPrecision(zoom,0)}%</div>
|
||||||
|
<div className="compressionIndicator">{compression}</div>
|
||||||
|
<div>{wwwc}</div>
|
||||||
|
</div>
|
||||||
|
<div className="bottom-left overlay-element">
|
||||||
|
<div>{seriesNumber >= 0 ? `Ser: ${seriesNumber}` : ''}</div>
|
||||||
|
<div>{numImages > 1 ? `Img: ${instanceNumber} ${imageIndex}/${numImages}` : ''}</div>
|
||||||
|
<div>{frameRate >= 0 ? `${formatNumberPrecision(frameRate, 2)} FPS` : ''}
|
||||||
|
<div>{imageDimensions}</div>
|
||||||
|
<div>
|
||||||
|
<span>{isValidNumber(sliceLocation) ? `Loc: ${formatNumberPrecision(sliceLocation, 2)} mm` : ''}</span>
|
||||||
|
<span>{thickness ? `Thick: ${formatNumberPrecision(thickness, 2)} mm` : ''}</span>
|
||||||
|
<span>{spacingBetweenSlices ? `Spacing: ${formatNumberPrecision(spacingBetweenSlices, 2)} mm` : ''}</span>
|
||||||
|
</div>
|
||||||
|
<div>{seriesDescription}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>);
|
||||||
|
|
||||||
|
const rightOnly = (<>
|
||||||
|
<div className="top-right overlay-element">
|
||||||
|
<div>{formatPN(patientName)}</div>
|
||||||
|
<div>{patientId}</div>
|
||||||
|
<div>{studyDescription}</div>
|
||||||
|
<div>{formatDA(studyDate)} {formatTM(studyTime)}</div>
|
||||||
|
</div>
|
||||||
|
<div className="bottom-right overlay-element">
|
||||||
|
<div>{seriesNumber >= 0 ? `Ser: ${seriesNumber}` : ''}</div>
|
||||||
|
<div>{numImages > 1 ? `Img: ${instanceNumber} ${imageIndex}/${numImages}` : ''}</div>
|
||||||
|
<div>{frameRate >= 0 ? `${formatNumberPrecision(frameRate, 2)} FPS` : ''}</div>
|
||||||
|
<div>{imageDimensions}</div>
|
||||||
|
<div>{seriesDescription}</div>
|
||||||
|
<div>Zoom: ${formatNumberPrecision(zoom, 0)}%</div>
|
||||||
|
<div className="compressionIndicator">{compression}</div>
|
||||||
|
<div>{wwwc}</div>
|
||||||
|
</div>
|
||||||
|
</>);
|
||||||
|
|
||||||
|
const leftOnly = (<>
|
||||||
|
<div className="top-left overlay-element">
|
||||||
|
<div>{formatPN(patientName)}</div>
|
||||||
|
<div>{patientId}</div>
|
||||||
|
<div>{studyDescription}</div>
|
||||||
|
<div>{formatDA(studyDate)} {formatTM(studyTime)}</div>
|
||||||
|
</div>
|
||||||
|
<div className="bottom-left overlay-element">
|
||||||
|
<div>{seriesNumber >= 0 ? `Ser: ${seriesNumber}` : ''}</div>
|
||||||
|
<div>{numImages > 1 ? `Img: ${instanceNumber} ${imageIndex}/${numImages}` : ''}</div>
|
||||||
|
<div>{frameRate >= 0 ? `${formatNumberPrecision(frameRate, 2)} FPS` : ''}</div>
|
||||||
|
<div>{imageDimensions}</div>
|
||||||
|
<div>{seriesDescription}</div>
|
||||||
|
<div>Zoom: ${formatNumberPrecision(zoom, 0)}%</div>
|
||||||
|
<div className="compressionIndicator">{compression}</div>
|
||||||
|
<div>{wwwc}</div>
|
||||||
|
</div>
|
||||||
|
</>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="ViewportOverlay">
|
<div className='ViewportOverlay'>
|
||||||
<div className="top-left overlay-element">
|
{normal}
|
||||||
<span>{this.props.patientId}</span>
|
|
||||||
<span>{this.props.studyDate}</span>
|
|
||||||
<span>{this.props.studyDescription}</span>
|
|
||||||
<span>
|
|
||||||
{imagesLeft > 0 ? `${imagesLeft} images remaining...` : ''}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div className="bottom-left overlay-element">Zoom: {scale}</div>
|
|
||||||
<div className="bottom-right overlay-element">
|
|
||||||
<span>
|
|
||||||
WW/WC: {windowWidth} / {windowCenter}
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
Image: {this.props.stack.currentImageIdIndex + 1} /{' '}
|
|
||||||
{this.props.stack.imageIds.length}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
$viewportTagPadding = 20px
|
$viewportTagPadding = 20px
|
||||||
|
|
||||||
.imageViewerViewport.empty ~ .imageViewerViewportOverlay
|
.imageViewerViewport.empty ~ .ViewportOverlay
|
||||||
display: none
|
display: none
|
||||||
|
|
||||||
.imageViewerViewportOverlay
|
.ViewportOverlay
|
||||||
theme('color', '$textSecondaryColor')
|
theme('color', '$textSecondaryColor')
|
||||||
|
|
||||||
.overlay-element
|
.overlay-element
|
||||||
|
|||||||
@ -88,7 +88,7 @@ Template.cineDialog.onCreated(() => {
|
|||||||
|
|
||||||
// Run this computation every time the active viewport is changed
|
// Run this computation every time the active viewport is changed
|
||||||
instance.autorun(() => {
|
instance.autorun(() => {
|
||||||
Session.get('activeViewport');
|
window.store.getState().viewports.activeViewport;
|
||||||
|
|
||||||
Tracker.afterFlush(() => {
|
Tracker.afterFlush(() => {
|
||||||
// Get the active viewportElement
|
// Get the active viewportElement
|
||||||
|
|||||||
@ -100,7 +100,7 @@ Template.toolbarSectionButton.helpers({
|
|||||||
},
|
},
|
||||||
|
|
||||||
disableButton() {
|
disableButton() {
|
||||||
Session.get('activeViewport');
|
window.store.getState().viewports.activeViewport;
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
const instance = Template.instance();
|
const instance = Template.instance();
|
||||||
const isCommandDisabled = OHIF.commands.isDisabled(instance.data.id);
|
const isCommandDisabled = OHIF.commands.isDisabled(instance.data.id);
|
||||||
|
|||||||
@ -248,3 +248,6 @@ Viewerbase.StackImagePositionOffsetSynchronizer = StackImagePositionOffsetSynchr
|
|||||||
// StudyMetadataSource
|
// StudyMetadataSource
|
||||||
import { StudyMetadataSource } from './lib/classes/StudyMetadataSource';
|
import { StudyMetadataSource } from './lib/classes/StudyMetadataSource';
|
||||||
Viewerbase.StudyMetadataSource = StudyMetadataSource;
|
Viewerbase.StudyMetadataSource = StudyMetadataSource;
|
||||||
|
|
||||||
|
import redux from './lib/redux/';
|
||||||
|
Viewerbase.redux = redux;
|
||||||
|
|||||||
@ -416,7 +416,7 @@ export class LayoutManager {
|
|||||||
const isSequenced = this.isDisplaySetsSequenced(sequenceMap);
|
const isSequenced = this.isDisplaySetsSequenced(sequenceMap);
|
||||||
|
|
||||||
// Get Active Viewport Index if isMultiple is false
|
// Get Active Viewport Index if isMultiple is false
|
||||||
const activeViewportIndex = !isMultiple ? Session.get('activeViewport') : null;
|
const activeViewportIndex = !isMultiple ? window.store.getState().viewports.activeViewport : null;
|
||||||
|
|
||||||
// Check if is next and looping is blocked
|
// Check if is next and looping is blocked
|
||||||
if (isNext && !allowLooping) {
|
if (isNext && !allowLooping) {
|
||||||
@ -649,7 +649,7 @@ export class LayoutManager {
|
|||||||
this.moveMultipleViewportDisplaySets(isNext);
|
this.moveMultipleViewportDisplaySets(isNext);
|
||||||
} else {
|
} else {
|
||||||
// Get the selected viewport index
|
// Get the selected viewport index
|
||||||
const viewportIndex = Session.get('activeViewport');
|
const viewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
|
|
||||||
// Move display sets on a single viewport
|
// Move display sets on a single viewport
|
||||||
this.moveSingleViewportDisplaySets(viewportIndex, isNext);
|
this.moveSingleViewportDisplaySets(viewportIndex, isNext);
|
||||||
|
|||||||
@ -86,7 +86,7 @@ export class StackImagePositionOffsetSynchronizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getActiveViewportElement() {
|
getActiveViewportElement() {
|
||||||
const viewportIndex = Session.get('activeViewport') || 0;
|
const viewportIndex = window.store.getState().viewports.activeViewport || 0;
|
||||||
return $('.imageViewerViewport').get(viewportIndex);
|
return $('.imageViewerViewport').get(viewportIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -86,7 +86,7 @@ export class StudyPrefetcher {
|
|||||||
// Make sure there is a stack to fetch
|
// Make sure there is a stack to fetch
|
||||||
if (this.hasStack(element)) {
|
if (this.hasStack(element)) {
|
||||||
// Check if this is a clip or not
|
// Check if this is a clip or not
|
||||||
const activeViewportIndex = Session.get('activeViewport');
|
const activeViewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
const displaySetInstanceUid = OHIF.viewer.data.loadedSeriesData[activeViewportIndex].displaySetInstanceUid;
|
const displaySetInstanceUid = OHIF.viewer.data.loadedSeriesData[activeViewportIndex].displaySetInstanceUid;
|
||||||
|
|
||||||
const stack = StackManager.findStack(displaySetInstanceUid);
|
const stack = StackManager.findStack(displaySetInstanceUid);
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
import { Blaze } from 'meteor/blaze';
|
import { Blaze } from 'meteor/blaze';
|
||||||
|
|
||||||
|
function formatNumberPrecision(number, precision) {
|
||||||
|
if (number !== null) {
|
||||||
|
return parseFloat(number).toFixed(precision);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A global Blaze UI helper to format a float value to a specified precision
|
* A global Blaze UI helper to format a float value to a specified precision
|
||||||
*/
|
*/
|
||||||
Blaze.registerHelper('formatNumberPrecision', function(context, precision) {
|
Blaze.registerHelper('formatNumberPrecision', formatNumberPrecision);
|
||||||
if (context != null) {
|
|
||||||
return parseFloat(context).toFixed(precision);
|
export default formatNumberPrecision;
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { isTouchDevice } from './isTouchDevice';
|
|||||||
import { formatPN } from './formatPN';
|
import { formatPN } from './formatPN';
|
||||||
import { formatDA } from './formatDA';
|
import { formatDA } from './formatDA';
|
||||||
import { formatTM } from './formatTM';
|
import { formatTM } from './formatTM';
|
||||||
|
import isValidNumber from './isValidNumber';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helpers with side effects only...
|
* Helpers with side effects only...
|
||||||
@ -13,7 +14,7 @@ import { formatTM } from './formatTM';
|
|||||||
|
|
||||||
import './formatJSDate';
|
import './formatJSDate';
|
||||||
import './jsDateFromNow';
|
import './jsDateFromNow';
|
||||||
import './formatNumberPrecision';
|
import formatNumberPrecision from './formatNumberPrecision';
|
||||||
import './inc';
|
import './inc';
|
||||||
import './isDisplaySetActive';
|
import './isDisplaySetActive';
|
||||||
import './getUsername';
|
import './getUsername';
|
||||||
@ -33,7 +34,9 @@ const helpers = {
|
|||||||
isTouchDevice,
|
isTouchDevice,
|
||||||
formatPN,
|
formatPN,
|
||||||
formatDA,
|
formatDA,
|
||||||
formatTM
|
formatTM,
|
||||||
|
formatNumberPrecision,
|
||||||
|
isValidNumber,
|
||||||
};
|
};
|
||||||
|
|
||||||
export { helpers };
|
export { helpers };
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
export default function isValidNumber(value) {
|
||||||
|
return typeof value === 'number' && !isNaN(value);
|
||||||
|
}
|
||||||
@ -92,7 +92,7 @@ Meteor.startup(function() {
|
|||||||
|
|
||||||
// Create a function that returns true if the active viewport is empty
|
// Create a function that returns true if the active viewport is empty
|
||||||
const isActiveViewportEmpty = () => {
|
const isActiveViewportEmpty = () => {
|
||||||
const activeViewport = Session.get('activeViewport') || 0;
|
const activeViewport = window.store.getState().viewports.activeViewport || 0;
|
||||||
return $('.imageViewerViewport').eq(activeViewport).hasClass('empty');
|
return $('.imageViewerViewport').eq(activeViewport).hasClass('empty');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import { setActiveViewport } from './setActiveViewport';
|
|||||||
|
|
||||||
const loadPreviousActivePanel = () => {
|
const loadPreviousActivePanel = () => {
|
||||||
OHIF.log.info('nextActivePanel');
|
OHIF.log.info('nextActivePanel');
|
||||||
let currentIndex = Session.get('activeViewport');
|
let currentIndex = window.store.getState().viewports.activeViewport;
|
||||||
currentIndex--;
|
currentIndex--;
|
||||||
|
|
||||||
const $viewports = $('.viewportContainer');
|
const $viewports = $('.viewportContainer');
|
||||||
@ -24,7 +24,7 @@ const loadPreviousActivePanel = () => {
|
|||||||
|
|
||||||
const loadNextActivePanel = () => {
|
const loadNextActivePanel = () => {
|
||||||
OHIF.log.info('nextActivePanel');
|
OHIF.log.info('nextActivePanel');
|
||||||
let currentIndex = Session.get('activeViewport');
|
let currentIndex = window.store.getState().viewports.activeViewport;
|
||||||
currentIndex++;
|
currentIndex++;
|
||||||
|
|
||||||
const $viewports = $('.viewportContainer');
|
const $viewports = $('.viewportContainer');
|
||||||
|
|||||||
9
Packages/ohif-viewerbase/client/lib/redux/actions.js
Normal file
9
Packages/ohif-viewerbase/client/lib/redux/actions.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export const setToolActive = tool => ({
|
||||||
|
type: 'SET_TOOL_ACTIVE',
|
||||||
|
tool
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setViewportActive = viewportIndex => ({
|
||||||
|
type: 'SET_VIEWPORT_ACTIVE',
|
||||||
|
viewportIndex
|
||||||
|
});
|
||||||
8
Packages/ohif-viewerbase/client/lib/redux/index.js
Normal file
8
Packages/ohif-viewerbase/client/lib/redux/index.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import './actions.js';
|
||||||
|
import combinedReducer from './reducers';
|
||||||
|
|
||||||
|
const redux = {
|
||||||
|
combinedReducer
|
||||||
|
};
|
||||||
|
|
||||||
|
export default redux;
|
||||||
10
Packages/ohif-viewerbase/client/lib/redux/reducers/index.js
Normal file
10
Packages/ohif-viewerbase/client/lib/redux/reducers/index.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import { combineReducers } from 'redux';
|
||||||
|
import tools from './tools.js';
|
||||||
|
import viewports from './viewports.js';
|
||||||
|
|
||||||
|
const combinedReducer = combineReducers({
|
||||||
|
tools,
|
||||||
|
viewports
|
||||||
|
});
|
||||||
|
|
||||||
|
export default combinedReducer;
|
||||||
101
Packages/ohif-viewerbase/client/lib/redux/reducers/tools.js
Normal file
101
Packages/ohif-viewerbase/client/lib/redux/reducers/tools.js
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
const defaultButtons = [
|
||||||
|
{
|
||||||
|
command: 'Pan',
|
||||||
|
type: 'tool',
|
||||||
|
text: 'Pan',
|
||||||
|
svgUrl: '/icons.svg#icon-tools-pan',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'Zoom',
|
||||||
|
type: 'tool',
|
||||||
|
text: 'Zoom',
|
||||||
|
svgUrl: '/icons.svg#icon-tools-zoom',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'Bidirectional',
|
||||||
|
type: 'tool',
|
||||||
|
text: 'Bidirectional',
|
||||||
|
svgUrl: '/icons.svg#icon-tools-measure-target',
|
||||||
|
active: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'StackScroll',
|
||||||
|
type: 'tool',
|
||||||
|
text: 'Stack Scroll',
|
||||||
|
svgUrl: '/icons.svg#icon-tools-stack-scroll',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'reset',
|
||||||
|
type: 'command',
|
||||||
|
text: 'Reset',
|
||||||
|
svgUrl: '/icons.svg#icon-tools-reset',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'Wwwc',
|
||||||
|
type: 'tool',
|
||||||
|
text: 'Manual',
|
||||||
|
svgUrl: '/icons.svg#icon-tools-levels',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'setWLPresetSoftTissue',
|
||||||
|
type: 'command',
|
||||||
|
text: 'Soft Tissue',
|
||||||
|
svgUrl: '/icons.svg#icon-wl-soft-tissue',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'setWLPresetLung',
|
||||||
|
type: 'command',
|
||||||
|
text: 'Lung',
|
||||||
|
svgUrl: '/icons.svg#icon-wl-lung',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'setWLPresetLiver',
|
||||||
|
type: 'command',
|
||||||
|
text: 'Liver',
|
||||||
|
svgUrl: '/icons.svg#icon-wl-liver',
|
||||||
|
active: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
command: 'setWLPresetBrain',
|
||||||
|
type: 'command',
|
||||||
|
text: 'Brain',
|
||||||
|
svgUrl: '/icons.svg#icon-wl-brain',
|
||||||
|
active: false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const tools = (state = { buttons: defaultButtons }, action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case 'SET_TOOL_ACTIVE':
|
||||||
|
const item = state.buttons.find(button => button.command === action.tool);
|
||||||
|
|
||||||
|
let buttons = [];
|
||||||
|
|
||||||
|
if (item.type === 'tool') {
|
||||||
|
buttons = state.buttons.map(button => {
|
||||||
|
if (button.command === action.tool) {
|
||||||
|
button.active = true;
|
||||||
|
} else if (button.type === 'tool') {
|
||||||
|
button.active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return button;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
buttons
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default tools;
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
const defaultState = {
|
||||||
|
activeViewport: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const viewports = (state = defaultState, action) => {
|
||||||
|
console.warn(action);
|
||||||
|
switch (action.type) {
|
||||||
|
case 'SET_VIEWPORT_ACTIVE':
|
||||||
|
return Object.assign({}, state, { activeViewport: action.viewportIndex });
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default viewports;
|
||||||
@ -30,9 +30,12 @@ export function setActiveViewport(element) {
|
|||||||
$element.trigger('OHIFBeforeActivateViewport');
|
$element.trigger('OHIFBeforeActivateViewport');
|
||||||
}
|
}
|
||||||
|
|
||||||
// When an OHIFActivateViewport event is fired, update the Meteor Session
|
// When an OHIFActivateViewport event is fired, update the Redux state
|
||||||
// with the viewport index that it was fired from.
|
// with the viewport index that it was fired from.
|
||||||
Session.set('activeViewport', viewportIndex);
|
window.store.dispatch({
|
||||||
|
type: 'SET_VIEWPORT_ACTIVE',
|
||||||
|
viewportIndex
|
||||||
|
});
|
||||||
|
|
||||||
// Finally, enable stack prefetching and hide the reference lines from
|
// Finally, enable stack prefetching and hide the reference lines from
|
||||||
// the newly activated viewport that has a canvas
|
// the newly activated viewport that has a canvas
|
||||||
|
|||||||
@ -12,7 +12,7 @@ const setFocusToActiveViewport = () => {
|
|||||||
const viewports = $('.imageViewerViewport');
|
const viewports = $('.imageViewerViewport');
|
||||||
|
|
||||||
// Get the current active viewport index from Session
|
// Get the current active viewport index from Session
|
||||||
const activeViewportIndex = Session.get('activeViewport');
|
const activeViewportIndex = window.store.getState().viewports.activeViewport;
|
||||||
|
|
||||||
// Find the div from the list of viewports
|
// Find the div from the list of viewports
|
||||||
const activeViewport = viewports.eq(activeViewportIndex);
|
const activeViewport = viewports.eq(activeViewportIndex);
|
||||||
|
|||||||
@ -30,7 +30,7 @@ const getEnabledElement = element => {
|
|||||||
* @return {DOMElement} DOMElement of the current active viewport
|
* @return {DOMElement} DOMElement of the current active viewport
|
||||||
*/
|
*/
|
||||||
const getActiveViewportElement = () => {
|
const getActiveViewportElement = () => {
|
||||||
const viewportIndex = Session.get('activeViewport') || 0;
|
const viewportIndex = window.store.getState().viewports.activeViewport || 0;
|
||||||
return $('.imageViewerViewport').get(viewportIndex);
|
return $('.imageViewerViewport').get(viewportIndex);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -274,7 +274,7 @@ const isPlaying = () => {
|
|||||||
// Check if a study has multiple frames
|
// Check if a study has multiple frames
|
||||||
const hasMultipleFrames = () => {
|
const hasMultipleFrames = () => {
|
||||||
// Its called everytime active viewport and/or layout change
|
// Its called everytime active viewport and/or layout change
|
||||||
Session.get('activeViewport');
|
window.store.getState().viewports.activeViewport;
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
const activeViewport = getActiveViewportElement();
|
const activeViewport = getActiveViewportElement();
|
||||||
@ -326,7 +326,7 @@ const isStackScrollLinkingDisabled = () => {
|
|||||||
let linkableViewportsCount = 0;
|
let linkableViewportsCount = 0;
|
||||||
|
|
||||||
// Its called everytime active viewport and/or layout change
|
// Its called everytime active viewport and/or layout change
|
||||||
Session.get('activeViewport');
|
window.store.getState().viewports.activeViewport;
|
||||||
Session.get('LayoutManagerUpdated');
|
Session.get('LayoutManagerUpdated');
|
||||||
|
|
||||||
const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer;
|
const synchronizer = OHIF.viewer.stackImagePositionOffsetSynchronizer;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user