From e03ea6e0002eaf6f015871bc0e5815039b6f60a9 Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Sun, 26 Aug 2018 07:51:26 +0200 Subject: [PATCH] WIP layer control --- src/atlasViewer/atlasViewer.component.ts | 18 +++--- src/atlasViewer/atlasViewer.template.html | 4 +- src/services/stateStore.service.ts | 12 +++- src/ui/databrowser/databrowser.component.ts | 5 -- .../dedicated/dedicated.component.ts | 47 +++++++------- .../dedicated/dedicated.template.html | 32 ++-------- src/ui/layerbrowser/layerbrowser.component.ts | 63 ++++++++++++++++++- .../layerbrowser/layerbrowser.template.html | 15 ++++- .../nehubaContainer.component.ts | 33 +++++----- .../nehubaViewer/nehubaViewer.component.ts | 12 ++-- 10 files changed, 145 insertions(+), 96 deletions(-) diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index 0aaf3777b..db6b45721 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -5,7 +5,6 @@ import { Observable, Subscription, combineLatest } from "rxjs"; import { map, filter, distinctUntilChanged } from "rxjs/operators"; import { AtlasViewerDataService } from "./atlasViewer.dataService.service"; import { WidgetServices } from "./widgetUnit/widgetService.service"; -import { DataBrowserUI } from "../ui/databrowser/databrowser.component"; import { LayoutMainSide } from "../layouts/mainside/mainside.component"; import { Chart } from 'chart.js' import { AtlasViewerConstantsServices, SUPPORT_LIBRARY_MAP } from "./atlasViewer.constantService.service"; @@ -13,7 +12,6 @@ import { BsModalService } from "ngx-bootstrap/modal"; import { ModalUnit } from "./modalUnit/modalUnit.component"; import { AtlasViewerURLService } from "./atlasViewer.urlService.service"; import { ToastComponent } from "../components/toast/toast.component"; -import { WidgetUnit } from "./widgetUnit/widgetUnit.component"; import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service"; import { PluginServices } from "./atlasViewer.pluginService.service"; @@ -218,8 +216,10 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { return } this.dedicatedViewComponentRef = this.toastContainer.createComponent(this.toastComponentFactory) - this.dedicatedViewComponentRef.instance.messageContainer.createEmbeddedView(this.dedicatedViewerToast) - this.dedicatedViewComponentRef.instance.dismissable = false + // this.dedicatedViewComponentRef.instance.messageContainer.createEmbeddedView(this.dedicatedViewerToast) + this.dedicatedViewComponentRef.instance.message = `hello` + this.dedicatedViewComponentRef.instance.dismissable = true + this.dedicatedViewComponentRef.instance.timeout = 1000 }) ) @@ -404,11 +404,11 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { } } - clearDedicatedView() { - this.store.dispatch({ - type: UNLOAD_DEDICATED_LAYER - }) - } + // clearDedicatedView() { + // this.store.dispatch({ + // type: UNLOAD_DEDICATED_LAYER + // }) + // } toggleSidePanel(panelName:string){ this.store.dispatch({ diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index c1b156795..41b53f945 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -139,10 +139,10 @@ </markdown-dom> <ng-template #dedicatedViewerToast> - <div *ngIf = "dedicatedView$ | async"> + <!-- <div *ngIf = "dedicatedView$ | async"> <span dedicatedviewertext>displaying : {{ dedicatedView$ | async | getFilenameFromPathname }}. </span> <span (click) = "clearDedicatedView()" class = "btn btn-link">clear</span> - </div> + </div> --> <div *ngIf = "!(dedicatedView$ | async)"> no special data is being displayed right now </div> diff --git a/src/services/stateStore.service.ts b/src/services/stateStore.service.ts index 0f49f1f49..909b93ef3 100644 --- a/src/services/stateStore.service.ts +++ b/src/services/stateStore.service.ts @@ -41,6 +41,7 @@ export interface ViewerStateInterface{ userLandmarks : UserLandmark[] navigation : any | null + dedicatedView : string[] } export interface AtlasAction extends Action{ @@ -49,7 +50,7 @@ export interface AtlasAction extends Action{ selectTemplate? : any selectParcellation? : any selectRegions? : any[] - dedicatedView? : string + dedicatedView? : string landmarks : UserLandmark[] @@ -175,12 +176,17 @@ export function uiState(state:UIStateInterface = {mouseOverSegment:null, focused export function viewerState(state:ViewerStateInterface,action:AtlasAction){ switch(action.type){ case LOAD_DEDICATED_LAYER: + const dedicatedView = state.dedicatedView + ? state.dedicatedView.concat(action.dedicatedView) + : [action.dedicatedView] return Object.assign({},state,{ - dedicatedView : action.dedicatedView + dedicatedView }) case UNLOAD_DEDICATED_LAYER: return Object.assign({},state,{ - dedicatedView : null + dedicatedView : state.dedicatedView + ? state.dedicatedView.filter(dv => dv !== action.dedicatedView) + : [] }) case NEWVIEWER: return Object.assign({},state,{ diff --git a/src/ui/databrowser/databrowser.component.ts b/src/ui/databrowser/databrowser.component.ts index 84f56fbd2..3e94701d8 100644 --- a/src/ui/databrowser/databrowser.component.ts +++ b/src/ui/databrowser/databrowser.component.ts @@ -270,11 +270,6 @@ export class DataBrowserUI implements OnDestroy,OnInit{ return `${file.name ? file.name : file.path}` } - handleDedicatedViewString = (dedicatedViewString:string|null)=>this.store.dispatch({ - type : dedicatedViewString ? LOAD_DEDICATED_LAYER : UNLOAD_DEDICATED_LAYER, - dedicatedView : dedicatedViewString - }) - dataWindowRegistry: Set<string> = new Set() handleTreeNodeClick(obj:{inputItem:any,node:TreeComponent},searchResult:any){ diff --git a/src/ui/fileviewer/dedicated/dedicated.component.ts b/src/ui/fileviewer/dedicated/dedicated.component.ts index ca9f143b8..73f0904dd 100644 --- a/src/ui/fileviewer/dedicated/dedicated.component.ts +++ b/src/ui/fileviewer/dedicated/dedicated.component.ts @@ -1,8 +1,9 @@ import { Component, OnDestroy, Input } from "@angular/core"; import { Store, select } from "@ngrx/store"; -import { DedicatedViewState, File, UNLOAD_DEDICATED_LAYER, LOAD_DEDICATED_LAYER } from "../../../services/stateStore.service"; +import { DedicatedViewState, File, ADD_NG_LAYER, REMOVE_NG_LAYER, NgViewerStateInterface } from "../../../services/stateStore.service"; import { Observable, Subscription } from "rxjs"; import { filter, map } from "rxjs/operators"; +import { getActiveColorMapFragmentMain } from "../../nehubaContainer/nehubaContainer.component"; @Component({ @@ -16,50 +17,44 @@ import { filter, map } from "rxjs/operators"; export class DedicatedViewer implements OnDestroy{ @Input() searchResultFile : File - private dedicatedView$ : Observable<string|null> - private dedicatedViewSubscription : Subscription - private dedicatedView : string | null + private ngLayers$ : Observable<NgViewerStateInterface> + private ngLayersSubscription : Subscription + private ngLayers : Set<string> = new Set() constructor(private store:Store<DedicatedViewState>){ - this.dedicatedView$ = this.store.pipe( - select('viewerState'), - filter(state=>typeof state !== 'undefined' && state !== null), - map(state=>state.dedicatedView) + this.ngLayers$ = this.store.pipe( + select('ngViewerState') ) - this.dedicatedViewSubscription = this.dedicatedView$.subscribe(url => this.dedicatedView = url) + this.ngLayersSubscription = this.ngLayers$.subscribe(layersInterface => this.ngLayers = new Set(layersInterface.layers.map(l => l.source))) } get isShowing(){ - return this.dedicatedView === `nifti://${this.searchResultFile.url}` - } - - get isObstructed(){ - return typeof this.dedicatedView !== 'undefined' && - this.dedicatedView !== null && - this.dedicatedView !== `nifti://${this.searchResultFile.url}` + return this.ngLayers.has(`nifti://${this.searchResultFile.url}`) } ngOnDestroy(){ - this.dedicatedViewSubscription.unsubscribe() + this.ngLayersSubscription.unsubscribe() } showDedicatedView(){ this.store.dispatch({ - type : LOAD_DEDICATED_LAYER, - dedicatedView : `nifti://${this.searchResultFile.url}` + type : ADD_NG_LAYER, + layer : { + name : this.searchResultFile.url, + source : `nifti://${this.searchResultFile.url}`, + mixability : 'nonmixable', + shader : getActiveColorMapFragmentMain() + } }) } removeDedicatedView(){ this.store.dispatch({ - type : UNLOAD_DEDICATED_LAYER, + type : REMOVE_NG_LAYER, + layer : { + name : this.searchResultFile.url + } }) } - - get nowShowing():string|null{ - return this.dedicatedView ? - this.dedicatedView.split('/')[this.dedicatedView.split('/').length-1]: - null - } } \ No newline at end of file diff --git a/src/ui/fileviewer/dedicated/dedicated.template.html b/src/ui/fileviewer/dedicated/dedicated.template.html index 254a40c54..4b4fd2b39 100644 --- a/src/ui/fileviewer/dedicated/dedicated.template.html +++ b/src/ui/fileviewer/dedicated/dedicated.template.html @@ -1,32 +1,10 @@ -<span *ngIf = "!isShowing" > - <span - *ngIf = "isObstructed"> - - <span class = "obstructedText"> - The viewer is currently displaying another dataset: - </span> - - <div class = "well"> - {{ nowShowing }} - </div> - <span class = "obstructedText"> - This dataset can be displayed after the currently shown dataset is cleared. - </span> - <span (click)="removeDedicatedView()" class = "btn btn-link"> - clear the currently shown dataset - </span> - </span> - - <span - (click) = "showDedicatedView()" - class = "btn btn-link" - *ngIf = "!isObstructed"> - - show this dataset in the viewer - </span> +<span + (click) = "showDedicatedView()" + *ngIf = "!isShowing" + class = "btn btn-link"> + show this dataset in the viewer </span> - <span (click) = "removeDedicatedView()" *ngIf = "isShowing" diff --git a/src/ui/layerbrowser/layerbrowser.component.ts b/src/ui/layerbrowser/layerbrowser.component.ts index 20a838992..0c011deb3 100644 --- a/src/ui/layerbrowser/layerbrowser.component.ts +++ b/src/ui/layerbrowser/layerbrowser.component.ts @@ -1,5 +1,9 @@ -import { Component, Input } from "@angular/core"; +import { Component, Input, OnDestroy } from "@angular/core"; import { AtlasViewerLayerInterface } from "../../util/pipes/newViewerDistinctViewToLayer.pipe"; +import { Observable, Subscription } from "rxjs"; +import { isDefined, ViewerStateInterface } from "../../services/stateStore.service"; +import { Store, select } from "@ngrx/store"; +import { filter, delay, distinctUntilChanged } from "rxjs/operators"; @Component({ @@ -8,9 +12,47 @@ import { AtlasViewerLayerInterface } from "../../util/pipes/newViewerDistinctVie styleUrls : [ './layerbrowser.style.css' ] }) -export class LayerBrowser{ +export class LayerBrowser implements OnDestroy{ @Input() layers : AtlasViewerLayerInterface[] = [] + ngLayers : NgLayerInterface[] = [] + newViewer$ : Observable<any> + subscription : Subscription + disposeHandler : any + + constructor(private store : Store<ViewerStateInterface>){ + this.newViewer$ = this.store.pipe( + select('viewerState'), + filter(state=>isDefined(state) && isDefined(state.templateSelected)), + distinctUntilChanged((o,n) => o.templateSelected.name === n.templateSelected.name) + ) + + this.subscription = this.newViewer$.pipe( + delay(0) + ).subscribe(() => { + this.layerChangedHandler() + this.disposeHandler = window['viewer'].layerManager.layersChanged.add(() => this.layerChangedHandler()) + window['viewer'].registerDisposer(this.disposeHandler) + }) + } + + ngOnDestroy(){ + this.disposeHandler() + this.subscription.unsubscribe() + } + + layerChangedHandler(){ + console.log('handle layer change',window['viewer'].layerManager.managedLayers) + + this.ngLayers = (window['viewer'].layerManager.managedLayers as any[]).map(obj => ({ + name : obj.name, + type : obj.initialSpecification.type, + source : obj.sourceUrl, + visible : obj.visible + }) as NgLayerInterface) + + } + public muteClass(layer:AtlasViewerLayerInterface):boolean{ if(this.layers.length === 0) return false @@ -18,4 +60,19 @@ export class LayerBrowser{ ? this.layers.some(l => l.type === 'nonmixable') : false } -} \ No newline at end of file + + public classVisible(layer:NgLayerInterface):boolean{ + return typeof layer.visible === 'undefined' + ? true + : layer.visible + } +} + +interface NgLayerInterface{ + name : string + visible : boolean + source : string + type : string // image | segmentation | etc ... + transform? : [[number, number, number, number],[number, number, number, number],[number, number, number, number],[number, number, number, number]] | null + // colormap : string +} diff --git a/src/ui/layerbrowser/layerbrowser.template.html b/src/ui/layerbrowser/layerbrowser.template.html index d98b3f89d..26c068997 100644 --- a/src/ui/layerbrowser/layerbrowser.template.html +++ b/src/ui/layerbrowser/layerbrowser.template.html @@ -1,5 +1,18 @@ <div container> <panel-component + [ngClass] = "{'muted' : !classVisible(ngLayer)}" + class = "layerContainer" + *ngFor = "let ngLayer of ngLayers"> + + <div heading> + {{ ngLayer.name }} : {{ ngLayer.type }} + </div> + + <div body> + {{ ngLayer.source }} + </div> + </panel-component> + <!-- <panel-component [ngClass] = "{'muted' : muteClass(layer)}" class = "layerContainer" *ngFor = "let layer of layers"> @@ -10,5 +23,5 @@ <div body> {{ layer.url }} </div> - </panel-component> + </panel-component> --> </div> \ No newline at end of file diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts index dfaff17a3..8c955e73b 100644 --- a/src/ui/nehubaContainer/nehubaContainer.component.ts +++ b/src/ui/nehubaContainer/nehubaContainer.component.ts @@ -30,7 +30,7 @@ export class NehubaContainer implements OnInit, OnDestroy{ private newViewer$ : Observable<any> private selectedParcellation$ : Observable<any> private selectedRegions$ : Observable<any[]> - private dedicatedView$ : Observable<string|null> + private dedicatedView$ : Observable<string[]|null> private fetchedSpatialDatasets$ : Observable<any[]> private userLandmarks$ : Observable<UserLandmark[]> public onHoverSegmentName$ : Observable<string> @@ -316,6 +316,7 @@ export class NehubaContainer implements OnInit, OnDestroy{ if(newLayers.length > 0){ const newLayersObj:any = {} newLayers.forEach(obj => newLayersObj[obj.name] = obj) + debugger this.nehubaViewer.loadLayer(newLayersObj) this.ngLayersRegister.layers = this.ngLayersRegister.layers.concat(newLayers) } @@ -356,14 +357,13 @@ export class NehubaContainer implements OnInit, OnDestroy{ /* TODO abit hacky. test what happens when: select dedicated view, then change template... check ngLayerRegister */ if(dedicatedView){ - const dedicatedViewLayer = { - name : 'niftiViewer', - source : dedicatedView, - visible: true, + this.ngLayersRegister.layers = this.ngLayersRegister.layers.concat(dedicatedView.map((layer, index) => ({ + name : `dedicatedview-${index}`, + source : layer, + visible : true, mixability : 'nonmixable', - transform:null - } - this.ngLayersRegister.layers.push(dedicatedViewLayer) + transform : null + }))) } }) @@ -418,17 +418,18 @@ export class NehubaContainer implements OnInit, OnDestroy{ this.selectedParcellation = parcellation } - private handleDedicatedView(dedicatedView:string){ - this.handleNifti(dedicatedView) - } - - private handleNifti(url:string|null){ + private handleDedicatedView(dedicatedView:string[]){ if(!this.nehubaViewer || !this.nehubaViewer.nehubaViewer){ /* if nehubaviewer has not yet been initialised for one reason or another, return */ console.warn('handling nifti view, nehubaviewer has not yet been initialised.') return } - if(url === null){ + + /* for now */ + return + if(dedicatedView.length === 0){ + + /* remove ng layer (?) */ this.store.dispatch({ type : REMOVE_NG_LAYER, layer : { @@ -459,8 +460,8 @@ export class NehubaContainer implements OnInit, OnDestroy{ this.store.dispatch({ type : ADD_NG_LAYER, layer : { - name : 'niftiViewer', - source : url, + name : null, + source : dedicatedView, mixability : 'nonmixable', shader : getActiveColorMapFragmentMain() } diff --git a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts index 98c5cdea9..82d79e510 100644 --- a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts +++ b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts @@ -20,7 +20,7 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{ /* only used to set initial navigation state */ initNav : any initRegions : any[] - initDedicatedView : string + initDedicatedView : string[] config : any @@ -327,13 +327,17 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{ if(this.initDedicatedView){ this.hideAllSeg() - this.loadLayer({ - niftiViewer : { + const _ = {} + + this.initDedicatedView.forEach((layer,index) => { + _[`dedicatedview-${index}`] = { type : 'image', - source : this.initDedicatedView, + source : layer, shader : getActiveColorMapFragmentMain() } }) + + this.loadLayer(_) } this._s8$ = this.nehubaViewer.mouseOver.segment.subscribe(({segment})=>{ -- GitLab