Merge branch 'master' of github.com:OHIF/Viewers
# Conflicts: # extensions/ohif-cornerstone-extension/package.json # package.json # src/components/Header/Header.js # src/components/Labelling/LabellingFlow.js # src/components/OHIFLogo/OHIFLogo.js # src/connectedComponents/ConnectedPluginSwitch.js # src/connectedComponents/ToolbarRow.js # src/utils/getDefaultToolbarButtons.js # src/utils/getDefaultToolbarButtons.test.js # yarn.lock
This commit is contained in:
commit
ffbd6ad6e4
64 files changed
+988
-961
No files matched your search
@@ -2,15 +2,15 @@ import { connect } from 'react-redux';
|
||||
import FlexboxLayout from './FlexboxLayout';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
leftSidebarOpen: state.ui.leftSidebarOpen,
|
||||
rightSidebarOpen: state.ui.rightSidebarOpen,
|
||||
};
|
||||
return {
|
||||
leftSidebarOpen: state.ui.leftSidebarOpen,
|
||||
rightSidebarOpen: state.ui.rightSidebarOpen,
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedFlexboxLayout = connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
mapStateToProps,
|
||||
null
|
||||
)(FlexboxLayout);
|
||||
|
||||
export default ConnectedFlexboxLayout;
|
||||
@@ -4,7 +4,7 @@ import { setUserPreferencesModalOpen } from '../redux/actions.js';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
isOpen: state.ui.userPreferencesModalOpen
|
||||
isOpen: state.ui.userPreferencesModalOpen,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@ const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
openUserPreferencesModal: () => {
|
||||
dispatch(setUserPreferencesModalOpen(true));
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { connect } from 'react-redux'
|
||||
import LabellingOverlay from './LabellingOverlay'
|
||||
import { connect } from 'react-redux';
|
||||
import LabellingOverlay from './LabellingOverlay';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
if (!state.ui || !state.ui.labelling) {
|
||||
return {
|
||||
visible: false,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const labellingFlowData = state.ui.labelling
|
||||
const labellingFlowData = state.ui.labelling;
|
||||
|
||||
return {
|
||||
visible: false,
|
||||
...labellingFlowData,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedLabellingOverlay = connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(LabellingOverlay)
|
||||
)(LabellingOverlay);
|
||||
|
||||
export default ConnectedLabellingOverlay
|
||||
export default ConnectedLabellingOverlay;
|
||||
@@ -1,41 +1,41 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { LayoutButton } from 'react-viewerbase';
|
||||
import OHIF from 'ohif-core'
|
||||
import OHIF from 'ohif-core';
|
||||
|
||||
const { setLayout } = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
currentLayout: state.viewports.layout,
|
||||
};
|
||||
return {
|
||||
currentLayout: state.viewports.layout,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
// TODO: Change if layout switched becomes more complex
|
||||
onChange: selectedCell => {
|
||||
let viewports = [];
|
||||
const rows = selectedCell.row + 1;
|
||||
const columns = selectedCell.col + 1;
|
||||
const numViewports = rows * columns;
|
||||
for (let i = 0; i < numViewports; i++) {
|
||||
viewports.push({
|
||||
height: `${100 / rows}%`,
|
||||
width: `${100 / columns}%`
|
||||
});
|
||||
}
|
||||
const layout = {
|
||||
viewports
|
||||
};
|
||||
return {
|
||||
// TODO: Change if layout switched becomes more complex
|
||||
onChange: selectedCell => {
|
||||
let viewports = [];
|
||||
const rows = selectedCell.row + 1;
|
||||
const columns = selectedCell.col + 1;
|
||||
const numViewports = rows * columns;
|
||||
for (let i = 0; i < numViewports; i++) {
|
||||
viewports.push({
|
||||
height: `${100 / rows}%`,
|
||||
width: `${100 / columns}%`,
|
||||
});
|
||||
}
|
||||
const layout = {
|
||||
viewports,
|
||||
};
|
||||
|
||||
dispatch(setLayout(layout))
|
||||
}
|
||||
};
|
||||
dispatch(setLayout(layout));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedLayoutButton = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(LayoutButton);
|
||||
|
||||
export default ConnectedLayoutButton;
|
||||
@@ -27,7 +27,7 @@ const mapStateToProps = state => {
|
||||
layout: state.viewports.layout,
|
||||
activeViewportIndex: state.viewports.activeViewportIndex,
|
||||
availablePlugins,
|
||||
defaultPlugin
|
||||
defaultPlugin,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,41 +1,41 @@
|
||||
import { connect } from 'react-redux'
|
||||
import { MeasurementTable } from 'react-viewerbase'
|
||||
import OHIF from 'ohif-core'
|
||||
import moment from 'moment'
|
||||
import cornerstone from 'cornerstone-core'
|
||||
import jumpToRowItem from '../lib/jumpToRowItem.js'
|
||||
import getMeasurementLocationCallback from '../lib/getMeasurementLocationCallback'
|
||||
import { connect } from 'react-redux';
|
||||
import { MeasurementTable } from 'react-viewerbase';
|
||||
import OHIF from 'ohif-core';
|
||||
import moment from 'moment';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import jumpToRowItem from '../lib/jumpToRowItem.js';
|
||||
import getMeasurementLocationCallback from '../lib/getMeasurementLocationCallback';
|
||||
|
||||
const { setViewportSpecificData } = OHIF.redux.actions
|
||||
const { MeasurementApi } = OHIF.measurements
|
||||
const { setViewportSpecificData } = OHIF.redux.actions;
|
||||
const { MeasurementApi } = OHIF.measurements;
|
||||
|
||||
function groupBy(list, props) {
|
||||
return list.reduce((a, b) => {
|
||||
;(a[b[props]] = a[b[props]] || []).push(b)
|
||||
return a
|
||||
}, {})
|
||||
(a[b[props]] = a[b[props]] || []).push(b);
|
||||
return a;
|
||||
}, {});
|
||||
}
|
||||
|
||||
function getAllTools() {
|
||||
const config = OHIF.measurements.MeasurementApi.getConfiguration()
|
||||
let tools = []
|
||||
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
||||
let tools = [];
|
||||
config.measurementTools.forEach(
|
||||
toolGroup => (tools = tools.concat(toolGroup.childTools))
|
||||
)
|
||||
);
|
||||
|
||||
return tools
|
||||
return tools;
|
||||
}
|
||||
|
||||
function getMeasurementText(measurementData) {
|
||||
const { location, description } = measurementData
|
||||
let text = '...'
|
||||
const { location, description } = measurementData;
|
||||
let text = '...';
|
||||
if (location) {
|
||||
text = location
|
||||
text = location;
|
||||
if (description) {
|
||||
text += `(${description})`
|
||||
text += `(${description})`;
|
||||
}
|
||||
}
|
||||
return text
|
||||
return text;
|
||||
}
|
||||
|
||||
function getDataForEachMeasurementNumber(
|
||||
@@ -43,54 +43,54 @@ function getDataForEachMeasurementNumber(
|
||||
timepoints,
|
||||
displayFunction
|
||||
) {
|
||||
const data = []
|
||||
const data = [];
|
||||
// on each measurement number we should get each measurement data by available timepoint
|
||||
measurementNumberList.forEach(measurement => {
|
||||
timepoints.forEach(timepoint => {
|
||||
const eachData = {
|
||||
displayText: '...',
|
||||
}
|
||||
};
|
||||
if (measurement.timepointId === timepoint.timepointId) {
|
||||
eachData.displayText = displayFunction(measurement)
|
||||
eachData.displayText = displayFunction(measurement);
|
||||
}
|
||||
data.push(eachData)
|
||||
})
|
||||
})
|
||||
data.push(eachData);
|
||||
});
|
||||
});
|
||||
|
||||
return data
|
||||
return data;
|
||||
}
|
||||
|
||||
function convertMeasurementsToTableData(toolCollections, timepoints) {
|
||||
const config = OHIF.measurements.MeasurementApi.getConfiguration()
|
||||
const toolGroups = config.measurementTools
|
||||
const tools = getAllTools()
|
||||
const config = OHIF.measurements.MeasurementApi.getConfiguration();
|
||||
const toolGroups = config.measurementTools;
|
||||
const tools = getAllTools();
|
||||
|
||||
const tableMeasurements = toolGroups.map(toolGroup => {
|
||||
return {
|
||||
groupName: toolGroup.name,
|
||||
groupId: toolGroup.id,
|
||||
measurements: [],
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
Object.keys(toolCollections).forEach(toolId => {
|
||||
const toolMeasurements = toolCollections[toolId]
|
||||
const tool = tools.find(tool => tool.id === toolId)
|
||||
const { displayFunction } = tool.options.measurementTable
|
||||
const toolMeasurements = toolCollections[toolId];
|
||||
const tool = tools.find(tool => tool.id === toolId);
|
||||
const { displayFunction } = tool.options.measurementTable;
|
||||
|
||||
// Group by measurementNumber so we can display then all in the same line
|
||||
const groupedMeasurements = groupBy(toolMeasurements, 'measurementNumber')
|
||||
const groupedMeasurements = groupBy(toolMeasurements, 'measurementNumber');
|
||||
|
||||
Object.keys(groupedMeasurements).forEach(groupedMeasurementsIndex => {
|
||||
const measurementNumberList =
|
||||
groupedMeasurements[groupedMeasurementsIndex]
|
||||
const measurementData = measurementNumberList[0]
|
||||
groupedMeasurements[groupedMeasurementsIndex];
|
||||
const measurementData = measurementNumberList[0];
|
||||
const {
|
||||
measurementNumber,
|
||||
lesionNamingNumber,
|
||||
toolType,
|
||||
} = measurementData
|
||||
const measurementId = measurementData._id
|
||||
} = measurementData;
|
||||
const measurementId = measurementData._id;
|
||||
|
||||
//check if all measurements with same measurementNumber will have same LABEL
|
||||
const tableMeasurement = {
|
||||
@@ -109,30 +109,30 @@ function convertMeasurementsToTableData(toolCollections, timepoints) {
|
||||
timepoints,
|
||||
displayFunction
|
||||
),
|
||||
}
|
||||
};
|
||||
|
||||
// find the group object for the tool
|
||||
const toolGroupMeasurements = tableMeasurements.find(group => {
|
||||
return group.groupId === tool.toolGroup
|
||||
})
|
||||
return group.groupId === tool.toolGroup;
|
||||
});
|
||||
// inject the new measurement for this measurementNumer
|
||||
toolGroupMeasurements.measurements.push(tableMeasurement)
|
||||
})
|
||||
})
|
||||
toolGroupMeasurements.measurements.push(tableMeasurement);
|
||||
});
|
||||
});
|
||||
|
||||
// Sort measurements by lesion naming number
|
||||
tableMeasurements.forEach(tm => {
|
||||
tm.measurements.sort((m1, m2) =>
|
||||
m1.lesionNamingNumber > m2.lesionNamingNumber ? 1 : -1
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
return tableMeasurements
|
||||
return tableMeasurements;
|
||||
}
|
||||
|
||||
function convertTimepointsToTableData(timepoints) {
|
||||
if (!timepoints || !timepoints.length) {
|
||||
return []
|
||||
return [];
|
||||
}
|
||||
|
||||
return [
|
||||
@@ -140,11 +140,11 @@ function convertTimepointsToTableData(timepoints) {
|
||||
label: 'Study date:',
|
||||
date: moment(timepoints[0].latestDate).format('DD-MMM-YY'),
|
||||
},
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { timepoints, measurements } = state.timepointManager
|
||||
const { timepoints, measurements } = state.timepointManager;
|
||||
return {
|
||||
timepoints: convertTimepointsToTableData(timepoints),
|
||||
measurementCollection: convertMeasurementsToTableData(
|
||||
@@ -153,22 +153,22 @@ const mapStateToProps = state => {
|
||||
),
|
||||
timepointManager: state.timepointManager,
|
||||
viewports: state.viewports,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
dispatchRelabel: (event, measurementData, viewportsState) => {
|
||||
const activeViewportIndex =
|
||||
(viewportsState && viewportsState.activeViewportIndex) || 0
|
||||
(viewportsState && viewportsState.activeViewportIndex) || 0;
|
||||
|
||||
const enabledElements = cornerstone.getEnabledElements()
|
||||
const enabledElements = cornerstone.getEnabledElements();
|
||||
if (!enabledElements || enabledElements.length <= activeViewportIndex) {
|
||||
OHIF.log.error('Failed to find the enabled element')
|
||||
return
|
||||
OHIF.log.error('Failed to find the enabled element');
|
||||
return;
|
||||
}
|
||||
|
||||
const { element } = enabledElements[activeViewportIndex]
|
||||
const { element } = enabledElements[activeViewportIndex];
|
||||
|
||||
const eventData = {
|
||||
event: {
|
||||
@@ -176,33 +176,33 @@ const mapDispatchToProps = dispatch => {
|
||||
clientY: event.clientY,
|
||||
},
|
||||
element,
|
||||
}
|
||||
};
|
||||
|
||||
const { toolType, measurementId } = measurementData
|
||||
const { toolType, measurementId } = measurementData;
|
||||
const tool = MeasurementApi.Instance.tools[toolType].find(measurement => {
|
||||
return measurement._id === measurementId
|
||||
})
|
||||
return measurement._id === measurementId;
|
||||
});
|
||||
|
||||
const options = {
|
||||
skipAddLabelButton: true,
|
||||
editLocation: true,
|
||||
}
|
||||
};
|
||||
|
||||
// Clone the tool not to set empty location initially
|
||||
const toolForLocation = Object.assign({}, tool, { location: null })
|
||||
getMeasurementLocationCallback(eventData, toolForLocation, options)
|
||||
const toolForLocation = Object.assign({}, tool, { location: null });
|
||||
getMeasurementLocationCallback(eventData, toolForLocation, options);
|
||||
},
|
||||
dispatchEditDescription: (event, measurementData, viewportsState) => {
|
||||
const activeViewportIndex =
|
||||
(viewportsState && viewportsState.activeViewportIndex) || 0
|
||||
(viewportsState && viewportsState.activeViewportIndex) || 0;
|
||||
|
||||
const enabledElements = cornerstone.getEnabledElements()
|
||||
const enabledElements = cornerstone.getEnabledElements();
|
||||
if (!enabledElements || enabledElements.length <= activeViewportIndex) {
|
||||
OHIF.log.error('Failed to find the enabled element')
|
||||
return
|
||||
OHIF.log.error('Failed to find the enabled element');
|
||||
return;
|
||||
}
|
||||
|
||||
const { element } = enabledElements[activeViewportIndex]
|
||||
const { element } = enabledElements[activeViewportIndex];
|
||||
|
||||
const eventData = {
|
||||
event: {
|
||||
@@ -210,18 +210,18 @@ const mapDispatchToProps = dispatch => {
|
||||
clientY: event.clientY,
|
||||
},
|
||||
element,
|
||||
}
|
||||
};
|
||||
|
||||
const { toolType, measurementId } = measurementData
|
||||
const { toolType, measurementId } = measurementData;
|
||||
const tool = MeasurementApi.Instance.tools[toolType].find(measurement => {
|
||||
return measurement._id === measurementId
|
||||
})
|
||||
return measurement._id === measurementId;
|
||||
});
|
||||
|
||||
const options = {
|
||||
editDescriptionOnDialog: true,
|
||||
}
|
||||
};
|
||||
|
||||
getMeasurementLocationCallback(eventData, tool, options)
|
||||
getMeasurementLocationCallback(eventData, tool, options);
|
||||
},
|
||||
dispatchJumpToRowItem: (
|
||||
measurementData,
|
||||
@@ -235,40 +235,40 @@ const mapDispatchToProps = dispatch => {
|
||||
timepointManagerState,
|
||||
dispatch,
|
||||
options
|
||||
)
|
||||
);
|
||||
|
||||
actionData.viewportSpecificData.forEach(viewportSpecificData => {
|
||||
const { viewportIndex, displaySet } = viewportSpecificData
|
||||
const { viewportIndex, displaySet } = viewportSpecificData;
|
||||
|
||||
dispatch(setViewportSpecificData(viewportIndex, displaySet))
|
||||
})
|
||||
dispatch(setViewportSpecificData(viewportIndex, displaySet));
|
||||
});
|
||||
|
||||
const { toolType, measurementNumber } = measurementData
|
||||
const measurementApi = MeasurementApi.Instance
|
||||
const { toolType, measurementNumber } = measurementData;
|
||||
const measurementApi = MeasurementApi.Instance;
|
||||
|
||||
Object.keys(measurementApi.tools).forEach(toolType => {
|
||||
const measurements = measurementApi.tools[toolType]
|
||||
const measurements = measurementApi.tools[toolType];
|
||||
|
||||
measurements.forEach(measurement => {
|
||||
measurement.active = false
|
||||
})
|
||||
})
|
||||
measurement.active = false;
|
||||
});
|
||||
});
|
||||
|
||||
const measurementsToActive = measurementApi.tools[toolType].filter(
|
||||
measurement => {
|
||||
return measurement.measurementNumber === measurementNumber
|
||||
return measurement.measurementNumber === measurementNumber;
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
measurementsToActive.forEach(measurementToActive => {
|
||||
measurementToActive.active = true
|
||||
})
|
||||
measurementToActive.active = true;
|
||||
});
|
||||
|
||||
measurementApi.syncMeasurementsAndToolData()
|
||||
measurementApi.syncMeasurementsAndToolData();
|
||||
|
||||
cornerstone.getEnabledElements().forEach(enabledElement => {
|
||||
cornerstone.updateImage(enabledElement.element)
|
||||
})
|
||||
cornerstone.updateImage(enabledElement.element);
|
||||
});
|
||||
|
||||
// Needs to update viewports.layout state to set layout
|
||||
//const layout = actionData.layout;
|
||||
@@ -284,8 +284,8 @@ const mapDispatchToProps = dispatch => {
|
||||
|
||||
// (later): Needs to set some property on state.extensions.cornerstone to synchronize viewport scrolling
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
|
||||
return {
|
||||
@@ -298,37 +298,37 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
|
||||
// TODO: Tooltype should be on the level below? This should
|
||||
// provide the entire row item?
|
||||
|
||||
const viewportsState = propsFromState.viewports
|
||||
const timepointManagerState = propsFromState.timepointManager
|
||||
const viewportsState = propsFromState.viewports;
|
||||
const timepointManagerState = propsFromState.timepointManager;
|
||||
|
||||
// TODO: invertViewportTimepointsOrder should be stored in / read from user preferences
|
||||
// TODO: childToolKey should come from the measurement table when it supports child tools
|
||||
const options = {
|
||||
invertViewportTimepointsOrder: false,
|
||||
childToolKey: null,
|
||||
}
|
||||
};
|
||||
|
||||
propsFromDispatch.dispatchJumpToRowItem(
|
||||
measurementData,
|
||||
viewportsState,
|
||||
timepointManagerState,
|
||||
options
|
||||
)
|
||||
);
|
||||
},
|
||||
onRelabelClick: (event, measurementData) => {
|
||||
const viewportsState = propsFromState.viewports
|
||||
propsFromDispatch.dispatchRelabel(event, measurementData, viewportsState)
|
||||
const viewportsState = propsFromState.viewports;
|
||||
propsFromDispatch.dispatchRelabel(event, measurementData, viewportsState);
|
||||
},
|
||||
onEditDescriptionClick: (event, measurementData) => {
|
||||
const viewportsState = propsFromState.viewports
|
||||
const viewportsState = propsFromState.viewports;
|
||||
propsFromDispatch.dispatchEditDescription(
|
||||
event,
|
||||
measurementData,
|
||||
viewportsState
|
||||
)
|
||||
);
|
||||
},
|
||||
onDeleteClick: (event, measurementData) => {
|
||||
const { MeasurementHandlers } = OHIF.measurements
|
||||
const { MeasurementHandlers } = OHIF.measurements;
|
||||
|
||||
MeasurementHandlers.onRemoved({
|
||||
detail: {
|
||||
@@ -339,15 +339,15 @@ const mergeProps = (propsFromState, propsFromDispatch, ownProps) => {
|
||||
measurementNumber: measurementData.measurementNumber,
|
||||
},
|
||||
},
|
||||
})
|
||||
});
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedMeasurementTable = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps,
|
||||
mergeProps
|
||||
)(MeasurementTable)
|
||||
)(MeasurementTable);
|
||||
|
||||
export default ConnectedMeasurementTable
|
||||
export default ConnectedMeasurementTable;
|
||||
@@ -6,35 +6,35 @@ import cloneDeep from 'lodash.clonedeep';
|
||||
// - Determine in which display set is active from Redux (activeViewportIndex and layout viewportData)
|
||||
// - Pass in errors and stack loading progress from Redux
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
// If we know that the stack loading progress details have changed,
|
||||
// we can try to update the component state so that the thumbnail
|
||||
// progress bar is updated
|
||||
const stackLoadingProgressMap = state.loading.progress;
|
||||
const studiesWithLoadingData = cloneDeep(ownProps.studies);
|
||||
// If we know that the stack loading progress details have changed,
|
||||
// we can try to update the component state so that the thumbnail
|
||||
// progress bar is updated
|
||||
const stackLoadingProgressMap = state.loading.progress;
|
||||
const studiesWithLoadingData = cloneDeep(ownProps.studies);
|
||||
|
||||
studiesWithLoadingData.forEach(study => {
|
||||
study.thumbnails.forEach(data => {
|
||||
const { displaySetInstanceUid } = data
|
||||
const stackId = `StackProgress:${displaySetInstanceUid}`;
|
||||
const stackProgressData = stackLoadingProgressMap[stackId];
|
||||
studiesWithLoadingData.forEach(study => {
|
||||
study.thumbnails.forEach(data => {
|
||||
const { displaySetInstanceUid } = data;
|
||||
const stackId = `StackProgress:${displaySetInstanceUid}`;
|
||||
const stackProgressData = stackLoadingProgressMap[stackId];
|
||||
|
||||
let stackPercentComplete = 0;
|
||||
if (stackProgressData) {
|
||||
stackPercentComplete = stackProgressData.percentComplete;
|
||||
}
|
||||
let stackPercentComplete = 0;
|
||||
if (stackProgressData) {
|
||||
stackPercentComplete = stackProgressData.percentComplete;
|
||||
}
|
||||
|
||||
data.stackPercentComplete = stackPercentComplete;
|
||||
})
|
||||
data.stackPercentComplete = stackPercentComplete;
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
studies: studiesWithLoadingData
|
||||
};
|
||||
return {
|
||||
studies: studiesWithLoadingData,
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedStudyBrowser = connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
mapStateToProps,
|
||||
null
|
||||
)(StudyBrowser);
|
||||
|
||||
export default ConnectedStudyBrowser;
|
||||
@@ -1,23 +1,26 @@
|
||||
import { connect } from 'react-redux';
|
||||
import StudyLoadingMonitor from '../components/StudyLoadingMonitor.js';
|
||||
import OHIF from 'ohif-core'
|
||||
import OHIF from 'ohif-core';
|
||||
|
||||
const { setStudyLoadingProgress, clearStudyLoadingProgress } = OHIF.redux.actions;
|
||||
const {
|
||||
setStudyLoadingProgress,
|
||||
clearStudyLoadingProgress,
|
||||
} = OHIF.redux.actions;
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setStudyLoadingProgress: (progressId, progressData) => {
|
||||
dispatch(setStudyLoadingProgress(progressId, progressData))
|
||||
},
|
||||
clearStudyLoadingProgress: progressId => {
|
||||
dispatch(clearStudyLoadingProgress(progressId))
|
||||
}
|
||||
};
|
||||
return {
|
||||
setStudyLoadingProgress: (progressId, progressData) => {
|
||||
dispatch(setStudyLoadingProgress(progressId, progressData));
|
||||
},
|
||||
clearStudyLoadingProgress: progressId => {
|
||||
dispatch(clearStudyLoadingProgress(progressId));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedStudyLoadingMonitor = connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(StudyLoadingMonitor);
|
||||
|
||||
export default ConnectedStudyLoadingMonitor;
|
||||
@@ -1,34 +1,34 @@
|
||||
import { connect } from 'react-redux'
|
||||
import ToolContextMenu from './ToolContextMenu'
|
||||
import { connect } from 'react-redux';
|
||||
import ToolContextMenu from './ToolContextMenu';
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
if (!state.ui || !state.ui.contextMenu) {
|
||||
return {
|
||||
visible: false,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
const { viewportIndex } = ownProps
|
||||
const toolContextMenuData = state.ui.contextMenu[viewportIndex]
|
||||
let availableTools
|
||||
const { viewportIndex } = ownProps;
|
||||
const toolContextMenuData = state.ui.contextMenu[viewportIndex];
|
||||
let availableTools;
|
||||
|
||||
if (
|
||||
state.extensions &&
|
||||
state.extensions.cornerstone &&
|
||||
state.extensions.cornerstone.availableTools
|
||||
) {
|
||||
availableTools = state.extensions.cornerstone.availableTools
|
||||
availableTools = state.extensions.cornerstone.availableTools;
|
||||
}
|
||||
|
||||
return {
|
||||
...toolContextMenuData,
|
||||
availableTools,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedToolContextMenu = connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(ToolContextMenu)
|
||||
)(ToolContextMenu);
|
||||
|
||||
export default ConnectedToolContextMenu
|
||||
export default ConnectedToolContextMenu;
|
||||
@@ -5,34 +5,38 @@ import { setLeftSidebarOpen, setRightSidebarOpen } from '../redux/actions.js';
|
||||
const defaultPlugin = 'cornerstone';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { layout, viewportSpecificData, activeViewportIndex } = state.viewports;
|
||||
const pluginInLayout = layout.viewports[activeViewportIndex] && layout.viewports[activeViewportIndex].plugin;
|
||||
const pluginInViewportData = viewportSpecificData[activeViewportIndex] && viewportSpecificData[activeViewportIndex].plugin;
|
||||
const pluginInActiveViewport = pluginInLayout || pluginInViewportData || defaultPlugin;
|
||||
// const extensionData = state.extensions[pluginInActiveViewport];
|
||||
const { layout, viewportSpecificData, activeViewportIndex } = state.viewports;
|
||||
const pluginInLayout =
|
||||
layout.viewports[activeViewportIndex] &&
|
||||
layout.viewports[activeViewportIndex].plugin;
|
||||
const pluginInViewportData =
|
||||
viewportSpecificData[activeViewportIndex] &&
|
||||
viewportSpecificData[activeViewportIndex].plugin;
|
||||
const pluginInActiveViewport =
|
||||
pluginInLayout || pluginInViewportData || defaultPlugin;
|
||||
// const extensionData = state.extensions[pluginInActiveViewport];
|
||||
|
||||
return {
|
||||
pluginId: pluginInActiveViewport,
|
||||
leftSidebarOpen: state.ui.leftSidebarOpen,
|
||||
rightSidebarOpen: state.ui.rightSidebarOpen
|
||||
};
|
||||
return {
|
||||
pluginId: pluginInActiveViewport,
|
||||
leftSidebarOpen: state.ui.leftSidebarOpen,
|
||||
rightSidebarOpen: state.ui.rightSidebarOpen,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setLeftSidebarOpen: state => {
|
||||
dispatch(setLeftSidebarOpen(state))
|
||||
},
|
||||
setRightSidebarOpen: state => {
|
||||
dispatch(setRightSidebarOpen(state))
|
||||
}
|
||||
};
|
||||
return {
|
||||
setLeftSidebarOpen: state => {
|
||||
dispatch(setLeftSidebarOpen(state));
|
||||
},
|
||||
setRightSidebarOpen: state => {
|
||||
dispatch(setRightSidebarOpen(state));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedToolbarRow = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ToolbarRow);
|
||||
|
||||
export default ConnectedToolbarRow;
|
||||
@@ -1,29 +1,29 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { ToolbarSection } from 'react-viewerbase';
|
||||
import OHIF from 'ohif-core'
|
||||
import OHIF from 'ohif-core';
|
||||
|
||||
const { setToolActive } = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const activeButton = state.tools.buttons.find(tool => tool.active === true);
|
||||
const activeButton = state.tools.buttons.find(tool => tool.active === true);
|
||||
|
||||
return {
|
||||
buttons: state.tools.buttons,
|
||||
activeCommand: activeButton && activeButton.command
|
||||
};
|
||||
return {
|
||||
buttons: state.tools.buttons,
|
||||
activeCommand: activeButton && activeButton.command,
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setToolActive: tool => {
|
||||
dispatch(setToolActive(tool.command))
|
||||
}
|
||||
};
|
||||
return {
|
||||
setToolActive: tool => {
|
||||
dispatch(setToolActive(tool.command));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedToolbarSection = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ToolbarSection);
|
||||
|
||||
export default ConnectedToolbarSection;
|
||||
@@ -15,7 +15,7 @@ const mapStateToProps = state => {
|
||||
: {},
|
||||
hotKeysData: state.preferences[contextName]
|
||||
? state.preferences[contextName].hotKeysData
|
||||
: {}
|
||||
: {},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -36,7 +36,7 @@ const mapDispatchToProps = dispatch => {
|
||||
dispatch(setUserPreferences());
|
||||
dispatch(setUserPreferencesModalOpen(false));
|
||||
OHIF.hotkeysUtil.setHotkeys();
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ const mapDispatchToProps = dispatch => {
|
||||
},
|
||||
onMeasurementsUpdated: measurements => {
|
||||
dispatch(setMeasurements(measurements));
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
import { connect } from 'react-redux'
|
||||
import ViewerMain from './ViewerMain'
|
||||
import OHIF from 'ohif-core'
|
||||
import { connect } from 'react-redux';
|
||||
import ViewerMain from './ViewerMain';
|
||||
import OHIF from 'ohif-core';
|
||||
|
||||
const {
|
||||
setViewportSpecificData,
|
||||
clearViewportSpecificData,
|
||||
setToolActive,
|
||||
setActiveViewportSpecificData,
|
||||
} = OHIF.redux.actions
|
||||
} = OHIF.redux.actions;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const { activeViewportIndex, layout, viewportSpecificData } = state.viewports
|
||||
const { activeViewportIndex, layout, viewportSpecificData } = state.viewports;
|
||||
|
||||
return {
|
||||
activeViewportIndex,
|
||||
layout,
|
||||
viewportSpecificData,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
setViewportSpecificData: (viewportIndex, data) => {
|
||||
dispatch(setViewportSpecificData(viewportIndex, data))
|
||||
dispatch(setViewportSpecificData(viewportIndex, data));
|
||||
},
|
||||
clearViewportSpecificData: () => {
|
||||
dispatch(clearViewportSpecificData())
|
||||
dispatch(clearViewportSpecificData());
|
||||
},
|
||||
setToolActive: tool => {
|
||||
dispatch(setToolActive(tool))
|
||||
dispatch(setToolActive(tool));
|
||||
},
|
||||
setActiveViewportSpecificData: viewport => {
|
||||
dispatch(setActiveViewportSpecificData(viewport))
|
||||
dispatch(setActiveViewportSpecificData(viewport));
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedViewerMain = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ViewerMain)
|
||||
)(ViewerMain);
|
||||
|
||||
export default ConnectedViewerMain
|
||||
export default ConnectedViewerMain;
|
||||
@@ -1,19 +1,19 @@
|
||||
import { connect } from 'react-redux'
|
||||
import ViewerRetrieveStudyData from './ViewerRetrieveStudyData.js'
|
||||
import { connect } from 'react-redux';
|
||||
import ViewerRetrieveStudyData from './ViewerRetrieveStudyData.js';
|
||||
|
||||
const isActive = a => a.active === true
|
||||
const isActive = a => a.active === true;
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const activeServer = state.servers.servers.find(isActive)
|
||||
const activeServer = state.servers.servers.find(isActive);
|
||||
|
||||
return {
|
||||
server: activeServer,
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
const ConnectedViewerRetrieveStudyData = connect(
|
||||
mapStateToProps,
|
||||
null
|
||||
)(ViewerRetrieveStudyData)
|
||||
)(ViewerRetrieveStudyData);
|
||||
|
||||
export default ConnectedViewerRetrieveStudyData
|
||||
export default ConnectedViewerRetrieveStudyData;
|
||||
@@ -1,38 +1,38 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import ConnectedStudyBrowser from './ConnectedStudyBrowser.js'
|
||||
import ConnectedViewerMain from './ConnectedViewerMain.js'
|
||||
import ConnectedMeasurementTable from './ConnectedMeasurementTable'
|
||||
import './FlexboxLayout.css'
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import ConnectedStudyBrowser from './ConnectedStudyBrowser.js';
|
||||
import ConnectedViewerMain from './ConnectedViewerMain.js';
|
||||
import ConnectedMeasurementTable from './ConnectedMeasurementTable';
|
||||
import './FlexboxLayout.css';
|
||||
|
||||
class FlexboxLayout extends Component {
|
||||
static propTypes = {
|
||||
studies: PropTypes.array.isRequired,
|
||||
leftSidebarOpen: PropTypes.bool.isRequired,
|
||||
rightSidebarOpen: PropTypes.bool.isRequired,
|
||||
}
|
||||
};
|
||||
|
||||
state = {
|
||||
studiesForBrowser: [],
|
||||
}
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
const studiesForBrowser = this.getStudiesForBrowser()
|
||||
const studiesForBrowser = this.getStudiesForBrowser();
|
||||
|
||||
this.setState({
|
||||
studiesForBrowser,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
getStudiesForBrowser = () => {
|
||||
const { studies } = this.props
|
||||
const { studies } = this.props;
|
||||
|
||||
// TODO[react]:
|
||||
// - Add sorting of display sets
|
||||
// - Add useMiddleSeriesInstanceAsThumbnail
|
||||
// - Add showStackLoadingProgressBar option
|
||||
return studies.map(study => {
|
||||
const { studyInstanceUid } = study
|
||||
const { studyInstanceUid } = study;
|
||||
|
||||
const thumbnails = study.displaySets.map(displaySet => {
|
||||
const {
|
||||
@@ -41,12 +41,12 @@ class FlexboxLayout extends Component {
|
||||
seriesNumber,
|
||||
instanceNumber,
|
||||
numImageFrames,
|
||||
} = displaySet
|
||||
} = displaySet;
|
||||
|
||||
let imageId
|
||||
let imageId;
|
||||
|
||||
if (displaySet.images && displaySet.images.length) {
|
||||
imageId = displaySet.images[0].getImageId()
|
||||
imageId = displaySet.images[0].getImageId();
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -56,24 +56,24 @@ class FlexboxLayout extends Component {
|
||||
seriesNumber,
|
||||
instanceNumber,
|
||||
numImageFrames,
|
||||
}
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
return {
|
||||
studyInstanceUid,
|
||||
thumbnails,
|
||||
}
|
||||
})
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
let mainContentClassName = 'main-content'
|
||||
let mainContentClassName = 'main-content';
|
||||
if (this.props.leftSidebarOpen) {
|
||||
mainContentClassName += ' sidebar-left-open'
|
||||
mainContentClassName += ' sidebar-left-open';
|
||||
}
|
||||
|
||||
if (this.props.rightSidebarOpen) {
|
||||
mainContentClassName += ' sidebar-right-open'
|
||||
mainContentClassName += ' sidebar-right-open';
|
||||
}
|
||||
|
||||
// TODO[react]: Make ConnectedMeasurementTable extension with state.timepointManager
|
||||
@@ -101,8 +101,8 @@ class FlexboxLayout extends Component {
|
||||
<ConnectedMeasurementTable />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default FlexboxLayout
|
||||
export default FlexboxLayout;
|
||||
@@ -1,23 +1,23 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import LabellingManager from '../components/Labelling/LabellingManager'
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import LabellingManager from '../components/Labelling/LabellingManager';
|
||||
|
||||
class LabellingOverlay extends Component {
|
||||
static propTypes = {
|
||||
visible: PropTypes.bool.isRequired,
|
||||
}
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
visible: false,
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
if (!this.props.visible) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return <LabellingManager {...this.props} />
|
||||
return <LabellingManager {...this.props} />;
|
||||
}
|
||||
}
|
||||
|
||||
export default LabellingOverlay
|
||||
export default LabellingOverlay;
|
||||
@@ -5,7 +5,7 @@ import './PluginSwitch.css';
|
||||
|
||||
class PluginSwitch extends Component {
|
||||
static propTypes = {
|
||||
buttons: PropTypes.array
|
||||
buttons: PropTypes.array,
|
||||
};
|
||||
|
||||
static defaultProps = {};
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import React, { Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import cornerstone from 'cornerstone-core'
|
||||
import cornerstoneTools from 'cornerstone-tools'
|
||||
import getMeasurementLocationCallback from '../lib/getMeasurementLocationCallback'
|
||||
import React, { Component } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cornerstone from 'cornerstone-core';
|
||||
import cornerstoneTools from 'cornerstone-tools';
|
||||
import getMeasurementLocationCallback from '../lib/getMeasurementLocationCallback';
|
||||
|
||||
import './ToolContextMenu.css'
|
||||
import './ToolContextMenu.css';
|
||||
|
||||
const toolTypes = [
|
||||
'Angle',
|
||||
@@ -14,87 +14,87 @@ const toolTypes = [
|
||||
'EllipticalRoi',
|
||||
'CircleRoi',
|
||||
'RectangleRoi',
|
||||
]
|
||||
];
|
||||
|
||||
let defaultDropdownItems = [
|
||||
{
|
||||
actionType: 'Delete',
|
||||
action: ({ nearbyToolData, eventData }) => {
|
||||
const element = eventData.element
|
||||
const element = eventData.element;
|
||||
|
||||
cornerstoneTools.removeToolState(
|
||||
element,
|
||||
nearbyToolData.toolType,
|
||||
nearbyToolData.tool
|
||||
)
|
||||
cornerstone.updateImage(element)
|
||||
);
|
||||
cornerstone.updateImage(element);
|
||||
},
|
||||
},
|
||||
{
|
||||
actionType: 'setLabel',
|
||||
action: ({ nearbyToolData, eventData }) => {
|
||||
const { tool } = nearbyToolData
|
||||
const { tool } = nearbyToolData;
|
||||
|
||||
const options = {
|
||||
skipAddLabelButton: true,
|
||||
editLocation: true,
|
||||
}
|
||||
};
|
||||
|
||||
getMeasurementLocationCallback(eventData, tool, options)
|
||||
getMeasurementLocationCallback(eventData, tool, options);
|
||||
},
|
||||
},
|
||||
{
|
||||
actionType: 'setDescription',
|
||||
action: ({ nearbyToolData, eventData }) => {
|
||||
const { tool } = nearbyToolData
|
||||
const { tool } = nearbyToolData;
|
||||
|
||||
const options = {
|
||||
editDescriptionOnDialog: true,
|
||||
}
|
||||
};
|
||||
|
||||
getMeasurementLocationCallback(eventData, tool, options)
|
||||
getMeasurementLocationCallback(eventData, tool, options);
|
||||
},
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
function getNearbyToolData(element, coords, toolTypes) {
|
||||
const nearbyTool = {}
|
||||
let pointNearTool = false
|
||||
const nearbyTool = {};
|
||||
let pointNearTool = false;
|
||||
|
||||
toolTypes.forEach(toolType => {
|
||||
const toolData = cornerstoneTools.getToolState(element, toolType)
|
||||
const toolData = cornerstoneTools.getToolState(element, toolType);
|
||||
if (!toolData) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
toolData.data.forEach(function(data, index) {
|
||||
// TODO: Fix this, it's ugly
|
||||
let toolInterface = cornerstoneTools.getToolForElement(element, toolType)
|
||||
let toolInterface = cornerstoneTools.getToolForElement(element, toolType);
|
||||
if (!toolInterface) {
|
||||
toolInterface = cornerstoneTools.getToolForElement(
|
||||
element,
|
||||
`${toolType}Tool`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!toolInterface) {
|
||||
throw new Error('Tool not found.')
|
||||
throw new Error('Tool not found.');
|
||||
}
|
||||
|
||||
if (toolInterface.pointNearTool(element, data, coords)) {
|
||||
pointNearTool = true
|
||||
nearbyTool.tool = data
|
||||
nearbyTool.index = index
|
||||
nearbyTool.toolType = toolType
|
||||
pointNearTool = true;
|
||||
nearbyTool.tool = data;
|
||||
nearbyTool.index = index;
|
||||
nearbyTool.toolType = toolType;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
if (pointNearTool) {
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
return pointNearTool ? nearbyTool : undefined
|
||||
return pointNearTool ? nearbyTool : undefined;
|
||||
}
|
||||
|
||||
function getDropdownItems(eventData, isTouchEvent = false, availableTools) {
|
||||
@@ -103,7 +103,7 @@ function getDropdownItems(eventData, isTouchEvent = false, availableTools) {
|
||||
eventData.currentPoints.canvas,
|
||||
toolTypes,
|
||||
availableTools
|
||||
)
|
||||
);
|
||||
|
||||
// Annotate tools for touch events already have a press handle to edit it, has a better UX for deleting it
|
||||
if (
|
||||
@@ -111,36 +111,36 @@ function getDropdownItems(eventData, isTouchEvent = false, availableTools) {
|
||||
nearbyToolData &&
|
||||
nearbyToolData.toolType === 'arrowAnnotate'
|
||||
) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
let dropdownItems = []
|
||||
let dropdownItems = [];
|
||||
if (nearbyToolData) {
|
||||
defaultDropdownItems.forEach(function(item) {
|
||||
item.params = {
|
||||
eventData,
|
||||
nearbyToolData,
|
||||
}
|
||||
};
|
||||
|
||||
if (item.actionType === 'Delete') {
|
||||
item.text = 'Delete measurement'
|
||||
item.text = 'Delete measurement';
|
||||
}
|
||||
|
||||
if (item.actionType === 'setLabel') {
|
||||
item.text = 'Relabel'
|
||||
item.text = 'Relabel';
|
||||
}
|
||||
|
||||
if (item.actionType === 'setDescription') {
|
||||
item.text = `${
|
||||
nearbyToolData.tool.description ? 'Edit' : 'Add'
|
||||
} Description`
|
||||
} Description`;
|
||||
}
|
||||
|
||||
dropdownItems.push(item)
|
||||
})
|
||||
dropdownItems.push(item);
|
||||
});
|
||||
}
|
||||
|
||||
return dropdownItems
|
||||
return dropdownItems;
|
||||
}
|
||||
|
||||
class ToolContextMenu extends Component {
|
||||
@@ -150,43 +150,43 @@ class ToolContextMenu extends Component {
|
||||
onClose: PropTypes.func,
|
||||
availableTools: PropTypes.array,
|
||||
visible: PropTypes.bool.isRequired,
|
||||
}
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
visible: true,
|
||||
isTouchEvent: false,
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
super(props);
|
||||
|
||||
this.mainElement = React.createRef()
|
||||
this.mainElement = React.createRef();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.props.eventData) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
const { isTouchEvent, eventData, availableTools } = this.props
|
||||
const { isTouchEvent, eventData, availableTools } = this.props;
|
||||
const dropdownItems = getDropdownItems(
|
||||
eventData,
|
||||
isTouchEvent,
|
||||
availableTools
|
||||
)
|
||||
);
|
||||
|
||||
// Skip if there is no dropdown item
|
||||
if (!dropdownItems.length) {
|
||||
return ''
|
||||
return '';
|
||||
}
|
||||
|
||||
const dropdownComponents = dropdownItems.map(item => {
|
||||
const itemOnClick = event => {
|
||||
item.action(item.params)
|
||||
item.action(item.params);
|
||||
if (this.props.onClose) {
|
||||
this.props.onClose()
|
||||
this.props.onClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<li key={item.actionType}>
|
||||
@@ -194,32 +194,32 @@ class ToolContextMenu extends Component {
|
||||
<span key={item.actionType}>{item.text}</span>
|
||||
</button>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
const position = {
|
||||
top: `${eventData.currentPoints.canvas.y}px`,
|
||||
left: `${eventData.currentPoints.canvas.x}px`,
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="ToolContextMenu" style={position} ref={this.mainElement}>
|
||||
<ul className="bounded">{dropdownComponents}</ul>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
componentDidMount = () => {
|
||||
if (this.mainElement.current) {
|
||||
this.updateElementPosition()
|
||||
this.updateElementPosition();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
componentDidUpdate = () => {
|
||||
if (this.mainElement.current) {
|
||||
this.updateElementPosition()
|
||||
this.updateElementPosition();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
updateElementPosition = () => {
|
||||
const {
|
||||
@@ -228,25 +228,26 @@ class ToolContextMenu extends Component {
|
||||
offsetHeight,
|
||||
offsetWidth,
|
||||
offsetLeft,
|
||||
} = this.mainElement.current
|
||||
} = this.mainElement.current;
|
||||
|
||||
const { eventData } = this.props
|
||||
const { eventData } = this.props;
|
||||
|
||||
if (offsetTop + offsetHeight > offsetParent.offsetHeight) {
|
||||
const offBoundPixels =
|
||||
offsetTop + offsetHeight - offsetParent.offsetHeight
|
||||
const top = eventData.currentPoints.canvas.y - offBoundPixels
|
||||
offsetTop + offsetHeight - offsetParent.offsetHeight;
|
||||
const top = eventData.currentPoints.canvas.y - offBoundPixels;
|
||||
|
||||
this.mainElement.current.style.top = `${top > 0 ? top : 0}px`
|
||||
this.mainElement.current.style.top = `${top > 0 ? top : 0}px`;
|
||||
}
|
||||
|
||||
if (offsetLeft + offsetWidth > offsetParent.offsetWidth) {
|
||||
const offBoundPixels = offsetLeft + offsetWidth - offsetParent.offsetWidth
|
||||
const left = eventData.currentPoints.canvas.x - offBoundPixels
|
||||
const offBoundPixels =
|
||||
offsetLeft + offsetWidth - offsetParent.offsetWidth;
|
||||
const left = eventData.currentPoints.canvas.x - offBoundPixels;
|
||||
|
||||
this.mainElement.current.style.left = `${left > 0 ? left : 0}px`
|
||||
this.mainElement.current.style.left = `${left > 0 ? left : 0}px`;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default ToolContextMenu
|
||||
export default ToolContextMenu;
|
||||
@@ -52,7 +52,7 @@ class Viewer extends Component {
|
||||
studies: PropTypes.array,
|
||||
studyInstanceUids: PropTypes.array,
|
||||
onTimepointsUpdated: PropTypes.func,
|
||||
onMeasurementsUpdated: PropTypes.func
|
||||
onMeasurementsUpdated: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
@@ -60,8 +60,8 @@ class Viewer extends Component {
|
||||
OHIF.measurements.MeasurementApi.setConfiguration({
|
||||
dataExchange: {
|
||||
retrieve: this.retrieveMeasurements,
|
||||
store: this.storeMeasurements
|
||||
}
|
||||
store: this.storeMeasurements,
|
||||
},
|
||||
});
|
||||
|
||||
OHIF.measurements.TimepointApi.setConfiguration({
|
||||
@@ -70,8 +70,8 @@ class Viewer extends Component {
|
||||
store: this.storeTimepoints,
|
||||
remove: this.removeTimepoint,
|
||||
update: this.updateTimepoint,
|
||||
disassociate: this.disassociateStudy
|
||||
}
|
||||
disassociate: this.disassociateStudy,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -115,8 +115,8 @@ class Viewer extends Component {
|
||||
patientId: filter.patientId,
|
||||
earliestDate,
|
||||
latestDate,
|
||||
isLocked: false
|
||||
}
|
||||
isLocked: false,
|
||||
},
|
||||
]);
|
||||
};
|
||||
|
||||
@@ -158,11 +158,11 @@ class Viewer extends Component {
|
||||
const currentTimepointId = 'TimepointId';
|
||||
|
||||
const timepointApi = new TimepointApi(currentTimepointId, {
|
||||
onTimepointsUpdated: this.onTimepointsUpdated
|
||||
onTimepointsUpdated: this.onTimepointsUpdated,
|
||||
});
|
||||
|
||||
const measurementApi = new MeasurementApi(timepointApi, {
|
||||
onMeasurementsUpdated: this.onMeasurementsUpdated
|
||||
onMeasurementsUpdated: this.onMeasurementsUpdated,
|
||||
});
|
||||
|
||||
const patientId = studies[0] && studies[0].patientId;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Component } from 'react'
|
||||
import React from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { OHIF } from 'ohif-core'
|
||||
import ConnectedLayoutManager from './ConnectedLayoutManager.js'
|
||||
import './ViewerMain.css'
|
||||
import { Component } from 'react';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { OHIF } from 'ohif-core';
|
||||
import ConnectedLayoutManager from './ConnectedLayoutManager.js';
|
||||
import './ViewerMain.css';
|
||||
|
||||
class ViewerMain extends Component {
|
||||
static propTypes = {
|
||||
@@ -12,10 +12,10 @@ class ViewerMain extends Component {
|
||||
clearViewportSpecificData: PropTypes.func.isRequired,
|
||||
setToolActive: PropTypes.func.isRequired,
|
||||
setActiveViewportSpecificData: PropTypes.func.isRequired,
|
||||
}
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
super(props);
|
||||
|
||||
// Initialize hotkeys
|
||||
new OHIF.HotkeysUtil('viewer', {
|
||||
@@ -23,39 +23,41 @@ class ViewerMain extends Component {
|
||||
clearViewportSpecificData: props.clearViewportSpecificData,
|
||||
setToolActive: props.setToolActive,
|
||||
setActiveViewportSpecificData: props.setActiveViewportSpecificData,
|
||||
})
|
||||
});
|
||||
|
||||
this.state = {
|
||||
displaySets: [],
|
||||
}
|
||||
};
|
||||
|
||||
this.cachedViewportData = {};
|
||||
}
|
||||
|
||||
getDisplaySets(studies) {
|
||||
const displaySets = []
|
||||
const displaySets = [];
|
||||
studies.forEach(study => {
|
||||
study.displaySets.forEach(dSet => {
|
||||
if (!dSet.plugin) {
|
||||
dSet.plugin = 'cornerstone'
|
||||
dSet.plugin = 'cornerstone';
|
||||
}
|
||||
displaySets.push(dSet)
|
||||
})
|
||||
})
|
||||
displaySets.push(dSet);
|
||||
});
|
||||
});
|
||||
|
||||
return displaySets
|
||||
return displaySets;
|
||||
}
|
||||
|
||||
findDisplaySet(studies, studyInstanceUid, displaySetInstanceUid) {
|
||||
const study = studies.find(study => {
|
||||
return study.studyInstanceUid === studyInstanceUid
|
||||
})
|
||||
return study.studyInstanceUid === studyInstanceUid;
|
||||
});
|
||||
|
||||
if (!study) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
return study.displaySets.find(displaySet => {
|
||||
return displaySet.displaySetInstanceUid === displaySetInstanceUid
|
||||
})
|
||||
return displaySet.displaySetInstanceUid === displaySetInstanceUid;
|
||||
});
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
@@ -63,50 +65,68 @@ class ViewerMain extends Component {
|
||||
//window.addEventListener('beforeunload', unloadHandlers.beforeUnload);
|
||||
|
||||
// Get all the display sets for the viewer studies
|
||||
const displaySets = this.getDisplaySets(this.props.studies)
|
||||
const displaySets = this.getDisplaySets(this.props.studies);
|
||||
|
||||
this.setState({
|
||||
displaySets,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
getViewportData = () => {
|
||||
const viewportData = []
|
||||
const { layout, viewportSpecificData } = this.props
|
||||
const viewportData = [];
|
||||
const { layout, viewportSpecificData } = this.props;
|
||||
|
||||
for (
|
||||
let viewportIndex = 0;
|
||||
viewportIndex < layout.viewports.length;
|
||||
viewportIndex++
|
||||
) {
|
||||
let displaySet = viewportSpecificData[viewportIndex]
|
||||
let displaySet = viewportSpecificData[viewportIndex];
|
||||
|
||||
// If the viewport is empty, get one available in study
|
||||
if (!displaySet || !displaySet.displaySetInstanceUid) {
|
||||
const { displaySets } = this.state
|
||||
// Use the cached display set in viewport if the new one is empty
|
||||
if (displaySet && !displaySet.displaySetInstanceUid) {
|
||||
displaySet = this.cachedViewportData[viewportIndex];
|
||||
}
|
||||
|
||||
if (
|
||||
displaySet &&
|
||||
displaySet.studyInstanceUid &&
|
||||
displaySet.displaySetInstanceUid
|
||||
) {
|
||||
// Get missing fields from original display set
|
||||
const originalDisplaySet = this.findDisplaySet(
|
||||
this.props.studies,
|
||||
displaySet.studyInstanceUid,
|
||||
displaySet.displaySetInstanceUid
|
||||
);
|
||||
viewportData.push(Object.assign({}, originalDisplaySet, displaySet));
|
||||
} else {
|
||||
// If the viewport is empty, get one available in study
|
||||
const { displaySets } = this.state;
|
||||
displaySet = displaySets.find(
|
||||
ds =>
|
||||
!viewportData.some(
|
||||
v => v.displaySetInstanceUid === ds.displaySetInstanceUid
|
||||
)
|
||||
)
|
||||
);
|
||||
viewportData.push(Object.assign({}, displaySet));
|
||||
}
|
||||
|
||||
viewportData.push(displaySet)
|
||||
}
|
||||
|
||||
return viewportData
|
||||
}
|
||||
this.cachedViewportData = viewportData;
|
||||
|
||||
return viewportData;
|
||||
};
|
||||
|
||||
setViewportData = ({ viewportIndex, item }) => {
|
||||
const displaySet = this.findDisplaySet(
|
||||
this.props.studies,
|
||||
item.studyInstanceUid,
|
||||
item.displaySetInstanceUid
|
||||
)
|
||||
);
|
||||
|
||||
this.props.setViewportSpecificData(viewportIndex, displaySet)
|
||||
}
|
||||
this.props.setViewportSpecificData(viewportIndex, displaySet);
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
@@ -117,15 +137,15 @@ class ViewerMain extends Component {
|
||||
setViewportData={this.setViewportData}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
// Clear the entire viewport specific data
|
||||
const { viewportSpecificData } = this.props
|
||||
const { viewportSpecificData } = this.props;
|
||||
Object.keys(viewportSpecificData).forEach(viewportIndex => {
|
||||
this.props.clearViewportSpecificData(viewportIndex)
|
||||
})
|
||||
this.props.clearViewportSpecificData(viewportIndex);
|
||||
});
|
||||
|
||||
// Remove beforeUnload event handler...
|
||||
//window.removeEventListener('beforeunload', unloadHandlers.beforeUnload);
|
||||
@@ -144,4 +164,4 @@ class ViewerMain extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default ViewerMain
|
||||
export default ViewerMain;
|
||||
@@ -9,12 +9,12 @@ class ViewerRetrieveStudyData extends Component {
|
||||
static propTypes = {
|
||||
studyInstanceUids: PropTypes.array.isRequired,
|
||||
seriesInstanceUids: PropTypes.array,
|
||||
server: PropTypes.object
|
||||
server: PropTypes.object,
|
||||
};
|
||||
|
||||
state = {
|
||||
studies: null,
|
||||
error: null
|
||||
error: null,
|
||||
};
|
||||
|
||||
componentDidMount() {
|
||||
@@ -33,12 +33,12 @@ class ViewerRetrieveStudyData extends Component {
|
||||
const updatedStudies = createDisplaySets(studies);
|
||||
|
||||
this.setState({
|
||||
studies: updatedStudies
|
||||
studies: updatedStudies,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({
|
||||
error: true
|
||||
error: true,
|
||||
});
|
||||
|
||||
throw new Error(error);
|
||||
|
||||
Reference in new issue
Block a user