Compare commits
16
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
855020d730 | ||
|
|
8503cbce4e | ||
|
|
c8667fb2d6 | ||
|
|
674ca9f96f | ||
|
|
7a4b97b4e8 | ||
|
|
c79c0c301d | ||
|
|
ff5060f276 | ||
|
|
dafb26b34b | ||
|
|
c4f9d5e750 | ||
|
|
cf40a8388c | ||
|
|
d596ab5c3d | ||
|
|
72198eee7d | ||
|
|
057f68a9b4 | ||
|
|
034ca64d6b | ||
|
|
4a0901aee9 | ||
|
|
d0ec9cf0e0 |
No files matched your search
@@ -175,7 +175,7 @@ jobs:
|
||||
- run:
|
||||
name: 'Build Demo Site'
|
||||
command: yarn run build:demo
|
||||
no_output_timeout: 30m
|
||||
no_output_timeout: 45m
|
||||
- run:
|
||||
name: 'Upload SourceMaps, Send Deploy Notification'
|
||||
command: |
|
||||
|
||||
+3
-1
@@ -8,11 +8,13 @@ coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 0.10%
|
||||
threshold: 0.5%
|
||||
core:
|
||||
flags: core
|
||||
threshold: 0.5%
|
||||
viewer:
|
||||
flags: viewer
|
||||
threshold: 0.5%
|
||||
patch: off
|
||||
flags:
|
||||
core:
|
||||
|
||||
@@ -132,7 +132,7 @@ deployment recipe.
|
||||
### Requirements
|
||||
|
||||
- [Yarn 1.17.3+](https://yarnpkg.com/en/docs/install)
|
||||
- [Node 8+](https://nodejs.org/en/)
|
||||
- [Node 10+](https://nodejs.org/en/)
|
||||
- Yarn Workspaces should be enabled on your machine:
|
||||
- `yarn config set workspaces-experimental true`
|
||||
|
||||
|
||||
@@ -3,6 +3,44 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [0.51.1](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.51.0...@ohif/extension-vtk@0.51.1) (2019-10-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **rotate:** Use new MPR rotate in react-vtkjs-viewport 0.1.2 ([#964](https://github.com/OHIF/Viewers/issues/964)) ([8503cbc](https://github.com/OHIF/Viewers/commit/8503cbc))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [0.51.0](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.23...@ohif/extension-vtk@0.51.0) (2019-10-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 MPR UI improvements. Added MinIP, AvgIP, slab thickness slider and mode toggle ([#947](https://github.com/OHIF/Viewers/issues/947)) ([c79c0c3](https://github.com/OHIF/Viewers/commit/c79c0c3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.23](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.22...@ohif/extension-vtk@0.50.23) (2019-10-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.22](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.21...@ohif/extension-vtk@0.50.22) (2019-09-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.50.21](https://github.com/OHIF/Viewers/compare/@ohif/extension-vtk@0.50.20...@ohif/extension-vtk@0.50.21) (2019-09-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/extension-vtk
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/extension-vtk",
|
||||
"version": "0.50.21",
|
||||
"version": "0.51.1",
|
||||
"description": "OHIF extension for VTK.js",
|
||||
"author": "OHIF",
|
||||
"license": "MIT",
|
||||
@@ -48,11 +48,11 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"react-vtkjs-viewport": "0.1.0"
|
||||
"react-vtkjs-viewport": "0.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ohif/core": "^1.0.0",
|
||||
"@ohif/ui": "^0.51.2",
|
||||
"@ohif/core": "^1.0.1",
|
||||
"@ohif/ui": "^0.52.0",
|
||||
"cornerstone-tools": "^4.0.9",
|
||||
"cornerstone-wado-image-loader": "^3.0.0",
|
||||
"dcmjs": "^0.6.1",
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
vtkInteractorStyleMPRCrosshairs,
|
||||
vtkInteractorStyleMPRWindowLevel,
|
||||
vtkInteractorStyleMPRSlice,
|
||||
vtkInteractorStyleMPRRotate,
|
||||
vtkSVGCrosshairsWidget,
|
||||
vtkSVGWidgetManager,
|
||||
} from 'react-vtkjs-viewport';
|
||||
@@ -18,6 +19,7 @@ const { BlendMode } = Constants;
|
||||
// TODO: Put this somewhere else
|
||||
let apis = {};
|
||||
let currentSlabThickness = 0.1;
|
||||
let defaultSlabThickness = 0.1;
|
||||
|
||||
function getCrosshairCallbackForIndex(index) {
|
||||
return ({ worldPos }) => {
|
||||
@@ -98,7 +100,7 @@ function _setView(api, sliceNormal, viewUp) {
|
||||
const camera = renderer.getActiveCamera();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
istyle.setSliceNormal(...sliceNormal);
|
||||
camera.setViewUp(...viewUp);
|
||||
istyle.setViewUp(...viewUp);
|
||||
|
||||
renderWindow.render();
|
||||
}
|
||||
@@ -109,14 +111,15 @@ function switchMPRInteractors(api, istyle) {
|
||||
const camera = renderer.getActiveCamera();
|
||||
const currentIStyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
let currentNormal;
|
||||
if (currentIStyle.getSliceNormal && istyle.getSliceNormal) {
|
||||
currentNormal = currentIStyle.getSliceNormal();
|
||||
let currentViewport;
|
||||
if (currentIStyle.getViewport && istyle.getViewport) {
|
||||
currentViewport = currentIStyle.getViewport();
|
||||
}
|
||||
|
||||
let currentSlabThickness;
|
||||
if (currentIStyle.getSlabThickness && istyle.getSlabThickness) {
|
||||
currentSlabThickness = currentIStyle.getSlabThickness();
|
||||
defaultSlabThickness = currentSlabThickness;
|
||||
}
|
||||
|
||||
renderWindow.getInteractor().setInteractorStyle(istyle);
|
||||
@@ -124,11 +127,11 @@ function switchMPRInteractors(api, istyle) {
|
||||
// TODO: Not sure why this is required the second time this function is called
|
||||
istyle.setInteractor(renderWindow.getInteractor());
|
||||
|
||||
if (istyle.getVolumeMapper() !== api.volumes[0]) {
|
||||
if (currentNormal) {
|
||||
istyle.setSliceNormal(currentNormal);
|
||||
}
|
||||
if (currentViewport) {
|
||||
istyle.setViewport(currentViewport);
|
||||
}
|
||||
|
||||
if (istyle.getVolumeMapper() !== api.volumes[0]) {
|
||||
if (currentSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
}
|
||||
@@ -161,7 +164,7 @@ const actions = {
|
||||
},
|
||||
enableRotateTool: () => {
|
||||
apis.forEach(api => {
|
||||
const istyle = vtkInteractorStyleMPRSlice.newInstance();
|
||||
const istyle = vtkInteractorStyleMPRRotate.newInstance();
|
||||
|
||||
switchMPRInteractors(api, istyle);
|
||||
});
|
||||
@@ -182,7 +185,7 @@ const actions = {
|
||||
switchMPRInteractors(api, istyle);
|
||||
});
|
||||
},
|
||||
setSlabThickness: slabThickness => {
|
||||
setSlabThickness: ({ slabThickness }) => {
|
||||
currentSlabThickness = slabThickness;
|
||||
|
||||
apis.forEach(api => {
|
||||
@@ -191,15 +194,6 @@ const actions = {
|
||||
|
||||
if (istyle.setSlabThickness) {
|
||||
istyle.setSlabThickness(currentSlabThickness);
|
||||
|
||||
// TODO: Do this inside the interactors in a setSlabThickness function instead
|
||||
const renderer = api.genericRenderWindow.getRenderer();
|
||||
const camera = renderer.getActiveCamera();
|
||||
const dist = camera.getDistance();
|
||||
const near = dist - currentSlabThickness / 2;
|
||||
const far = dist + currentSlabThickness / 2;
|
||||
|
||||
camera.setClippingRange(near, far);
|
||||
}
|
||||
|
||||
renderWindow.render();
|
||||
@@ -220,6 +214,32 @@ const actions = {
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
setBlendModeToComposite: () => {
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const istyle = renderWindow.getInteractor().getInteractorStyle();
|
||||
|
||||
const mapper = api.volumes[0].getMapper();
|
||||
if (mapper.setBlendModeToComposite) {
|
||||
mapper.setBlendModeToComposite();
|
||||
}
|
||||
|
||||
if (istyle.setSlabThickness) {
|
||||
istyle.setSlabThickness(defaultSlabThickness);
|
||||
}
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
setBlendModeToMaximumIntensity: () => {
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
const mapper = api.volumes[0].getMapper();
|
||||
if (mapper.setBlendModeToMaximumIntensity) {
|
||||
mapper.setBlendModeToMaximumIntensity();
|
||||
}
|
||||
renderWindow.render();
|
||||
});
|
||||
},
|
||||
setBlendMode: ({ blendMode }) => {
|
||||
apis.forEach(api => {
|
||||
const renderWindow = api.genericRenderWindow.getRenderWindow();
|
||||
@@ -284,18 +304,18 @@ const actions = {
|
||||
case 0:
|
||||
//Axial
|
||||
istyle.setSliceNormal(0, 0, 1);
|
||||
camera.setViewUp(0, -1, 0);
|
||||
istyle.setViewUp(0, -1, 0);
|
||||
|
||||
break;
|
||||
case 1:
|
||||
// sagittal
|
||||
istyle.setSliceNormal(1, 0, 0);
|
||||
camera.setViewUp(0, 0, 1);
|
||||
istyle.setViewUp(0, 0, 1);
|
||||
break;
|
||||
case 2:
|
||||
// Coronal
|
||||
istyle.setSliceNormal(0, 1, 0);
|
||||
camera.setViewUp(0, 0, 1);
|
||||
istyle.setViewUp(0, 0, 1);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -338,12 +358,12 @@ const definitions = {
|
||||
options: {},
|
||||
},
|
||||
setBlendModeToComposite: {
|
||||
commandFn: actions.setBlendMode,
|
||||
commandFn: actions.setBlendModeToComposite,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.COMPOSITE_BLEND },
|
||||
},
|
||||
setBlendModeToMaximumIntensity: {
|
||||
commandFn: actions.setBlendMode,
|
||||
commandFn: actions.setBlendModeToMaximumIntensity,
|
||||
storeContexts: [],
|
||||
options: { blendMode: BlendMode.MAXIMUM_INTENSITY_BLEND },
|
||||
},
|
||||
|
||||
@@ -0,0 +1,207 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { Range, Checkbox, Select } from '@ohif/ui';
|
||||
|
||||
import './slab-thickness-toolbar-button.styl';
|
||||
|
||||
const SLIDER = {
|
||||
MIN: 0.1,
|
||||
MAX: 1000,
|
||||
STEP: 0.1,
|
||||
};
|
||||
|
||||
const ToolbarLabel = props => {
|
||||
const { label } = props;
|
||||
return <div className="toolbar-button-label">{label}</div>;
|
||||
};
|
||||
|
||||
const ToolbarSlider = props => {
|
||||
const { value, min, max, onChange } = props;
|
||||
return (
|
||||
<div className="toolbar-slider-container">
|
||||
<label htmlFor="toolbar-slider">{value}mm</label>
|
||||
<Range
|
||||
value={value}
|
||||
min={min}
|
||||
max={max}
|
||||
step={SLIDER.STEP}
|
||||
onChange={onChange}
|
||||
id="toolbar-slider"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const _getSelectOptions = button => {
|
||||
return button.operationButtons.map(button => {
|
||||
return {
|
||||
key: button.label,
|
||||
value: button.id,
|
||||
};
|
||||
});
|
||||
};
|
||||
|
||||
const _getClassNames = (isActive, className) => {
|
||||
return classnames('toolbar-button', 'slab-thickness', className, {
|
||||
active: isActive,
|
||||
});
|
||||
};
|
||||
|
||||
const _applySlabThickness = (
|
||||
value,
|
||||
modeChecked,
|
||||
toolbarClickCallback,
|
||||
button
|
||||
) => {
|
||||
if (!modeChecked || !toolbarClickCallback) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { actionButton } = button;
|
||||
|
||||
const generateOperation = (operation, value) => {
|
||||
// Combine slider value into slider operation
|
||||
const generatedOperation = { ...operation };
|
||||
generatedOperation.commandOptions = {
|
||||
...operation.commandOptions,
|
||||
slabThickness: value,
|
||||
};
|
||||
|
||||
return generatedOperation;
|
||||
};
|
||||
|
||||
const operation = generateOperation(actionButton, value);
|
||||
toolbarClickCallback(operation, event);
|
||||
};
|
||||
|
||||
const _applyModeOperation = (
|
||||
operation,
|
||||
modeChecked,
|
||||
toolbarClickCallback,
|
||||
button
|
||||
) => {
|
||||
// in case modeChecked has not being triggered by user yet
|
||||
if (typeof modeChecked !== 'boolean') {
|
||||
return;
|
||||
}
|
||||
|
||||
const { deactivateButton } = button;
|
||||
|
||||
const _operation = modeChecked ? operation : deactivateButton;
|
||||
if (toolbarClickCallback && _operation) {
|
||||
toolbarClickCallback(_operation);
|
||||
}
|
||||
};
|
||||
|
||||
const _getInitialState = currentSelectedOption => {
|
||||
return {
|
||||
value: SLIDER.MIN,
|
||||
sliderMin: SLIDER.MIN,
|
||||
sliderMax: SLIDER.MAX,
|
||||
modeChecked: undefined,
|
||||
operation: currentSelectedOption,
|
||||
};
|
||||
};
|
||||
|
||||
const INITIAL_OPTION_INDEX = 0;
|
||||
const _getInitialtSelectedOption = (button = {}) => {
|
||||
return (
|
||||
button.operationButtons && button.operationButtons[INITIAL_OPTION_INDEX]
|
||||
);
|
||||
};
|
||||
|
||||
function SlabThicknessToolbarComponent({
|
||||
parentContext,
|
||||
toolbarClickCallback,
|
||||
button,
|
||||
activeButtons,
|
||||
isActive,
|
||||
className,
|
||||
}) {
|
||||
const currentSelectedOption = _getInitialtSelectedOption(button);
|
||||
const [state, setState] = useState(_getInitialState(currentSelectedOption));
|
||||
const { label, operationButtons } = button;
|
||||
const _className = _getClassNames(isActive, className);
|
||||
const selectOptions = _getSelectOptions(button);
|
||||
function onChangeSelect(selectedValue) {
|
||||
// find select value
|
||||
const operation = operationButtons.find(
|
||||
button => button.id === selectedValue
|
||||
);
|
||||
|
||||
if (operation === state.operation) {
|
||||
return;
|
||||
}
|
||||
|
||||
setState({ ...state, operation });
|
||||
}
|
||||
|
||||
function onChangeCheckbox(checked) {
|
||||
setState({ ...state, modeChecked: checked });
|
||||
}
|
||||
|
||||
function onChangeSlider(event) {
|
||||
const value = Number(event.target.value);
|
||||
|
||||
if (value !== state.value) {
|
||||
setState({ ...state, value, modeChecked: true });
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
_applyModeOperation(
|
||||
state.operation,
|
||||
state.modeChecked,
|
||||
toolbarClickCallback,
|
||||
button
|
||||
);
|
||||
}, [state.modeChecked, state.operation]);
|
||||
|
||||
useEffect(() => {
|
||||
_applySlabThickness(
|
||||
state.value,
|
||||
state.modeChecked,
|
||||
toolbarClickCallback,
|
||||
button
|
||||
);
|
||||
}, [state.operation, state.modeChecked, state.value]);
|
||||
|
||||
return (
|
||||
<div className={_className}>
|
||||
<div className="container">
|
||||
<ToolbarSlider
|
||||
value={state.value}
|
||||
min={state.sliderMin}
|
||||
max={state.sliderMax}
|
||||
onChange={onChangeSlider}
|
||||
/>
|
||||
<ToolbarLabel key="toolbar-label" label={label} />
|
||||
</div>
|
||||
<div className="controller">
|
||||
<Checkbox
|
||||
label="mode"
|
||||
checked={state.modeChecked}
|
||||
onChange={onChangeCheckbox}
|
||||
></Checkbox>
|
||||
<Select
|
||||
key="toolbar-select"
|
||||
options={selectOptions}
|
||||
value={selectOptions[INITIAL_OPTION_INDEX].value}
|
||||
onChange={onChangeSelect}
|
||||
></Select>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
SlabThicknessToolbarComponent.propTypes = {
|
||||
parentContext: PropTypes.object.isRequired,
|
||||
toolbarClickCallback: PropTypes.func.isRequired,
|
||||
button: PropTypes.object.isRequired,
|
||||
activeButtons: PropTypes.array.isRequired,
|
||||
isActive: PropTypes.bool,
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SlabThicknessToolbarComponent;
|
||||
@@ -0,0 +1,55 @@
|
||||
.slab-thickness
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: flex-end;
|
||||
height: 60px;
|
||||
margin-top: -12px;
|
||||
&:hover
|
||||
color: var(--default-color);
|
||||
.container
|
||||
padding-right: 10px;
|
||||
height: inherit;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
.toolbar-slider-container
|
||||
width: 80px;
|
||||
margin: 0px 2px 2px 2px;
|
||||
font-size: 12px;
|
||||
&:hover
|
||||
color: var(--hover-color);
|
||||
input
|
||||
height: 20px;
|
||||
padding-top: 6px;
|
||||
&::-moz-range-thumb
|
||||
height: 16px;
|
||||
margin-top: -7px;
|
||||
&::-webkit-slider-thumb
|
||||
height: 16px;
|
||||
margin-top: -7px;
|
||||
.controller
|
||||
width: 62px;
|
||||
.ohif-check-container
|
||||
margin-bottom: 5px;
|
||||
padding-left: 18px;
|
||||
.ohif-check-label
|
||||
text-transform: capitalize;
|
||||
&:hover
|
||||
color: var(--hover-color);
|
||||
.ohif-checkbox
|
||||
border-radius: 3px;
|
||||
background-color: white;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
top: 22%;
|
||||
&.ohif-checked:after
|
||||
background-color: var(--active-color);
|
||||
top: 17%;
|
||||
left: 17%;
|
||||
.select-ohif
|
||||
color: var(--default-color);
|
||||
border-color: var(--default-color);
|
||||
background-color: black;
|
||||
background-image: url('data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22%2F%3E%3C%2Fsvg%3E');
|
||||
&:hover
|
||||
color: var(--hover-color);
|
||||
@@ -1,3 +1,5 @@
|
||||
import SlabThicknessToolbarComponent from './toolbarComponents/SlabThicknessToolbarComponent';
|
||||
|
||||
const TOOLBAR_BUTTON_TYPES = {
|
||||
COMMAND: 'command',
|
||||
SET_TOOL_ACTIVE: 'setToolActive',
|
||||
@@ -31,6 +33,7 @@ const definitions = [
|
||||
commandName: 'enableRotateTool',
|
||||
commandOptions: {},
|
||||
},
|
||||
/*
|
||||
{
|
||||
id: 'setBlendModeToComposite',
|
||||
label: 'Disable MIP',
|
||||
@@ -68,6 +71,50 @@ const definitions = [
|
||||
commandName: 'decreaseSlabThickness',
|
||||
commandOptions: {},
|
||||
},
|
||||
*/
|
||||
{
|
||||
id: 'changeSlabThickness',
|
||||
label: 'Slab Thickness',
|
||||
icon: 'soft-tissue',
|
||||
CustomComponent: SlabThicknessToolbarComponent,
|
||||
commandName: 'setSlabThickness',
|
||||
actionButton: {
|
||||
id: 'setSlabThickness',
|
||||
label: 'slider',
|
||||
type: TOOLBAR_BUTTON_TYPES.COMMAND,
|
||||
commandName: 'setSlabThickness',
|
||||
commandOptions: {},
|
||||
},
|
||||
deactivateButton: {
|
||||
id: 'setBlendModeToComposite',
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setBlendModeToComposite',
|
||||
commandOptions: {},
|
||||
},
|
||||
operationButtons: [
|
||||
{
|
||||
id: 'setBlendModeToMaximumIntensity',
|
||||
label: 'MIP',
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setBlendModeToMaximumIntensity',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'setBlendModeToMinimumIntensity',
|
||||
label: 'MinIP',
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setBlendModeToMinimumIntensity',
|
||||
commandOptions: {},
|
||||
},
|
||||
{
|
||||
id: 'setBlendModeToAverageIntensity',
|
||||
label: 'AvgIP',
|
||||
type: TOOLBAR_BUTTON_TYPES.SET_TOOL_ACTIVE,
|
||||
commandName: 'setBlendModeToAverageIntensity',
|
||||
commandOptions: {},
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default {
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
"dev:project": ".scripts/dev.sh",
|
||||
"dev:orthanc": "lerna run dev:orthanc --stream",
|
||||
"orthanc:up": "docker-compose -f .docker/Nginx-Orthanc/docker-compose.yml up",
|
||||
"start": "yarn run dev",
|
||||
"test": "yarn run test:unit",
|
||||
"test:unit": "jest --collectCoverage",
|
||||
"test:unit:ci": "lerna run test:unit:ci --parallel --stream",
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.0.1](https://github.com/OHIF/Viewers/compare/@ohif/core@1.0.0...@ohif/core@1.0.1) (2019-09-27)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Check for Value in 00081155 sequence (Few patient protocol images doesn't have this value) and removed a duplicate declaration ([#921](https://github.com/OHIF/Viewers/issues/921)) ([d0ec9cf](https://github.com/OHIF/Viewers/commit/d0ec9cf))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.0.0](https://github.com/OHIF/Viewers/compare/@ohif/core@0.50.10...@ohif/core@1.0.0) (2019-09-27)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/core",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"description": "Generic business logic for web-based medical imaging applications",
|
||||
"author": "OHIF Core Team",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -133,7 +133,8 @@ function getSourceImageInstanceUid(instance) {
|
||||
if (
|
||||
SourceImageSequence &&
|
||||
SourceImageSequence.Value &&
|
||||
SourceImageSequence.Value.length
|
||||
SourceImageSequence.Value.length &&
|
||||
SourceImageSequence.Value[0]['00081155'].Value
|
||||
) {
|
||||
return SourceImageSequence.Value[0]['00081155'].Value[0];
|
||||
}
|
||||
@@ -293,7 +294,6 @@ async function resultDataToStudyMetadata(server, studyInstanceUid, resultData) {
|
||||
// TODO: Pass a reference ID to the server instead of including the URLs here
|
||||
const studyData = {
|
||||
seriesList: [],
|
||||
studyInstanceUid,
|
||||
wadoUriRoot: server.wadoUriRoot,
|
||||
wadoRoot: server.wadoRoot,
|
||||
qidoRoot: server.qidoRoot,
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
# [0.52.0](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.51.3...@ohif/ui@0.52.0) (2019-10-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 MPR UI improvements. Added MinIP, AvgIP, slab thickness slider and mode toggle ([#947](https://github.com/OHIF/Viewers/issues/947)) ([c79c0c3](https://github.com/OHIF/Viewers/commit/c79c0c3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.51.3](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.51.2...@ohif/ui@0.51.3) (2019-10-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Address issues with touch devices and drag/drop causing crashes ([#982](https://github.com/OHIF/Viewers/issues/982)) ([cf40a83](https://github.com/OHIF/Viewers/commit/cf40a83))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [0.51.2](https://github.com/OHIF/Viewers/compare/@ohif/ui@0.51.1...@ohif/ui@0.51.2) (2019-09-26)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/ui",
|
||||
"version": "0.51.2",
|
||||
"version": "0.52.0",
|
||||
"description": "A set of React components for Medical Imaging Viewers",
|
||||
"author": "OHIF Contributors",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -6,15 +6,29 @@ export class Checkbox extends Component {
|
||||
static propTypes = {
|
||||
label: PropTypes.string.isRequired,
|
||||
checked: PropTypes.bool,
|
||||
onChange: PropTypes.func,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = { checked: props.checked, label: props.label };
|
||||
this.state = { checked: !!props.checked, label: props.label };
|
||||
}
|
||||
|
||||
handleChange(e) {
|
||||
this.setState({ checked: e.target.checked });
|
||||
const checked = e.target.checked;
|
||||
this.setState({ checked });
|
||||
if (this.props.onChange) this.props.onChange(checked);
|
||||
}
|
||||
|
||||
componentDidUpdate(props) {
|
||||
const { checked = false, label } = props;
|
||||
|
||||
if (this.state.checked !== checked || this.state.label !== label) {
|
||||
this.setState({
|
||||
checked,
|
||||
label,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -32,9 +46,7 @@ export class Checkbox extends Component {
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={this.state.checked}
|
||||
onChange={e => {
|
||||
this.handleChange(e);
|
||||
}}
|
||||
onChange={this.handleChange.bind(this)}
|
||||
/>
|
||||
{checkbox}
|
||||
{this.state.label}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
UserPreferencesModal,
|
||||
} from './userPreferencesModal';
|
||||
|
||||
import { Checkbox } from './checkbox';
|
||||
import { CineDialog } from './cineDialog';
|
||||
import { QuickSwitch } from './quickSwitch';
|
||||
import { RoundedButtonGroup } from './roundedButtonGroup';
|
||||
@@ -23,6 +24,7 @@ import { ToolbarSection } from './toolbarSection';
|
||||
import { Tooltip } from './tooltip';
|
||||
|
||||
export {
|
||||
Checkbox,
|
||||
CineDialog,
|
||||
ExampleDropTarget,
|
||||
LayoutButton,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
-webkit-appearance: none;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.range:focus {
|
||||
|
||||
@@ -11,7 +11,7 @@ class Range extends React.Component {
|
||||
|
||||
handleChange = event => {
|
||||
this.setState({ value: event.target.value });
|
||||
if (this.props.onChange) this.props.onChange();
|
||||
if (this.props.onChange) this.props.onChange(event);
|
||||
};
|
||||
|
||||
render() {
|
||||
@@ -21,6 +21,7 @@ class Range extends React.Component {
|
||||
value={this.state.value}
|
||||
min={this.props.min}
|
||||
max={this.props.max}
|
||||
step={this.props.step || 1}
|
||||
onChange={this.handleChange}
|
||||
id={this.props.id}
|
||||
className="range"
|
||||
|
||||
@@ -34,10 +34,6 @@
|
||||
}
|
||||
|
||||
.select-ohif:focus {
|
||||
border-color: #aaa;
|
||||
box-shadow: 0 0 1px 3px rgba(59, 153, 252, 0.7);
|
||||
box-shadow: 0 0 0 3px -moz-mac-focusring;
|
||||
color: #222;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,9 @@ class Select extends Component {
|
||||
}
|
||||
|
||||
handleChange = event => {
|
||||
this.setState({ value: event.target.value });
|
||||
if (this.props.onChange) this.props.onChange();
|
||||
const value = event.target.value;
|
||||
this.setState({ value });
|
||||
if (this.props.onChange) this.props.onChange(value);
|
||||
};
|
||||
|
||||
render() {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Checkbox,
|
||||
CineDialog,
|
||||
ExampleDropTarget,
|
||||
LayoutButton,
|
||||
@@ -25,7 +26,7 @@ import {
|
||||
import { ICONS, Icon } from './elements';
|
||||
|
||||
// Alias this for now as not all dependents are using strict versioning
|
||||
import { DropdownMenu as Dropdown } from './elements/form';
|
||||
import { DropdownMenu as Dropdown, Range, Select } from './elements/form';
|
||||
import ExpandableToolMenu from './viewer/ExpandableToolMenu.js';
|
||||
import LayoutManager from './LayoutChooser/LayoutManager.js';
|
||||
import LayoutPanelDropTarget from './LayoutChooser/LayoutPanelDropTarget.js';
|
||||
@@ -38,6 +39,7 @@ import ViewerbaseDragDropContext from './utils/viewerbaseDragDropContext.js';
|
||||
export {
|
||||
ICONS,
|
||||
//
|
||||
Checkbox,
|
||||
CineDialog,
|
||||
Dropdown,
|
||||
ExpandableToolMenu,
|
||||
@@ -53,8 +55,10 @@ export {
|
||||
OverlayTrigger,
|
||||
PlayClipButton,
|
||||
QuickSwitch,
|
||||
Range,
|
||||
RoundedButtonGroup,
|
||||
ScrollableArea,
|
||||
Select,
|
||||
SelectTree,
|
||||
SimpleDialog,
|
||||
StudyBrowser,
|
||||
|
||||
@@ -10,10 +10,11 @@ const isTouchDevice = !!('ontouchstart' in window || navigator.maxTouchPoints);
|
||||
//
|
||||
// http://react-dnd.github.io/react-dnd/docs/api/drag-drop-context
|
||||
export default function viewerbaseDragDropContext(DecoratedClass) {
|
||||
const backend = isTouchDevice ? TouchBackend({ enableMouseEvents: true }) : HTML5Backend;
|
||||
const backend = isTouchDevice ? TouchBackend : HTML5Backend;
|
||||
const opts = isTouchDevice ? { enableMouseEvents: true } : {};
|
||||
|
||||
return (props) => (
|
||||
<DndProvider backend={backend}>
|
||||
<DndProvider backend={backend} opts={opts}>
|
||||
<DecoratedClass {...props}/>
|
||||
</DndProvider>
|
||||
);
|
||||
|
||||
@@ -108,16 +108,8 @@ class ExpandableToolMenu extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<OverlayTrigger
|
||||
key="menu-button"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
rootClose={true}
|
||||
handleHide={this.onOverlayHide}
|
||||
onClick={this.onExpandableToolClick}
|
||||
overlay={this.toolbarMenuOverlay()}
|
||||
>
|
||||
const getToolBarButtonComponent = () => {
|
||||
return (
|
||||
<ToolbarButton
|
||||
key="menu-button"
|
||||
type="tool"
|
||||
@@ -128,6 +120,22 @@ class ExpandableToolMenu extends React.Component {
|
||||
isExpandable={true}
|
||||
isExpanded={this.state.isExpanded}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const toolbarComponent = getToolBarButtonComponent();
|
||||
|
||||
return (
|
||||
<OverlayTrigger
|
||||
key="menu-button"
|
||||
trigger="click"
|
||||
placement="bottom"
|
||||
rootClose={true}
|
||||
handleHide={this.onOverlayHide}
|
||||
onClick={this.onExpandableToolClick}
|
||||
overlay={this.toolbarMenuOverlay()}
|
||||
>
|
||||
{toolbarComponent}
|
||||
</OverlayTrigger>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -114,6 +114,8 @@ module.exports = (env, argv) => {
|
||||
hot: true,
|
||||
open: true,
|
||||
port: 3000,
|
||||
host: '0.0.0.0',
|
||||
public: 'http://localhost:' + 3000,
|
||||
historyApiFallback: {
|
||||
disableDotRule: true,
|
||||
},
|
||||
|
||||
@@ -3,6 +3,60 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [1.3.2](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.3.1...@ohif/viewer@1.3.2) (2019-10-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.3.1](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.3.0...@ohif/viewer@1.3.1) (2019-10-01)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Exit MPR mode if Layout is changed ([#984](https://github.com/OHIF/Viewers/issues/984)) ([674ca9f](https://github.com/OHIF/Viewers/commit/674ca9f))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [1.3.0](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.2.8...@ohif/viewer@1.3.0) (2019-10-01)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* 🎸 MPR UI improvements. Added MinIP, AvgIP, slab thickness slider and mode toggle ([#947](https://github.com/OHIF/Viewers/issues/947)) ([c79c0c3](https://github.com/OHIF/Viewers/commit/c79c0c3))
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.8](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.2.7...@ohif/viewer@1.2.8) (2019-10-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.7](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.2.6...@ohif/viewer@1.2.7) (2019-10-01)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.6](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.2.5...@ohif/viewer@1.2.6) (2019-09-27)
|
||||
|
||||
**Note:** Version bump only for package @ohif/viewer
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## [1.2.5](https://github.com/OHIF/Viewers/compare/@ohif/viewer@1.2.4...@ohif/viewer@1.2.5) (2019-09-27)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ohif/viewer",
|
||||
"version": "1.2.5",
|
||||
"version": "1.3.2",
|
||||
"description": "OHIF Viewer",
|
||||
"author": "OHIF Contributors",
|
||||
"license": "MIT",
|
||||
@@ -46,14 +46,14 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.5.5",
|
||||
"@ohif/core": "^1.0.0",
|
||||
"@ohif/core": "^1.0.1",
|
||||
"@ohif/extension-cornerstone": "^2.0.0",
|
||||
"@ohif/extension-dicom-html": "^1.0.0",
|
||||
"@ohif/extension-dicom-microscopy": "^0.50.6",
|
||||
"@ohif/extension-dicom-pdf": "^1.0.0",
|
||||
"@ohif/extension-vtk": "^0.50.21",
|
||||
"@ohif/extension-vtk": "^0.51.1",
|
||||
"@ohif/i18n": "^0.50.4",
|
||||
"@ohif/ui": "^0.51.2",
|
||||
"@ohif/ui": "^0.52.0",
|
||||
"@tanem/react-nprogress": "^1.1.25",
|
||||
"classnames": "^2.2.6",
|
||||
"core-js": "^3.2.1",
|
||||
|
||||
@@ -13,15 +13,23 @@ const mapStateToProps = state => {
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
// TODO: Change if layout switched becomes more complex
|
||||
onChange: selectedCell => {
|
||||
onChange: (selectedCell, currentLayout) => {
|
||||
let viewports = [];
|
||||
const rows = selectedCell.row + 1;
|
||||
const columns = selectedCell.col + 1;
|
||||
const numViewports = rows * columns;
|
||||
for (let i = 0; i < numViewports; i++) {
|
||||
// Hacky way to allow users to exit MPR "mode"
|
||||
const viewport = currentLayout.viewports[i];
|
||||
let plugin = viewport && viewport.plugin;
|
||||
if (viewport && viewport.vtk) {
|
||||
plugin = 'cornerstone';
|
||||
}
|
||||
|
||||
viewports.push({
|
||||
height: `${100 / rows}%`,
|
||||
width: `${100 / columns}%`,
|
||||
plugin,
|
||||
});
|
||||
}
|
||||
const layout = {
|
||||
@@ -33,9 +41,19 @@ const mapDispatchToProps = dispatch => {
|
||||
};
|
||||
};
|
||||
|
||||
const mergeProps = (propsFromState, propsFromDispatch) => {
|
||||
const onChangeFromDispatch = propsFromDispatch.onChange;
|
||||
const { currentLayout } = propsFromState;
|
||||
|
||||
return {
|
||||
onChange: (selectedCell) => onChangeFromDispatch(selectedCell, currentLayout)
|
||||
};
|
||||
}
|
||||
|
||||
const ConnectedLayoutButton = connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
mapDispatchToProps,
|
||||
mergeProps
|
||||
)(LayoutButton);
|
||||
|
||||
export default ConnectedLayoutButton;
|
||||
@@ -229,6 +229,7 @@ function _getButtonComponents(toolbarButtons, activeButtons) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A handy way for us to handle different button types. IE. firing commands for
|
||||
* buttons, or initiation built in behavior.
|
||||
|
||||
@@ -8273,6 +8273,11 @@ gl-matrix@3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.0.0.tgz#888301ac7650e148c3865370e13ec66d08a8381f"
|
||||
integrity sha512-PD4mVH/C/Zs64kOozeFnKY8ybhgwxXXQYGWdB4h68krAHknWJgk9uKOn6z8YElh5//vs++90pb6csrTIDWnexA==
|
||||
|
||||
gl-matrix@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/gl-matrix/-/gl-matrix-3.1.0.tgz#f5b2de17d8fed95a79e5025b10cded0ab9ccbed0"
|
||||
integrity sha512-526NA+3EA+ztAQi0IZpSWiM0fyQXIp7IbRvfJ4wS/TjjQD0uv0fVybXwwqqSOlq33UckivI0yMDlVtboWm3k7A==
|
||||
|
||||
gl-preserve-state@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/gl-preserve-state/-/gl-preserve-state-1.0.0.tgz#4ef710d62873f1470ed015c6546c37dacddd4198"
|
||||
@@ -14954,12 +14959,13 @@ react-transition-group@^4.1.1:
|
||||
loose-envify "^1.4.0"
|
||||
prop-types "^15.6.2"
|
||||
|
||||
react-vtkjs-viewport@0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.1.0.tgz#a00b114b635ff95a82ae1227d70c248e4cafddf4"
|
||||
integrity sha512-0gnRfntpV6ZBNvZOHzjHapFeJajO8nfkSvO5SNUu41bkyXxqYcJwZvb3EWbd04V1RnA0AnKRoR/KL+I09Os7gg==
|
||||
react-vtkjs-viewport@0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-vtkjs-viewport/-/react-vtkjs-viewport-0.1.2.tgz#087af73b1c46627c5079d25ab1b0d3866cb7b06b"
|
||||
integrity sha512-1UejtY8i6LhK2FXouD7so2VRYbdjo7w80VUQ6EesyurBAZYAYW3ppvAlBjtvMlJhYZn13wwE3gTFAbrHPVPjDw==
|
||||
dependencies:
|
||||
date-fns "^2.2.1"
|
||||
gl-matrix "^3.1.0"
|
||||
|
||||
react-with-direction@1.3.0:
|
||||
version "1.3.0"
|
||||
|
||||
Reference in new issue
Block a user