From f9d10c9d6bed738fe9b7bcf15100f276dca2f1aa Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Fri, 16 Jul 2021 17:06:03 +0200 Subject: [PATCH] bugfix: hide pmap on clear view flag present --- src/glue.spec.ts | 4 +- src/util/fn.spec.ts | 55 ++++++- src/util/fn.ts | 32 +++- .../nehuba/layerCtrl.service/index.ts | 3 +- .../layerCtrl.service.spec.ts | 124 +++++++++++++- .../layerCtrl.service/layerCtrl.service.ts | 152 +++++++++++++++++- .../layerCtrl.service/layerCtrl.util.ts | 31 ++++ .../nehubaViewer/nehubaViewer.component.ts | 73 ++++++++- .../nehubaViewerGlue.component.ts | 140 ++-------------- 9 files changed, 469 insertions(+), 145 deletions(-) diff --git a/src/glue.spec.ts b/src/glue.spec.ts index 73f6013e0..0124829a8 100644 --- a/src/glue.spec.ts +++ b/src/glue.spec.ts @@ -2,15 +2,13 @@ import { TestBed, tick, fakeAsync, discardPeriodicTasks } from "@angular/core/te import { DatasetPreviewGlue, glueSelectorGetUiStatePreviewingFiles, glueActionRemoveDatasetPreview, datasetPreviewMetaReducer, glueActionAddDatasetPreview, GlueEffects, ClickInterceptorService } from "./glue" import { ACTION_TO_WIDGET_TOKEN, EnumActionToWidget } from "./widget" import { provideMockStore, MockStore } from "@ngrx/store/testing" -import { getRandomHex } from 'common/util' +import { getRandomHex, getIdObj } from 'common/util' import { EnumWidgetTypes, TypeOpenedWidget, uiActionSetPreviewingDatasetFiles, uiStatePreviewingDatasetFilesSelector } from "./services/state/uiState.store.helper" import { hot } from "jasmine-marbles" import { HttpClientTestingModule, HttpTestingController } from "@angular/common/http/testing" import { glueActionToggleDatasetPreview } from './glue' -import { getIdObj } from 'common/util' import { DS_PREVIEW_URL } from 'src/util/constants' import { NgLayersService } from "./ui/layerbrowser/ngLayerService.service" -import { EnumColorMapName } from "./util/colorMaps" import { GET_KGDS_PREVIEW_INFO_FROM_ID_FILENAME } from "./atlasComponents/databrowserModule/pure" import { viewerStateSelectedTemplateSelector } from "./services/state/viewerState/selectors" import { generalActionError } from "./services/stateStore.helper" diff --git a/src/util/fn.spec.ts b/src/util/fn.spec.ts index 1fe2e6469..bbdbff610 100644 --- a/src/util/fn.spec.ts +++ b/src/util/fn.spec.ts @@ -1,9 +1,9 @@ import { fakeAsync, tick } from '@angular/core/testing' import {} from 'jasmine' -import { cold, hot } from 'jasmine-marbles' -import { of } from 'rxjs' +import { hot } from 'jasmine-marbles' +import { Observable, of } from 'rxjs' import { switchMap } from 'rxjs/operators' -import { isSame, getGetRegionFromLabelIndexId, switchMapWaitFor } from './fn' +import { isSame, getGetRegionFromLabelIndexId, switchMapWaitFor, bufferUntil } from './fn' describe(`> util/fn.ts`, () => { @@ -78,4 +78,53 @@ describe(`> util/fn.ts`, () => { })) }) }) + + describe('> #bufferUntil', () => { + let src: Observable<number> + beforeEach(() => { + src = hot('a-b-c|', { + a: 1, + b: 2, + c: 3, + }) + }) + it('> outputs array of original emitted value', () => { + + expect( + src.pipe( + bufferUntil({ + condition: () => true, + leading: true, + }) + ) + ).toBeObservable( + hot('a-b-c|', { + a: [1], + b: [2], + c: [3], + }) + ) + }) + + it('> on condition success, emit all in array', () => { + + let counter = 0 + expect( + src.pipe( + bufferUntil({ + condition: () => { + counter ++ + return counter > 2 + }, + leading: true, + interval: 60000, + }) + ) + ).toBeObservable( + hot('----c|', { + c: [1,2,3], + }) + ) + }) + }) }) diff --git a/src/util/fn.ts b/src/util/fn.ts index cb92708d5..f4eb08ac4 100644 --- a/src/util/fn.ts +++ b/src/util/fn.ts @@ -1,5 +1,5 @@ import { deserialiseParcRegionId } from 'common/util' -import { interval, of } from 'rxjs' +import { interval, Observable, of } from 'rxjs' import { filter, mapTo, take } from 'rxjs/operators' export function isSame(o, n) { @@ -268,3 +268,33 @@ export function recursiveMutate<T>(arr: T[], getChildren: (obj: T) => T[], mutat ) } } + +export function bufferUntil<T>(opts: ISwitchMapWaitFor) { + const { condition, leading, interval: int = 160 } = opts + let buffer: T[] = [] + return (src: Observable<T>) => new Observable<T[]>(obs => { + const sub = interval(int).pipe( + filter(() => buffer.length > 0) + ).subscribe(() => { + if (condition()) { + obs.next(buffer) + buffer = [] + } + }) + src.subscribe( + val => { + if (leading && condition()) { + obs.next([...buffer, val]) + buffer = [] + } else { + buffer.push(val) + } + }, + err => obs.error(err), + () => { + obs.complete() + sub.unsubscribe() + } + ) + }) +} diff --git a/src/viewerModule/nehuba/layerCtrl.service/index.ts b/src/viewerModule/nehuba/layerCtrl.service/index.ts index 61975bcfe..05cbb34fe 100644 --- a/src/viewerModule/nehuba/layerCtrl.service/index.ts +++ b/src/viewerModule/nehuba/layerCtrl.service/index.ts @@ -1,5 +1,5 @@ export { - NehubaLayerControlService + NehubaLayerControlService, } from './layerCtrl.service' export { @@ -7,4 +7,5 @@ export { SET_COLORMAP_OBS, SET_LAYER_VISIBILITY, getRgb, + INgLayerInterface, } from './layerCtrl.util' diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts index ffb2443d9..3d2ae0f4f 100644 --- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.spec.ts @@ -1,12 +1,13 @@ import { fakeAsync, TestBed, tick } from "@angular/core/testing" import { MockStore, provideMockStore } from "@ngrx/store/testing" -import { viewerStateSelectedParcellationSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors" +import { viewerStateSelectedParcellationSelector, viewerStateSelectedRegionsSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors" import { NehubaLayerControlService } from "./layerCtrl.service" import * as layerCtrlUtil from '../constants' import { hot } from "jasmine-marbles" import { IColorMap } from "./layerCtrl.util" import { debounceTime } from "rxjs/operators" - +import { ngViewerSelectorClearView, ngViewerSelectorLayers } from "src/services/state/ngViewerState.store.helper" +const util = require('common/util') describe('> layerctrl.service.ts', () => { describe('> NehubaLayerControlService', () => { @@ -296,5 +297,124 @@ describe('> layerctrl.service.ts', () => { })) }) }) + + describe('> segmentVis$', () => { + const region1= { + ngId: 'ngid', + labelIndex: 1 + } + const region2= { + ngId: 'ngid', + labelIndex: 2 + } + beforeEach(() => { + mockStore.overrideSelector(viewerStateSelectedRegionsSelector, []) + mockStore.overrideSelector(ngViewerSelectorLayers, []) + mockStore.overrideSelector(ngViewerSelectorClearView, false) + mockStore.overrideSelector(viewerStateSelectedParcellationSelector, {}) + }) + + it('> by default, should return []', () => { + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: [] + }) + ) + }) + + describe('> if sel regions exist', () => { + beforeEach(() => { + mockStore.overrideSelector(viewerStateSelectedRegionsSelector, [ + region1, region2 + ]) + }) + + it('> default, should return encoded strings', () => { + mockStore.overrideSelector(viewerStateSelectedRegionsSelector, [ + region1, region2 + ]) + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: [`ngid#1`, `ngid#2`] + }) + ) + }) + + it('> if clearflag is true, then return []', () => { + + mockStore.overrideSelector(ngViewerSelectorClearView, true) + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: [] + }) + ) + }) + }) + + describe('> if non mixable layer exist', () => { + beforeEach(() => { + mockStore.overrideSelector(ngViewerSelectorLayers, [{ + mixability: 'nonmixable' + }]) + }) + + it('> default, should return null', () => { + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: null + }) + ) + }) + + it('> if regions selected, should still return null', () => { + + mockStore.overrideSelector(viewerStateSelectedRegionsSelector, [ + region1, region2 + ]) + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: null + }) + ) + }) + + describe('> if clear flag is set', () => { + beforeEach(() => { + mockStore.overrideSelector(ngViewerSelectorClearView, true) + }) + + it('> default, should return []', () => { + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: [] + }) + ) + }) + + it('> if reg selected, should return []', () => { + + mockStore.overrideSelector(viewerStateSelectedRegionsSelector, [ + region1, region2 + ]) + const service = TestBed.inject(NehubaLayerControlService) + expect(service.segmentVis$).toBeObservable( + hot('a', { + a: [] + }) + ) + }) + }) + }) + }) + + describe('> ngLayersController$', () => { + + }) }) }) diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts index f0d0d7257..a7df04ef1 100644 --- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.service.ts @@ -1,16 +1,17 @@ import { Inject, Injectable, OnDestroy, Optional } from "@angular/core"; import { select, Store } from "@ngrx/store"; import { BehaviorSubject, combineLatest, from, merge, Observable, of, Subject, Subscription } from "rxjs"; -import { filter, map, shareReplay, switchMap, tap } from "rxjs/operators"; -import { viewerStateSelectedParcellationSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors"; -import { getRgb, IColorMap } from "./layerCtrl.util"; +import { distinctUntilChanged, filter, map, shareReplay, switchMap, withLatestFrom } from "rxjs/operators"; +import { viewerStateSelectedParcellationSelector, viewerStateSelectedRegionsSelector, viewerStateSelectedTemplateSelector } from "src/services/state/viewerState/selectors"; +import { getRgb, IColorMap, INgLayerCtrl, INgLayerInterface, TNgLayerCtrl } from "./layerCtrl.util"; import { getMultiNgIdsRegionsLabelIndexMap } from "../constants"; import { IAuxMesh } from '../store' import { REGION_OF_INTEREST } from "src/util/interfaces"; import { TRegionDetail } from "src/util/siibraApiConstants/types"; import { EnumColorMapName } from "src/util/colorMaps"; import { getShader, PMAP_DEFAULT_CONFIG } from "src/util/constants"; -import { ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer } from "src/services/state/ngViewerState.store.helper"; +import { ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer, ngViewerSelectorClearView, ngViewerSelectorLayers } from "src/services/state/ngViewerState.store.helper"; +import { serialiseParcellationRegion } from 'common/util' export function getAuxMeshesAndReturnIColor(auxMeshes: IAuxMesh[]): IColorMap{ const returnVal: IColorMap = {} @@ -182,6 +183,31 @@ export class NehubaLayerControlService implements OnDestroy{ }) ) } + + this.sub.push( + this.ngLayers$.subscribe(({ ngLayers }) => { + this.ngLayersRegister.layers = ngLayers + }) + ) + + this.sub.push( + this.store$.pipe( + select(ngViewerSelectorClearView), + distinctUntilChanged() + ).subscribe(flag => { + const pmapLayer = this.ngLayersRegister.layers.find(l => l.name === NehubaLayerControlService.PMAP_LAYER_NAME) + if (!pmapLayer) return + const payload = { + type: 'update', + payload: { + [NehubaLayerControlService.PMAP_LAYER_NAME]: { + visible: !flag + } + } + } as TNgLayerCtrl<'update'> + this.manualNgLayersControl$.next(payload) + }) + ) } public activeColorMap: IColorMap @@ -216,4 +242,122 @@ export class NehubaLayerControlService implements OnDestroy{ return Array.from(ngIdSet) }) ) + + /** + * define when shown segments should be updated + */ + public segmentVis$: Observable<string[]> = combineLatest([ + /** + * selectedRegions + */ + this.store$.pipe( + select(viewerStateSelectedRegionsSelector) + ), + /** + * if layer contains non mixable layer + */ + this.store$.pipe( + select(ngViewerSelectorLayers), + map(layers => layers.findIndex(l => l.mixability === 'nonmixable') >= 0), + ), + /** + * clearviewqueue, indicating something is controlling colour map + * show all seg + */ + this.store$.pipe( + select(ngViewerSelectorClearView), + distinctUntilChanged() + ) + ]).pipe( + withLatestFrom(this.selectedParcellation$), + map(([[ regions, nonmixableLayerExists, clearViewFlag ], selParc]) => { + if (nonmixableLayerExists && !clearViewFlag) { + return null + } + const { ngId: defaultNgId } = selParc || {} + + /* selectedregionindexset needs to be updated regardless of forceshowsegment */ + const selectedRegionIndexSet = new Set<string>(regions.map(({ngId = defaultNgId, labelIndex}) => serialiseParcellationRegion({ ngId, labelIndex }))) + if (selectedRegionIndexSet.size > 0 && !clearViewFlag) { + return [...selectedRegionIndexSet] + } else { + return [] + } + }) + ) + + /** + * ngLayers controller + */ + + private ngLayersRegister: {layers: INgLayerInterface[]} = { + layers: [] + } + public removeNgLayers(layerNames: string[]) { + this.ngLayersRegister.layers + .filter(layer => layerNames?.findIndex(l => l === layer.name) >= 0) + .map(l => l.name) + .forEach(layerName => { + this.store$.dispatch(ngViewerActionRemoveNgLayer({ + layer: { + name: layerName + } + })) + }) + } + public addNgLayer(layers: INgLayerInterface[]){ + this.store$.dispatch(ngViewerActionAddNgLayer({ + layer: layers + })) + } + private ngLayers$ = this.store$.pipe( + select(ngViewerSelectorLayers), + map((ngLayers: INgLayerInterface[]) => { + const newLayers = ngLayers.filter(l => { + const registeredLayerNames = this.ngLayersRegister.layers.map(l => l.name) + return !registeredLayerNames.includes(l.name) + }) + const removeLayers = this.ngLayersRegister.layers.filter(l => { + const stateLayerNames = ngLayers.map(l => l.name) + return !stateLayerNames.includes(l.name) + }) + return { newLayers, removeLayers, ngLayers } + }), + shareReplay(1) + ) + private manualNgLayersControl$ = new Subject<TNgLayerCtrl<keyof INgLayerCtrl>>() + ngLayersController$: Observable<TNgLayerCtrl<keyof INgLayerCtrl>> = merge( + this.ngLayers$.pipe( + map(({ newLayers }) => newLayers), + filter(layers => layers.length > 0), + map(newLayers => { + + const newLayersObj: any = {} + newLayers.forEach(({ name, source, ...rest }) => newLayersObj[name] = { + ...rest, + source, + // source: getProxyUrl(source), + // ...getProxyOther({source}) + }) + + return { + type: 'add', + payload: newLayersObj + } as TNgLayerCtrl<'add'> + }) + ), + this.ngLayers$.pipe( + map(({ removeLayers }) => removeLayers), + filter(layers => layers.length > 0), + map(removeLayers => { + const removeLayerNames = removeLayers.map(v => v.name) + return { + type: 'remove', + payload: { names: removeLayerNames } + } as TNgLayerCtrl<'remove'> + }) + ), + this.manualNgLayersControl$, + ).pipe( + ) } diff --git a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts index 9ad22f97d..a815d3c68 100644 --- a/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts +++ b/src/viewerModule/nehuba/layerCtrl.service/layerCtrl.util.ts @@ -36,5 +36,36 @@ export function getRgb(labelIndex: number, region: { rgb?: [number, number, numb } } + +export interface INgLayerCtrl { + remove: { + names: string[] + } + add: { + [key: string]: INgLayerInterface + } + update: { + [key: string]: INgLayerInterface + } +} + +export type TNgLayerCtrl<T extends keyof INgLayerCtrl> = { + type: T + payload: INgLayerCtrl[T] +} + export const SET_COLORMAP_OBS = new InjectionToken<Observable<IColorMap>>('SET_COLORMAP_OBS') export const SET_LAYER_VISIBILITY = new InjectionToken<Observable<string[]>>('SET_LAYER_VISIBILITY') +export const SET_SEGMENT_VISIBILITY = new InjectionToken<Observable<string[]>>('SET_SEGMENT_VISIBILITY') +export const NG_LAYER_CONTROL = new InjectionToken<TNgLayerCtrl<keyof INgLayerCtrl>>('NG_LAYER_CONTROL') + +export interface INgLayerInterface { + name: string // displayName + source: string + mixability: string // base | mixable | nonmixable + annotation?: string // + id?: string // unique identifier + visible?: boolean + shader?: string + transform?: any +} diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts index d6e317036..23adf8d1c 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts @@ -4,7 +4,7 @@ import { debounceTime, filter, map, scan, startWith, mapTo, switchMap, take, ski import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service"; import { StateInterface as ViewerConfiguration } from "src/services/state/viewerConfig.store"; import { LoggingService } from "src/logging"; -import { getExportNehuba, getViewer, setNehubaViewer, switchMapWaitFor } from "src/util/fn"; +import { bufferUntil, getExportNehuba, getViewer, setNehubaViewer, switchMapWaitFor } from "src/util/fn"; import { NEHUBA_INSTANCE_INJTKN, scanSliceViewRenderFn } from "../util"; import { deserialiseParcRegionId } from 'common/util' import { IMeshesToLoad, SET_MESHES_TO_LOAD } from "../constants"; @@ -12,6 +12,7 @@ import { IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl. import '!!file-loader?context=third_party&name=main.bundle.js!export-nehuba/dist/min/main.bundle.js' import '!!file-loader?context=third_party&name=chunk_worker.bundle.js!export-nehuba/dist/min/chunk_worker.bundle.js' +import { INgLayerCtrl, NG_LAYER_CONTROL, SET_SEGMENT_VISIBILITY, TNgLayerCtrl } from "../layerCtrl.service/layerCtrl.util"; const NG_LANDMARK_LAYER_NAME = 'spatial landmark layer' const NG_USER_LANDMARK_LAYER_NAME = 'user landmark layer' @@ -151,6 +152,8 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { @Optional() @Inject(SET_MESHES_TO_LOAD) private injSetMeshesToLoad$: Observable<IMeshesToLoad>, @Optional() @Inject(SET_COLORMAP_OBS) private setColormap$: Observable<IColorMap>, @Optional() @Inject(SET_LAYER_VISIBILITY) private layerVis$: Observable<string[]>, + @Optional() @Inject(SET_SEGMENT_VISIBILITY) private segVis$: Observable<string[]>, + @Optional() @Inject(NG_LAYER_CONTROL) private layerCtrl$: Observable<TNgLayerCtrl<keyof INgLayerCtrl>>, ) { if (this.nehubaViewer$) { @@ -328,6 +331,56 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { } else { this.log.error(`SET_LAYER_VISIBILITY not provided`) } + + if (this.segVis$) { + this.ondestroySubscriptions.push( + this.segVis$.pipe().subscribe(val => { + // null === hide all seg + if (val === null) { + this.hideAllSeg() + return + } + // empty array === show all seg + if (val.length === 0) { + this.showAllSeg() + return + } + // show limited seg + this.showSegs(val) + }) + ) + } else { + this.log.error(`SET_SEGMENT_VISIBILITY not provided`) + } + + if (this.layerCtrl$) { + this.ondestroySubscriptions.push( + this.layerCtrl$.pipe( + bufferUntil(({ + condition: () => !!this.nehubaViewer?.ngviewer + })) + ).subscribe(messages => { + for (const message of messages) { + if (message.type === 'add') { + const p = message as TNgLayerCtrl<'add'> + this.loadLayer(p.payload) + } + if (message.type === 'remove') { + const p = message as TNgLayerCtrl<'remove'> + for (const name of p.payload.names){ + this.removeLayer({ name }) + } + } + if (message.type === 'update') { + const p = message as TNgLayerCtrl<'update'> + this.updateLayer(p.payload) + } + } + }) + ) + } else { + this.log.error(`NG_LAYER_CONTROL not provided`) + } } public numMeshesToBeLoaded: number = 0 @@ -391,12 +444,6 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { } private loadMeshes$: ReplaySubject<{labelIndicies: number[], layer: { name: string }}> = new ReplaySubject() - private loadMeshes(labelIndicies: number[], { name }) { - this.loadMeshes$.next({ - labelIndicies, - layer: { name }, - }) - } public mouseOverSegment: number | null public mouseOverLayer: {name: string, url: string}| null @@ -658,6 +705,18 @@ export class NehubaViewerUnit implements OnInit, OnDestroy { }) } + public updateLayer(layerObj: INgLayerCtrl['update']) { + + const viewer = this.nehubaViewer.ngviewer + + for (const layerName in layerObj) { + const layer = viewer.layerManager.getLayerByName(layerName) + if (!layer) continue + const { visible } = layerObj[layerName] + layer.setVisible(!!visible) + } + } + public hideAllSeg() { if (!this.nehubaViewer) { return } Array.from(this.multiNgIdsLabelIndexMap.keys()).forEach(ngId => { diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts index 370eb9242..2ac10c76f 100644 --- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts +++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts @@ -2,13 +2,13 @@ import { AfterViewInit, Component, ElementRef, EventEmitter, Inject, Input, OnChanges, OnDestroy, Optional, Output, SimpleChanges, ViewChild } from "@angular/core"; import { select, Store } from "@ngrx/store"; import { asyncScheduler, combineLatest, fromEvent, merge, Observable, of, Subject } from "rxjs"; -import { ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer, ngViewerActionToggleMax } from "src/services/state/ngViewerState/actions"; +import { ngViewerActionToggleMax } from "src/services/state/ngViewerState/actions"; import { ClickInterceptor, CLICK_INTERCEPTOR_INJECTOR } from "src/util"; import { uiStateMouseOverSegmentsSelector } from "src/services/state/uiState/selectors"; import { debounceTime, distinctUntilChanged, filter, map, mapTo, scan, shareReplay, startWith, switchMap, switchMapTo, take, tap, throttleTime } from "rxjs/operators"; import { viewerStateAddUserLandmarks, viewerStateChangeNavigation, viewerStateMouseOverCustomLandmark, viewerStateSelectRegionWithIdDeprecated, viewerStateSetSelectedRegions, viewreStateRemoveUserLandmarks } from "src/services/state/viewerState/actions"; -import { ngViewerSelectorLayers, ngViewerSelectorClearView, ngViewerSelectorPanelOrder, ngViewerSelectorPanelMode } from "src/services/state/ngViewerState/selectors"; -import { viewerStateCustomLandmarkSelector, viewerStateNavigationStateSelector, viewerStateSelectedRegionsSelector } from "src/services/state/viewerState/selectors"; +import { ngViewerSelectorPanelOrder, ngViewerSelectorPanelMode } from "src/services/state/ngViewerState/selectors"; +import { viewerStateCustomLandmarkSelector, viewerStateNavigationStateSelector } from "src/services/state/viewerState/selectors"; import { serialiseParcellationRegion } from 'common/util' import { ARIA_LABELS, IDS, QUICKTOUR_DESC } from 'common/constants' import { PANELS } from "src/services/state/ngViewerState/constants"; @@ -26,17 +26,7 @@ import { IQuickTourData } from "src/ui/quickTour/constrants"; import { NehubaLayerControlService, IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl.service"; import { switchMapWaitFor } from "src/util/fn"; import { INavObj } from "../navigation.service"; - -interface INgLayerInterface { - name: string // displayName - source: string - mixability: string // base | mixable | nonmixable - annotation?: string // - id?: string // unique identifier - visible?: boolean - shader?: string - transform?: any -} +import { NG_LAYER_CONTROL, SET_SEGMENT_VISIBILITY } from "../layerCtrl.service/layerCtrl.util"; @Component({ selector: 'iav-cmp-viewer-nehuba-glue', @@ -62,6 +52,16 @@ interface INgLayerInterface { useFactory: (layerCtrl: NehubaLayerControlService) => layerCtrl.visibleLayer$, deps: [ NehubaLayerControlService ] }, + { + provide: SET_SEGMENT_VISIBILITY, + useFactory: (layerCtrl: NehubaLayerControlService) => layerCtrl.segmentVis$, + deps: [ NehubaLayerControlService ] + }, + { + provide: NG_LAYER_CONTROL, + useFactory: (layerCtrl: NehubaLayerControlService) => layerCtrl.ngLayersController$, + deps: [ NehubaLayerControlService ] + }, NehubaLayerControlService ] }) @@ -82,9 +82,6 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnChanges, OnDestroy, A private onhoverSegments = [] private onDestroyCb: Function[] = [] private viewerUnit: NehubaViewerUnit - private ngLayersRegister: {layers: INgLayerInterface[]} = { - layers: [] - } private multiNgIdsRegionsLabelIndexMap: Map<string, Map<number, any>> @Input() @@ -223,16 +220,7 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnChanges, OnDestroy, A /* on selecting of new template, remove additional nglayers */ const baseLayerNames = Object.keys(tmpl.nehubaConfig.dataset.initialNgState.layers) - this.ngLayersRegister.layers - .filter(layer => baseLayerNames?.findIndex(l => l === layer.name) >= 0) - .map(l => l.name) - .forEach(layerName => { - this.store$.dispatch(ngViewerActionRemoveNgLayer({ - layer: { - name: layerName - } - })) - }) + this.layerCtrlService.removeNgLayers(baseLayerNames) } private async loadTmpl(_template: any, parcellation: any) { @@ -296,14 +284,11 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnChanges, OnDestroy, A ? null : layers[key].transform, } - this.ngLayersRegister.layers.push(layer) return layer }) + this.layerCtrlService.addNgLayer(dispatchLayers) this.newViewer$.next(true) - this.store$.dispatch(ngViewerActionAddNgLayer({ - layer: dispatchLayers - })) } @Output() @@ -401,99 +386,6 @@ export class NehubaGlueCmp implements IViewer<'nehuba'>, OnChanges, OnDestroy, A }) this.onDestroyCb.push(() => onhovSegSub.unsubscribe()) - /** - * subscribe to when ngLayer gets updated, and add/remove layer as necessary - */ - const addRemoveAdditionalLayerSub = this.store$.pipe( - select(ngViewerSelectorLayers), - switchMap(this.waitForNehuba.bind(this)), - ).subscribe((ngLayers: INgLayerInterface[]) => { - - const newLayers = ngLayers.filter(l => this.ngLayersRegister.layers?.findIndex(ol => ol.name === l.name) < 0) - const removeLayers = this.ngLayersRegister.layers.filter(l => ngLayers?.findIndex(nl => nl.name === l.name) < 0) - - if (newLayers?.length > 0) { - const newLayersObj: any = {} - newLayers.forEach(({ name, source, ...rest }) => newLayersObj[name] = { - ...rest, - source, - // source: getProxyUrl(source), - // ...getProxyOther({source}) - }) - - this.nehubaContainerDirective.nehubaViewerInstance.loadLayer(newLayersObj) - - /** - * previous miplementation... if nehubaViewer has not yet be instantiated, add it to the queue - * may no longer be necessary - * or implement proper queue'ing rather than ... this... half assed queue'ing - */ - // if (!this.nehubaViewer.nehubaViewer || !this.nehubaViewer.nehubaViewer.ngviewer) { - // this.nehubaViewer.initNiftiLayers.push(newLayersObj) - // } else { - // this.nehubaViewer.loadLayer(newLayersObj) - // } - this.ngLayersRegister.layers = this.ngLayersRegister.layers.concat(newLayers) - } - - if (removeLayers?.length > 0) { - removeLayers.forEach(l => { - if (this.nehubaContainerDirective.nehubaViewerInstance.removeLayer({ - name : l.name, - })) { - this.ngLayersRegister.layers = this.ngLayersRegister.layers.filter(rl => rl.name !== l.name) - } - }) - } - }) - this.onDestroyCb.push(() => addRemoveAdditionalLayerSub.unsubscribe()) - - /** - * define when shown segments should be updated - * TODO move to layerCtrl.service.ts - */ - const regSelectSub = combineLatest([ - /** - * selectedRegions - */ - this.store$.pipe( - select(viewerStateSelectedRegionsSelector) - ), - /** - * if layer contains non mixable layer - */ - this.store$.pipe( - select(ngViewerSelectorLayers), - map(layers => layers.findIndex(l => l.mixability === 'nonmixable') >= 0), - ), - /** - * clearviewqueue, indicating something is controlling colour map - * show all seg - */ - this.store$.pipe( - select(ngViewerSelectorClearView), - distinctUntilChanged() - ) - ]).pipe( - switchMap(this.waitForNehuba.bind(this)), - ).subscribe(([ regions, nonmixableLayerExists, clearViewFlag ]) => { - if (nonmixableLayerExists) { - this.nehubaContainerDirective.nehubaViewerInstance.hideAllSeg() - return - } - const { ngId: defaultNgId } = this.selectedParcellation || {} - - /* selectedregionindexset needs to be updated regardless of forceshowsegment */ - const selectedRegionIndexSet = new Set<string>(regions.map(({ngId = defaultNgId, labelIndex}) => serialiseParcellationRegion({ ngId, labelIndex }))) - - if (selectedRegionIndexSet.size > 0 && !clearViewFlag) { - this.nehubaContainerDirective.nehubaViewerInstance.showSegs([...selectedRegionIndexSet]) - } else { - this.nehubaContainerDirective.nehubaViewerInstance.showAllSeg() - } - }) - this.onDestroyCb.push(() => regSelectSub.unsubscribe()) - const perspectiveRenderEvSub = this.newViewer$.pipe( switchMapTo(fromEvent<CustomEvent>(this.el.nativeElement, 'perpspectiveRenderEvent').pipe( take(1) -- GitLab