diff --git a/extensions/cornerstone/src/commandsModule.ts b/extensions/cornerstone/src/commandsModule.ts index a2e059d5782..1859eec24ec 100644 --- a/extensions/cornerstone/src/commandsModule.ts +++ b/extensions/cornerstone/src/commandsModule.ts @@ -696,6 +696,48 @@ function commandsModule({ renameMeasurement: async ({ uid }) => { await actions._handleMeasurementLabelDialog(uid); }, + + changeMeasurementColor: ({uid}) => { + const measurement = measurementService.getMeasurement(uid); + + if (!measurement) { + console.debug('No measurement found for color editing'); + return; + } + + const color = measurement.color ?? [255, 255, 0, 255]; + const rgbaColor = { + r: color[0], + g: color[1], + b: color[2], + a: (color[3] !== undefined ? color[3] : 255) / 255.0, + }; + + uiDialogService.show({ + id: 'measurement-color-dialog', + content: colorPickerDialog, + title: i18n.t('Tools:Measurement Color'), + contentProps: { + value: rgbaColor, + onSave: newRgbaColor => { + const colorArray = [newRgbaColor.r, newRgbaColor.g, newRgbaColor.b, newRgbaColor.a * 255.0]; + const colorStr = `rgba(${newRgbaColor.r}, ${newRgbaColor.g}, ${newRgbaColor.b}, ${newRgbaColor.a})`; + + // Update OHIF measurement service + measurementService.updateColorMeasurement(uid, colorArray); + + // Update cornerstone tools rendering + annotation.config.style.setAnnotationStyles(uid, { + color: colorStr, + }); + + // Force re-render + const renderingEngine = cornerstoneViewportService.getRenderingEngine(); + renderingEngine.render(); + }, + }, + }); + }, /** * * @param props - containing the updates to apply @@ -2576,6 +2618,9 @@ function commandsModule({ renameMeasurement: { commandFn: actions.renameMeasurement, }, + changeMeasurementColor: { + commandFn: actions.changeMeasurementColor, + }, updateMeasurement: { commandFn: actions.updateMeasurement, }, diff --git a/extensions/cornerstone/src/initMeasurementService.ts b/extensions/cornerstone/src/initMeasurementService.ts index 84f370dc730..870432132da 100644 --- a/extensions/cornerstone/src/initMeasurementService.ts +++ b/extensions/cornerstone/src/initMeasurementService.ts @@ -353,7 +353,7 @@ const connectMeasurementServiceToTools = ({ }) => { const { measurementService, cornerstoneViewportService, viewportGridService } = servicesManager.services; - const { MEASUREMENT_REMOVED, MEASUREMENTS_CLEARED, MEASUREMENT_UPDATED, RAW_MEASUREMENT_ADDED } = + const { MEASUREMENT_REMOVED, MEASUREMENTS_CLEARED, MEASUREMENT_UPDATED, RAW_MEASUREMENT_ADDED, MEASUREMENT_ADDED } = measurementService.EVENTS; measurementService.subscribe(MEASUREMENTS_CLEARED, ({ measurements, trackingContext }) => { @@ -421,7 +421,7 @@ const connectMeasurementServiceToTools = ({ return; } - const { uid, label, isLocked, isVisible } = measurement; + const { uid, label, isLocked, isVisible, color } = measurement; const sourceAnnotation = annotation.state.getAnnotation(uid); const { data, metadata } = sourceAnnotation; @@ -440,9 +440,13 @@ const connectMeasurementServiceToTools = ({ // update the isVisible state annotation.visibility.setAnnotationVisibility(uid, isVisible); - // annotation.config.style.setAnnotationStyles(uid, { - // color: `rgb(${color[0]}, ${color[1]}, ${color[2]})`, - // }); + if (color) { + annotation.config.style.setAnnotationStyles(uid, { + color: `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${ + (color[3] !== undefined ? color[3] : 255) / 255.0 + })`, + }); + } // I don't like this but will fix later const renderingEngine = @@ -454,6 +458,24 @@ const connectMeasurementServiceToTools = ({ } ); + measurementService.subscribe( + MEASUREMENT_ADDED, + ({ source, measurement }) => { + if (!source || source.name !== CORNERSTONE_3D_TOOLS_SOURCE_NAME) { + return; + } + + const { uid, color } = measurement; + if (color) { + annotation.config.style.setAnnotationStyles(uid, { + color: `rgba(${color[0]}, ${color[1]}, ${color[2]}, ${ + (color[3] !== undefined ? color[3] : 255) / 255.0 + })`, + }); + } + } + ); + measurementService.subscribe( RAW_MEASUREMENT_ADDED, ({ source, measurement, data, dataSource }) => { @@ -515,6 +537,15 @@ const connectMeasurementServiceToTools = ({ }, }; annotationManager.addAnnotation(newAnnotation); + + if (measurement.color) { + annotation.config.style.setAnnotationStyles(measurement.uid, { + color: `rgba(${measurement.color[0]}, ${measurement.color[1]}, ${measurement.color[2]}, ${ + (measurement.color[3] !== undefined ? measurement.color[3] : 255) / 255.0 + })`, + }); + } + commandsManager.run('triggerCreateAnnotationMemo', { annotation: newAnnotation, FrameOfReferenceUID: newAnnotation.metadata.FrameOfReferenceUID, diff --git a/platform/core/src/services/MeasurementService/MeasurementService.test.js b/platform/core/src/services/MeasurementService/MeasurementService.test.js index 51ec9b66d23..fd73b543971 100644 --- a/platform/core/src/services/MeasurementService/MeasurementService.test.js +++ b/platform/core/src/services/MeasurementService/MeasurementService.test.js @@ -42,6 +42,8 @@ describe('MeasurementService.js', () => { { x: 1, y: 2 }, ], source: source, + color: [255, 255, 0, 255], + isDirty: undefined, }; // A measurement with various metadata missing (e.g. referenced SOPInstanceUID) that // would not typically get mapped my the MeasurementService possibly because it was diff --git a/platform/core/src/services/MeasurementService/MeasurementService.ts b/platform/core/src/services/MeasurementService/MeasurementService.ts index d91a61b990d..720f9603fb8 100644 --- a/platform/core/src/services/MeasurementService/MeasurementService.ts +++ b/platform/core/src/services/MeasurementService/MeasurementService.ts @@ -543,6 +543,7 @@ class MeasurementService extends PubSubService { const newMeasurement = { ...oldMeasurement, ...measurement, + color: measurement.color || oldMeasurement?.color || [255, 255, 0, 255], modifiedTimestamp: Math.floor(Date.now() / 1000), uid: internalUID, }; @@ -900,6 +901,12 @@ class MeasurementService extends PubSubService { return measurementUIDs.forEach(uid => this.toggleVisibilityMeasurement(uid, visibility)); } + /** + * Updates the color of a specific measurement and broadcasts the update event. + * + * @param {string} measurementUID The unique identifier of the measurement + * @param {number[]} color The new color as an RGBA array [r, g, b, a] + */ public updateColorMeasurement(measurementUID: string, color: number[]): void { const measurement = this.measurements.get(measurementUID);