Skip to content

Commit 709649f

Browse files
Allow displaying different segments with different colors (#326)
* Add segment color support * Address rerendering issue resetting colors * Fix default color * Lint * Use dcmjs to convert ceilab values * Lint * Fix color set issue * Lint * Use custom func to color * Update call to palette func * Lint * Remove txt * Fix color * Refactor slider components * Lint * Sonar * Sonar * Sonar * Fix default color for optical path * Add segment interpolation toggle * Bump dmv
1 parent 84d0f18 commit 709649f

22 files changed

Lines changed: 942 additions & 702 deletions

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"craco-less": "^2.0.0",
5757
"dcmjs": "^0.35.0",
5858
"detect-browser": "^5.2.1",
59-
"dicom-microscopy-viewer": "^0.48.7",
59+
"dicom-microscopy-viewer": "^0.48.8",
6060
"dicomweb-client": "^0.10.3",
6161
"gh-pages": "^5.0.0",
6262
"oidc-client": "^1.11.5",
@@ -67,6 +67,7 @@
6767
"react-scripts": "5.0.0",
6868
"react-test-renderer": "^18.2.0",
6969
"retry": "^0.13.1",
70+
"sonarqube-scanner": "^4.3.0",
7071
"ts-standard": "^11.0.0",
7172
"typescript": "^4.7.4"
7273
},

src/App.tsx

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -221,18 +221,24 @@ class App extends React.Component<AppProps, AppState> {
221221
constructor (props: AppProps) {
222222
super(props)
223223

224-
console.info('instatiate app')
225-
console.info(`app is located at "${props.config.path}"`)
224+
// Only log in development environment
225+
if (process.env.NODE_ENV === 'development') {
226+
console.info('instatiate app')
227+
console.info(`app is located at "${props.config.path}"`)
228+
}
229+
226230
const { protocol, host } = window.location
227231
const baseUri = `${protocol}//${host}`
228232
const appUri = joinUrl(props.config.path, baseUri)
229233

230234
const oidcSettings = props.config.oidc
231235
if (oidcSettings !== undefined) {
232-
console.info(
233-
'app uses the following OIDC configuration: ',
234-
props.config.oidc
235-
)
236+
if (process.env.NODE_ENV === 'development') {
237+
console.info(
238+
'app uses the following OIDC configuration: ',
239+
props.config.oidc
240+
)
241+
}
236242
this.auth = new OidcManager(appUri, oidcSettings)
237243
}
238244

@@ -244,10 +250,13 @@ class App extends React.Component<AppProps, AppState> {
244250
'One server needs to be configured.')
245251
)
246252
}
247-
console.info(
248-
'app uses the following DICOMweb server configuration: ',
249-
props.config.servers
250-
)
253+
254+
if (process.env.NODE_ENV === 'development') {
255+
console.info(
256+
'app uses the following DICOMweb server configuration: ',
257+
props.config.servers
258+
)
259+
}
251260

252261
this.handleServerSelection = this.handleServerSelection.bind(this)
253262

src/DicomWebManager.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ export default class DicomWebManager implements dwc.api.DICOMwebClient {
3737
this.handleError = onError
3838
} else {
3939
this.handleError = (error, serverSettings) => {
40-
console.error(error, serverSettings)
40+
// Only log errors in development environment
41+
if (process.env.NODE_ENV === 'development') {
42+
console.error(error, serverSettings)
43+
}
4144
}
4245
}
4346

src/components/AnnotationGroupItem.tsx

Lines changed: 37 additions & 177 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
Space,
1414
Switch
1515
} from 'antd'
16+
import type { SelectProps } from 'antd'
1617
import { SettingOutlined } from '@ant-design/icons'
1718
import { FaEye, FaEyeSlash } from 'react-icons/fa'
1819
// skipcq: JS-C1003
@@ -22,6 +23,8 @@ import * as dcmjs from 'dcmjs'
2223

2324
import Description from './Description'
2425
import ValidationWarning from './ValidationWarning'
26+
import ColorSlider from './ColorSlider'
27+
import OpacitySlider from './OpacitySlider'
2528

2629
// Helper function components
2730
function AnnotationGroupControls ({
@@ -164,13 +167,6 @@ AnnotationGroupItemState
164167
> {
165168
constructor (props: AnnotationGroupItemProps) {
166169
super(props)
167-
this.handleMeasurementSelection =
168-
this.handleMeasurementSelection.bind(this)
169-
this.handleOpacityChange = this.handleOpacityChange.bind(this)
170-
this.handleColorRChange = this.handleColorRChange.bind(this)
171-
this.handleColorGChange = this.handleColorGChange.bind(this)
172-
this.handleColorBChange = this.handleColorBChange.bind(this)
173-
this.getCurrentColor = this.getCurrentColor.bind(this)
174170
this.state = {
175171
isVisible: this.props.isVisible,
176172
currentStyle: {
@@ -191,88 +187,39 @@ AnnotationGroupItemState
191187
this.setState({ isVisible: checked })
192188
}
193189

194-
handleOpacityChange (value: number | null): void {
195-
if (value !== null && value !== undefined) {
190+
handleColorChange = (color: number[]): void => {
191+
this.setState((state) => ({
192+
currentStyle: {
193+
color,
194+
opacity: state.currentStyle.opacity,
195+
limitValues: state.currentStyle.limitValues
196+
}
197+
}))
198+
this.props.onStyleChange({
199+
uid: this.props.annotationGroup.uid,
200+
styleOptions: { color }
201+
})
202+
}
203+
204+
handleOpacityChange = (opacity: number | null): void => {
205+
if (opacity !== null) {
196206
this.props.onStyleChange({
197207
uid: this.props.annotationGroup.uid,
198208
styleOptions: {
199-
opacity: value
209+
opacity
200210
}
201211
})
202212
this.setState({
203213
currentStyle: {
204-
opacity: value,
214+
opacity,
205215
color: this.state.currentStyle.color,
206216
limitValues: this.state.currentStyle.limitValues
207217
}
208218
})
209219
}
210220
}
211221

212-
handleColorRChange (value: number | number[] | null): void {
213-
if (value !== null && value !== undefined && this.state.currentStyle.color !== undefined) {
214-
const color = [
215-
Array.isArray(value) ? value[0] : value,
216-
this.state.currentStyle.color[1],
217-
this.state.currentStyle.color[2]
218-
]
219-
this.setState((state) => ({
220-
currentStyle: {
221-
color: color,
222-
opacity: state.currentStyle.opacity,
223-
limitValues: state.currentStyle.limitValues
224-
}
225-
}))
226-
this.props.onStyleChange({
227-
uid: this.props.annotationGroup.uid,
228-
styleOptions: { color: color }
229-
})
230-
}
231-
}
232-
233-
handleColorGChange (value: number | number[] | null): void {
234-
if (value !== null && value !== undefined && this.state.currentStyle.color !== undefined) {
235-
const color = [
236-
this.state.currentStyle.color[0],
237-
Array.isArray(value) ? value[0] : value,
238-
this.state.currentStyle.color[2]
239-
]
240-
this.setState((state) => ({
241-
currentStyle: {
242-
color: color,
243-
opacity: state.currentStyle.opacity,
244-
limitValues: state.currentStyle.limitValues
245-
}
246-
}))
247-
this.props.onStyleChange({
248-
uid: this.props.annotationGroup.uid,
249-
styleOptions: { color: color }
250-
})
251-
}
252-
}
253-
254-
handleColorBChange (value: number | number[] | null): void {
255-
if (value !== null && value !== undefined && this.state.currentStyle.color !== undefined) {
256-
const color = [
257-
this.state.currentStyle.color[0],
258-
this.state.currentStyle.color[1],
259-
Array.isArray(value) ? value[0] : value
260-
]
261-
this.setState((state) => ({
262-
currentStyle: {
263-
color: color,
264-
opacity: state.currentStyle.opacity,
265-
limitValues: state.currentStyle.limitValues
266-
}
267-
}))
268-
this.props.onStyleChange({
269-
uid: this.props.annotationGroup.uid,
270-
styleOptions: { color: color }
271-
})
272-
}
273-
}
274-
275-
getCurrentColor (): string {
222+
getCurrentColor = (): string => {
276223
const rgb2hex = (values: number[]): string => {
277224
const r = values[0]
278225
const g = values[1]
@@ -287,7 +234,7 @@ AnnotationGroupItemState
287234
}
288235
}
289236

290-
handleLowerLimitChange (value: number | null): void {
237+
handleLowerLimitChange = (value: number | null): void => {
291238
if (value !== null && value !== undefined && this.state.currentStyle.limitValues !== undefined) {
292239
this.setState((state) => {
293240
if (state.currentStyle.limitValues !== undefined) {
@@ -317,7 +264,7 @@ AnnotationGroupItemState
317264
}
318265
}
319266

320-
handleUpperLimitChange (value: number | null): void {
267+
handleUpperLimitChange = (value: number | null): void => {
321268
if (value !== null && value !== undefined && this.state.currentStyle.limitValues !== undefined) {
322269
this.setState((state) => {
323270
if (state.currentStyle.limitValues !== undefined) {
@@ -347,7 +294,7 @@ AnnotationGroupItemState
347294
}
348295
}
349296

350-
handleLimitChange (values: number[]): void {
297+
handleLimitChange = (values: number[]): void => {
351298
this.setState((state) => ({
352299
currentStyle: {
353300
color: state.currentStyle.color,
@@ -365,13 +312,13 @@ AnnotationGroupItemState
365312
this.props.onAnnotationGroupClick(this.props.annotationGroup.uid)
366313
}
367314

368-
handleMeasurementSelection (value?: string, option?: any): void {
369-
if (value !== null && value !== undefined && option?.children !== null && option?.children !== undefined) {
315+
handleMeasurementSelection: SelectProps['onChange'] = (value, option) => {
316+
if (value !== null && value !== undefined && option !== null && option !== undefined && Array.isArray(option) && option.length > 0 && option[0] !== null && option[0] !== undefined && option[0].children !== null && option[0].children !== undefined) {
370317
const codeComponents = value.split('-')
371318
const measurement = new dcmjs.sr.coding.CodedConcept({
372319
value: codeComponents[1],
373320
schemeDesignator: codeComponents[0],
374-
meaning: option.children
321+
meaning: Array.isArray(option[0].children) ? String(option[0].children[0]) : String(option[0].children)
375322
})
376323
this.props.onStyleChange({
377324
uid: this.props.annotationGroup.uid,
@@ -458,81 +405,14 @@ AnnotationGroupItemState
458405
)
459406

460407
let colorSettings
461-
if (this.state.currentStyle.color !== null && this.state.currentStyle.color !== undefined) {
408+
if (this.state.currentStyle.color !== null && this.state.currentStyle.color !== undefined && this.state.currentStyle.color.length === 3) {
462409
colorSettings = (
463410
<>
464411
<Divider plain>Color</Divider>
465-
<Row justify='center' align='middle' gutter={[8, 8]}>
466-
<Col span={5}>Red</Col>
467-
<Col span={14}>
468-
<Slider
469-
range={false}
470-
min={0}
471-
max={255}
472-
step={1}
473-
value={this.state.currentStyle.color[0]}
474-
onChange={this.handleColorRChange}
475-
/>
476-
</Col>
477-
<Col span={5}>
478-
<InputNumber
479-
min={0}
480-
max={255}
481-
size='small'
482-
style={{ width: '65px' }}
483-
value={this.state.currentStyle.color[0]}
484-
onChange={this.handleColorRChange}
485-
/>
486-
</Col>
487-
</Row>
488-
489-
<Row justify='center' align='middle' gutter={[8, 8]}>
490-
<Col span={5}>Green</Col>
491-
<Col span={14}>
492-
<Slider
493-
range={false}
494-
min={0}
495-
max={255}
496-
step={1}
497-
value={this.state.currentStyle.color[1]}
498-
onChange={this.handleColorGChange}
499-
/>
500-
</Col>
501-
<Col span={5}>
502-
<InputNumber
503-
min={0}
504-
max={255}
505-
size='small'
506-
style={{ width: '65px' }}
507-
value={this.state.currentStyle.color[1]}
508-
onChange={this.handleColorGChange}
509-
/>
510-
</Col>
511-
</Row>
512-
513-
<Row justify='center' align='middle' gutter={[8, 8]}>
514-
<Col span={5}>Blue</Col>
515-
<Col span={14}>
516-
<Slider
517-
range={false}
518-
min={0}
519-
max={255}
520-
step={1}
521-
value={this.state.currentStyle.color[2]}
522-
onChange={this.handleColorBChange}
523-
/>
524-
</Col>
525-
<Col span={5}>
526-
<InputNumber
527-
min={0}
528-
max={255}
529-
size='small'
530-
style={{ width: '65px' }}
531-
value={this.state.currentStyle.color[2]}
532-
onChange={this.handleColorBChange}
533-
/>
534-
</Col>
535-
</Row>
412+
<ColorSlider
413+
color={this.state.currentStyle.color}
414+
onChange={this.handleColorChange}
415+
/>
536416
<Divider plain />
537417
</>
538418
)
@@ -610,30 +490,10 @@ AnnotationGroupItemState
610490
<div>
611491
{colorSettings}
612492
{windowSettings}
613-
<Row justify='start' align='middle' gutter={[8, 8]}>
614-
<Col span={6}>Opacity</Col>
615-
<Col span={12}>
616-
<Slider
617-
range={false}
618-
min={0}
619-
max={1}
620-
step={0.01}
621-
value={this.state.currentStyle.opacity}
622-
onChange={this.handleOpacityChange}
623-
/>
624-
</Col>
625-
<Col span={6}>
626-
<InputNumber
627-
min={0}
628-
max={1}
629-
size='small'
630-
step={0.1}
631-
style={{ width: '65px' }}
632-
value={this.state.currentStyle.opacity}
633-
onChange={this.handleOpacityChange}
634-
/>
635-
</Col>
636-
</Row>
493+
<OpacitySlider
494+
opacity={this.state.currentStyle.opacity}
495+
onChange={this.handleOpacityChange}
496+
/>
637497
{explorationSettings}
638498
</div>
639499
)

0 commit comments

Comments
 (0)