itk-viewer-bootstrap-ui
Advanced tools
Comparing version 0.17.0 to 0.18.0
{ | ||
"name": "itk-viewer-bootstrap-ui", | ||
"version": "0.17.0", | ||
"version": "0.18.0", | ||
"scripts": { | ||
@@ -28,3 +28,3 @@ "dev": "vite", | ||
"itk-viewer-color-maps": "^1.2.0", | ||
"itk-viewer-icons": "^11.13.0", | ||
"itk-viewer-icons": "^11.13.1", | ||
"itk-viewer-transfer-function-editor": "^1.2.2", | ||
@@ -31,0 +31,0 @@ "prettier": "^2.5.0", |
@@ -5,2 +5,3 @@ import React, { useEffect, useRef, useState } from 'react' | ||
import ColorMapIconSelector from './ColorMapIconSelector' | ||
import WindowLevelReset from './WindowLevelReset' | ||
import '../style.css' | ||
@@ -19,2 +20,4 @@ import Button from 'react-bootstrap/Button' | ||
const interpolationButton = useRef(null) | ||
const [input1Tooltip, setInput1Tooltip] = useState('Color range min') | ||
const [input2Tooltip, setInput2Tooltip] = useState('Color range max') | ||
const send = service.send | ||
@@ -31,2 +34,3 @@ const name = useSelector( | ||
) | ||
const colorRanges = useSelector( | ||
@@ -39,2 +43,9 @@ service, | ||
const colorRangeBounds = useSelector( | ||
service, | ||
(state) => | ||
state.context.images.actorContext.get(state.context.images.selectedName) | ||
.colorRangeBounds | ||
) | ||
const selectedComponent = useSelector( | ||
@@ -47,2 +58,9 @@ service, | ||
const windowLevelEnabled = useSelector( | ||
service, | ||
(state) => | ||
state.context.images.actorContext.get(state.context.images.selectedName) | ||
.windowLevelEnabled | ||
) | ||
const colorRangesSelected = useSelector(service, (state) => | ||
@@ -70,2 +88,7 @@ state.context.images.actorContext | ||
useEffect(() => { | ||
setInput1Tooltip(windowLevelEnabled ? 'Window width' : 'Color range min') | ||
setInput2Tooltip(windowLevelEnabled ? 'Window level' : 'Color range max') | ||
}, [windowLevelEnabled]) | ||
const toggleInterpolate = () => { | ||
@@ -81,2 +104,5 @@ send({ | ||
const currentRangeMax = currentRange[1] | ||
const currentBounds = colorRangeBounds.size ? boundsSelected : [0, 1] | ||
const currentWidth = currentBounds[1] - currentBounds[0] | ||
const currentLevel = (currentBounds[1] + currentBounds[0]) / 2 | ||
@@ -101,6 +127,10 @@ let [rangeMin, rangeMax] = [0, 0] | ||
} | ||
const step = | ||
const rangeStep = | ||
imageType?.slice(0, 5) === 'float' ? (rangeMax - rangeMin) / 200 : 1 | ||
const windowingStep = | ||
10 ** Math.ceil(Math.log((currentBounds[1] - currentBounds[0]) / 1000)) | ||
const [minIntent, setminIntent] = useState(currentRangeMin) | ||
const [maxIntent, setmaxIntent] = useState(currentRangeMax) | ||
const [width, setWidth] = useState(currentWidth) | ||
const [level, setLevel] = useState(currentLevel) | ||
@@ -114,51 +144,72 @@ // update the initialized state for minIntent and maxIntent | ||
}, [currentRangeMax]) | ||
useEffect(() => { | ||
setWidth(currentWidth) | ||
}, [currentWidth]) | ||
useEffect(() => { | ||
setLevel(currentLevel) | ||
}, [currentLevel]) | ||
useEffect(() => { | ||
const [min, max] = currentRange | ||
setWidth(max - min) | ||
setLevel((max + min) / 2) | ||
}, [currentRange]) | ||
const isValidBounds = (minVal, maxVal) => { | ||
if (minVal < maxVal) { | ||
return true | ||
} else { | ||
const isValidBounds = (input1, input2) => { | ||
if (isNaN(input1) || isNaN(input2)) { | ||
return false | ||
} | ||
return isValidInput(input1, input2) | ||
} | ||
const rangeChanged = (minVal, maxVal) => { | ||
const bounds = boundsSelected | ||
const isValidInput = () => { | ||
if (windowLevelEnabled) { | ||
return width > 0 | ||
} else { | ||
return minIntent <= maxIntent | ||
} | ||
} | ||
if (!isNaN(minVal) && !isNaN(maxVal)) { | ||
let rangeMax = maxVal >= bounds[1] ? bounds[1] : maxVal | ||
let rangeMin = minVal <= bounds[0] ? bounds[0] : minVal | ||
if (isValidBounds(rangeMin, rangeMax)) { | ||
const inputChanged = (input1, input2) => { | ||
if (isValidBounds(input1, input2)) { | ||
let rangeMin = minIntent | ||
let rangeMax = maxIntent | ||
if (windowLevelEnabled) { | ||
rangeMin = input2 - input1 / 2 | ||
rangeMax = input2 + input1 / 2 | ||
setWidth(input1) | ||
setLevel(input2) | ||
} else { | ||
const bounds = boundsSelected | ||
rangeMax = input2 >= bounds[1] ? bounds[1] : input2 | ||
rangeMin = input1 <= bounds[0] ? bounds[0] : input1 | ||
setmaxIntent(rangeMax) | ||
setminIntent(rangeMin) | ||
send({ | ||
type: 'IMAGE_COLOR_RANGE_CHANGED', | ||
data: { | ||
name, | ||
component: selectedComponent, | ||
range: [rangeMin, rangeMax] | ||
} | ||
}) | ||
} else { | ||
setmaxIntent(maxVal) | ||
setminIntent(minVal) | ||
} | ||
send({ | ||
type: 'IMAGE_COLOR_RANGE_CHANGED', | ||
data: { | ||
name, | ||
component: selectedComponent, | ||
range: [rangeMin, rangeMax] | ||
} | ||
}) | ||
} else { | ||
if (isNaN(minVal)) { | ||
setminIntent('') | ||
if (windowLevelEnabled) { | ||
setWidth(input1) | ||
setLevel(input2) | ||
} else { | ||
setmaxIntent(input1) | ||
setminIntent(input2) | ||
} | ||
if (isNaN(maxVal)) { | ||
setmaxIntent('') | ||
} | ||
} | ||
} | ||
const rangeMinChanged = (val) => { | ||
const maxVal = currentRangeMax | ||
rangeChanged(parseFloat(val), maxVal) | ||
const input1Changed = (val) => { | ||
let input2 = windowLevelEnabled ? level : currentRangeMax | ||
inputChanged(parseFloat(val), input2) | ||
} | ||
const rangeMaxChanged = (val) => { | ||
const minVal = currentRangeMin | ||
rangeChanged(minVal, parseFloat(val)) | ||
const input2Changed = (val) => { | ||
let input1 = windowLevelEnabled ? width : currentRangeMin | ||
inputChanged(input1, parseFloat(val)) | ||
} | ||
@@ -190,29 +241,36 @@ | ||
</OverlayTrigger> | ||
<OverlayTrigger transition={false} overlay={<Tooltip>Min</Tooltip>}> | ||
<OverlayTrigger | ||
transition={false} | ||
overlay={<Tooltip>{input1Tooltip}</Tooltip>} | ||
> | ||
<Form.Control | ||
className={cn('numberInput', { | ||
invalidNumber: minIntent >= maxIntent | ||
invalidNumber: !isValidInput() | ||
})} | ||
type="number" | ||
value={minIntent} | ||
value={windowLevelEnabled ? width : minIntent} | ||
onChange={(e) => { | ||
rangeMinChanged(e.target.value) | ||
input1Changed(e.target.value) | ||
}} | ||
step={step} | ||
step={windowLevelEnabled ? windowingStep : rangeStep} | ||
/> | ||
</OverlayTrigger> | ||
<ColorMapIconSelector {...props} /> | ||
<OverlayTrigger transition={false} overlay={<Tooltip>Max</Tooltip>}> | ||
<OverlayTrigger | ||
transition={false} | ||
overlay={<Tooltip>{input2Tooltip}</Tooltip>} | ||
> | ||
<Form.Control | ||
className={cn('numberInput', { | ||
invalidNumber: maxIntent <= minIntent | ||
invalidNumber: !isValidInput() | ||
})} | ||
type="number" | ||
value={maxIntent} | ||
value={windowLevelEnabled ? level : maxIntent} | ||
onChange={(e) => { | ||
rangeMaxChanged(e.target.value) | ||
input2Changed(e.target.value) | ||
}} | ||
step={step} | ||
step={windowLevelEnabled ? windowingStep : rangeStep} | ||
/> | ||
</OverlayTrigger> | ||
<WindowLevelReset {...props} /> | ||
</div> | ||
@@ -219,0 +277,0 @@ ) |
@@ -5,2 +5,3 @@ import ImagesInterface from './ImagesInterface' | ||
import { applyPiecewiseFunctionPointsToEditor } from './transferFunctionWidgetUtils' | ||
import applyWindowLevelReset from './applyWindowLevelReset' | ||
@@ -12,3 +13,4 @@ const imagesUIMachineOptions = { | ||
applyPiecewiseFunctionPointsToEditor, | ||
selectImageComponent | ||
selectImageComponent, | ||
applyWindowLevelReset | ||
} | ||
@@ -15,0 +17,0 @@ } |
@@ -7,2 +7,3 @@ import React from 'react' | ||
import ShadowToggle from './ShadowToggle' | ||
import WindowingLevelToggle from './WindowLevelToggle' | ||
import CinematicParameters from './CinematicParameters' | ||
@@ -36,2 +37,3 @@ import '../style.css' | ||
<GradientOpacitySlider {...props} /> | ||
<WindowingLevelToggle {...props} /> | ||
</div> | ||
@@ -38,0 +40,0 @@ {advancedInputs && advancedInputContent} |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
14991711
132
24353
Updateditk-viewer-icons@^11.13.1