11import { defineStore } from 'pinia' ;
2- import { reactive , watch , computed , MaybeRef , unref } from 'vue' ;
2+ import {
3+ reactive ,
4+ watch ,
5+ computed ,
6+ MaybeRef ,
7+ unref ,
8+ effectScope ,
9+ type EffectScope ,
10+ } from 'vue' ;
311import * as Comlink from 'comlink' ;
412import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray' ;
513import vtkImageData from '@kitware/vtk.js/Common/DataModel/ImageData' ;
@@ -8,6 +16,7 @@ import { WLAutoRanges, WL_HIST_BINS } from '@/src/constants';
816import { HistogramWorker } from '@/src/utils/histogram.worker' ;
917import { Maybe } from '@/src/types' ;
1018import { useImage } from '@/src/composables/useCurrentImage' ;
19+ import { ensureError } from '@/src/utils' ;
1120import { useImageCacheStore } from './image-cache' ;
1221import { useMessageStore } from './messages' ;
1322
@@ -18,13 +27,8 @@ export type ImageStats = {
1827} ;
1928
2029async function computeAutoRangeValues (
21- imageData : vtkImageData ,
22- isImageLoading : boolean
30+ imageData : vtkImageData
2331) : Promise < Record < string , [ number , number ] > > {
24- if ( isImageLoading || ! imageData ) {
25- return { } ;
26- }
27-
2832 const scalars = imageData . getPointData ( ) ?. getScalars ( ) ;
2933 if ( ! scalars ) {
3034 return { } ;
@@ -71,7 +75,7 @@ export const useImageStatsStore = defineStore('image-stats', () => {
7175 const imageCacheStore = useImageCacheStore ( ) ;
7276 const messageStore = useMessageStore ( ) ;
7377
74- const scalarRangeWatchers : Record < string , ( ) => void > = { } ;
78+ const statsEffectScope : Record < string , EffectScope > = { } ;
7579 const autoRangeComputations : Record <
7680 string ,
7781 Promise < Record < string , [ number , number ] > >
@@ -94,7 +98,7 @@ export const useImageStatsStore = defineStore('image-stats', () => {
9498 autoValues : Record < string , [ number , number ] >
9599 ) => {
96100 stats [ imageID ] = {
97- ...( stats [ imageID ] ?? { scalarMin : 0 , scalarMax : 0 } ) ,
101+ ...stats [ imageID ] ,
98102 autoRangeValues : autoValues ,
99103 } ;
100104 } ;
@@ -103,11 +107,7 @@ export const useImageStatsStore = defineStore('image-stats', () => {
103107 delete stats [ imageID ] ;
104108 } ;
105109
106- const setupImageWatcher = ( id : string ) => {
107- if ( scalarRangeWatchers [ id ] ) {
108- scalarRangeWatchers [ id ] ( ) ;
109- }
110-
110+ const setupImageWatchers = ( id : string ) => {
111111 const { imageData, isLoading : isImageLoading } = useImage (
112112 computed ( ( ) => id )
113113 ) ;
@@ -117,77 +117,68 @@ export const useImageStatsStore = defineStore('image-stats', () => {
117117 ) ;
118118 const scalarRange = vtkFieldRef ( activeScalars , 'range' ) ;
119119
120- scalarRangeWatchers [ id ] = watch (
120+ watch (
121121 scalarRange ,
122122 ( range ) => {
123- if ( imageData . value && range ) {
123+ if ( range ) {
124124 internalSetScalarRange ( id , range [ 0 ] , range [ 1 ] ) ;
125- } else {
126- internalRemoveStats ( id ) ;
127125 }
128126 } ,
129127 { immediate : true }
130128 ) ;
131129
132- const updateAutoRangeValuesIfNeeded = ( ) => {
133- const currentImageData = imageData . value ;
134- const currentIsLoading = isImageLoading . value ;
135-
136- if ( ! currentIsLoading && currentImageData ) {
137- if ( id in autoRangeComputations ) {
138- return ;
139- }
140- autoRangeComputations [ id ] = computeAutoRangeValues (
141- currentImageData ,
142- currentIsLoading
143- ) ;
144-
145- autoRangeComputations [ id ]
146- . then ( ( autoValues ) => {
147- if ( imageCacheStore . imageIds . includes ( id ) ) {
148- internalSetAutoRangeValues ( id , autoValues ) ;
149- }
150- } )
151- . catch ( ( error ) => {
152- console . error (
153- `[ImageStatsStore] Auto range computation for image ${ id } FAILED:` ,
154- error
155- ) ;
156- messageStore . addError (
157- `Auto range computation failed for image ${ id } ` ,
158- error instanceof Error ? error : String ( error )
159- ) ;
160- if ( imageCacheStore . imageIds . includes ( id ) ) {
161- internalSetAutoRangeValues ( id , { } ) ;
162- }
163- } )
164- . finally ( ( ) => {
165- delete autoRangeComputations [ id ] ;
166- } ) ;
167- } else if ( ! currentImageData ) {
168- internalSetAutoRangeValues ( id , { } ) ;
169- if ( id in autoRangeComputations ) {
130+ const triggerAutoRangeComputation = ( image : vtkImageData ) => {
131+ autoRangeComputations [ id ] = computeAutoRangeValues ( image ) ;
132+
133+ autoRangeComputations [ id ]
134+ . then ( ( autoValues ) => {
135+ if ( imageCacheStore . imageIds . includes ( id ) ) {
136+ // not deleted yet, save values
137+ internalSetAutoRangeValues ( id , autoValues ) ;
138+ }
139+ } )
140+ . catch ( ( error ) => {
141+ console . error (
142+ `[ImageStatsStore] Auto range computation for image ${ id } FAILED:` ,
143+ error
144+ ) ;
145+ messageStore . addError (
146+ `Auto range computation failed for image ${ id } ` ,
147+ ensureError ( error )
148+ ) ;
149+ } )
150+ . finally ( ( ) => {
170151 delete autoRangeComputations [ id ] ;
171- }
172- }
152+ } ) ;
173153 } ;
174154
175155 watch (
176156 [ imageData , isImageLoading ] ,
177157 ( ) => {
178- updateAutoRangeValuesIfNeeded ( ) ;
158+ if (
159+ isImageLoading . value ||
160+ ! imageData . value ||
161+ id in autoRangeComputations ||
162+ ( stats [ id ] && stats [ id ] . autoRangeValues )
163+ )
164+ return ;
165+ triggerAutoRangeComputation ( imageData . value ) ;
179166 } ,
180- { immediate : true , deep : false }
167+ { immediate : true }
181168 ) ;
182169 } ;
183170
184- const cleanupImageWatcher = ( id : string ) => {
171+ const cleanupImage = ( id : string ) => {
185172 internalRemoveStats ( id ) ;
186- if ( scalarRangeWatchers [ id ] ) {
187- scalarRangeWatchers [ id ] ( ) ;
188- delete scalarRangeWatchers [ id ] ;
173+
174+ if ( statsEffectScope [ id ] ) {
175+ statsEffectScope [ id ] . stop ( ) ;
176+ delete statsEffectScope [ id ] ;
177+ }
178+
179+ if ( id in autoRangeComputations ) {
180+ delete autoRangeComputations [ id ] ;
189181 }
190- delete autoRangeComputations [ id ] ;
191182 } ;
192183
193184 watch (
@@ -200,8 +191,17 @@ export const useImageStatsStore = defineStore('image-stats', () => {
200191 ( id ) => ! currentImageIds . includes ( id )
201192 ) ;
202193
203- removedIds . forEach ( cleanupImageWatcher ) ;
204- addedIds . forEach ( setupImageWatcher ) ;
194+ removedIds . forEach ( cleanupImage ) ;
195+ addedIds . forEach ( ( id ) => {
196+ if ( statsEffectScope [ id ] ) {
197+ cleanupImage ( id ) ;
198+ console . error ( `Setting up stats for ${ id } twice!` ) ;
199+ }
200+ statsEffectScope [ id ] = effectScope ( ) ;
201+ statsEffectScope [ id ] . run ( ( ) => {
202+ setupImageWatchers ( id ) ;
203+ } ) ;
204+ } ) ;
205205 } ,
206206 { immediate : true }
207207 ) ;
0 commit comments