diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index db6b45721de1820e2f53043348e1cd2c197899c8..95e78c5deacdae28c9424407aefefdabb27d3772 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -1,8 +1,8 @@ import { Component, HostBinding, ViewChild, ViewContainerRef, ComponentFactoryResolver, ComponentFactory, OnDestroy, ElementRef, Injector, ComponentRef, AfterViewInit, OnInit, TemplateRef, HostListener, Renderer2 } from "@angular/core"; import { Store, select } from "@ngrx/store"; -import { ViewerStateInterface, OPEN_SIDE_PANEL, CLOSE_SIDE_PANEL, isDefined,UNLOAD_DEDICATED_LAYER, FETCHED_SPATIAL_DATA, UPDATE_SPATIAL_DATA, TOGGLE_SIDE_PANEL } from "../services/stateStore.service"; -import { Observable, Subscription, combineLatest } from "rxjs"; -import { map, filter, distinctUntilChanged } from "rxjs/operators"; +import { ViewerStateInterface, OPEN_SIDE_PANEL, CLOSE_SIDE_PANEL, isDefined,UNLOAD_DEDICATED_LAYER, FETCHED_SPATIAL_DATA, UPDATE_SPATIAL_DATA, TOGGLE_SIDE_PANEL, NgViewerStateInterface } from "../services/stateStore.service"; +import { Observable, Subscription } from "rxjs"; +import { map, filter, distinctUntilChanged, delay } from "rxjs/operators"; import { AtlasViewerDataService } from "./atlasViewer.dataService.service"; import { WidgetServices } from "./widgetUnit/widgetService.service"; import { LayoutMainSide } from "../layouts/mainside/mainside.component"; @@ -38,7 +38,7 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { @ViewChild('databrowser', { read: ElementRef }) databrowser: ElementRef @ViewChild('temporaryContainer', { read: ViewContainerRef }) temporaryContainer: ViewContainerRef @ViewChild('toastContainer', { read: ViewContainerRef }) toastContainer: ViewContainerRef - @ViewChild('dedicatedViewerToast', { read: TemplateRef }) dedicatedViewerToast: TemplateRef<any> + // @ViewChild('dedicatedViewerToast', { read: TemplateRef }) dedicatedViewerToast: TemplateRef<any> @ViewChild('floatingMouseContextualContainer', { read: ViewContainerRef }) floatingMouseContextualContainer: ViewContainerRef @ViewChild('pluginFactory', { read: ViewContainerRef }) pluginViewContainerRef: ViewContainerRef @ViewChild(LayoutMainSide) layoutMainSide: LayoutMainSide @@ -51,19 +51,20 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { meetsRequirement: boolean = true toastComponentFactory: ComponentFactory<ToastComponent> - // databrowserComponentFactory: ComponentFactory<DataBrowserUI> - // databrowserComponentRef: ComponentRef<DataBrowserUI> - // private databrowserHostComponentRef: ComponentRef<WidgetUnit> private dedicatedViewComponentRef: ComponentRef<ToastComponent> public sidePanelView$: Observable<string|null> private newViewer$: Observable<any> public selectedRegions$: Observable<any[]> - public layersLoaded$: Observable<any[]> public dedicatedView$: Observable<string | null> public onhoverSegment$: Observable<string> private subscriptions: Subscription[] = [] + /* handlers for nglayer */ + public ngLayerNames$ : Observable<any> + public ngLayers : NgLayerInterface[] + private disposeHandler : any + constructor( private pluginService: PluginServices, private rd2: Renderer2, @@ -74,12 +75,17 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { private constantsService: AtlasViewerConstantsServices, public urlService: AtlasViewerURLService, public apiService: AtlasViewerAPIServices, - private modalService: BsModalService, - private injector: Injector + private modalService: BsModalService ) { this.toastComponentFactory = this.cfr.resolveComponentFactory(ToastComponent) - // this.databrowserComponentFactory = this.cfr.resolveComponentFactory(DataBrowserUI) - // this.databrowserComponentRef = this.databrowserComponentFactory.create(this.injector) + + this.ngLayerNames$ = this.store.pipe( + select('viewerState'), + filter(state => isDefined(state) && isDefined(state.templateSelected)), + distinctUntilChanged((o,n) => o.templateSelected.name === n.templateSelected.name), + map(state => Object.keys(state.templateSelected.nehubaConfig.dataset.initialNgState.layers)), + delay(0) + ) this.sidePanelView$ = this.store.pipe( select('uiState'), @@ -119,11 +125,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { ''), distinctUntilChanged() ) - - this.layersLoaded$ = combineLatest( - this.newViewer$, - this.dedicatedView$ - ) } ngOnInit() { @@ -216,13 +217,20 @@ 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.message = `hello` this.dedicatedViewComponentRef.instance.dismissable = true this.dedicatedViewComponentRef.instance.timeout = 1000 }) ) + this.subscriptions.push( + this.ngLayerNames$.subscribe(() => { + this.ngLayersChangeHandler() + this.disposeHandler = window['viewer'].layerManager.layersChanged.add(() => this.ngLayersChangeHandler()) + window['viewer'].registerDisposer(this.disposeHandler) + }) + ) + this.subscriptions.push( this.newViewer$.subscribe(template => { this.darktheme = this.meetsRequirement ? @@ -239,19 +247,6 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { totalResults : 0 }) - // if (this.databrowserHostComponentRef) { - // // this.databrowserHostComponentRef.instance.container.detach(0) - // // this.temporaryContainer.insert(this.databrowserComponentRef.hostView) - // } else { - // this.databrowserHostComponentRef = - // this.widgetServices.addNewWidget(this.databrowserComponentRef, { - // title: 'Data Browser', - // exitable: false, - // state: 'docked', - // persistency:true - // }) - // } - this.widgetServices.clearAllWidgets() }) ) @@ -379,6 +374,18 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { return true } + ngLayersChangeHandler(){ + + 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) + } + /* obsolete soon */ manualPanelToggle(show: boolean) { this.store.dispatch({ @@ -427,4 +434,13 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit { get floatingMouseContextualContainerTransform() { return `translate(${this.mousePos[0]}px,${this.mousePos[1]}px)` } -} \ No newline at end of file +} + +export 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/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index 41b53f945899d4dc413c5e7b251518536878136a..c6400672433f45fbe619ff62e4773d69d35022e2 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -37,7 +37,11 @@ Layer Browser </div> <div body> - <layer-browser [layers] = "layersLoaded$ | async | newViewerDisctinctViewToLayer"></layer-browser> + <layer-browser + () + [lockedLayers] = "ngLayerNames$ | async" + [ngLayers] = "ngLayers"> + </layer-browser> </div> </panel-component> </div> @@ -85,15 +89,15 @@ <span placement = "left" - [tooltip] = "!(layersLoaded$ | async | newViewerDisctinctViewToLayer) ? '' : (((layersLoaded$ | async | newViewerDisctinctViewToLayer).length === 0 ? 'No' : (layersLoaded$ | async | newViewerDisctinctViewToLayer).length) + ' loaded layer' + ((layersLoaded$ | async | newViewerDisctinctViewToLayer).length > 1 ? 's' : ''))" + [tooltip] = "!ngLayers ? '' : ((ngLayers.length === 0 ? 'No' : ngLayers.length) + ' loaded layer' + (ngLayers.length > 1 ? 's' : ''))" [ngClass] = "{'active-tab' : (sidePanelView$ | async) === 'ngLayer'}" (click) = "toggleSidePanel('ngLayer')" class = "tabContainer"> - <span [@newEvent] = "layersLoaded$ | async | newViewerDisctinctViewToLayer" class = "highlightContainer"> + <span [@newEvent] = "ngLayers" class = "highlightContainer"> </span> <i class = "glyphicon glyphicon-list"></i> - <span class = "badge" *ngIf = "(layersLoaded$ | async | newViewerDisctinctViewToLayer).length > 0"> - {{ (layersLoaded$ | async | newViewerDisctinctViewToLayer).length }} + <span class = "badge" *ngIf = "ngLayers && ngLayers.length > 0"> + {{ ngLayers.length }} </span> </span> diff --git a/src/res/css/extra_styles.css b/src/res/css/extra_styles.css index f11dcfe934700c44d909b079bcb5cb075205c1ed..3a880eccf9974a2ea3d0aaa301712996d8e74209 100644 --- a/src/res/css/extra_styles.css +++ b/src/res/css/extra_styles.css @@ -135,3 +135,8 @@ markdown-dom pre code { background-color:rgba(150,150,0,0.5); } + +.glyphicon-none +{ + width:1em; +} \ No newline at end of file diff --git a/src/ui/layerbrowser/layerbrowser.component.ts b/src/ui/layerbrowser/layerbrowser.component.ts index 0c011deb385eb0589b904b074478d28da8cd3434..cf297a564a190d3d20e3f7489d6df4c32c9c034e 100644 --- a/src/ui/layerbrowser/layerbrowser.component.ts +++ b/src/ui/layerbrowser/layerbrowser.component.ts @@ -1,10 +1,5 @@ -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"; - +import { Component, Input, Output, EventEmitter } from "@angular/core"; +import { NgLayerInterface } from "../../atlasViewer/atlasViewer.component"; @Component({ selector : 'layer-browser', @@ -12,67 +7,33 @@ import { filter, delay, distinctUntilChanged } from "rxjs/operators"; styleUrls : [ './layerbrowser.style.css' ] }) -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) +export class LayerBrowser { - 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) - - } + @Input() ngLayers : NgLayerInterface[] = [] + @Input() lockedLayers : string[] = [] - public muteClass(layer:AtlasViewerLayerInterface):boolean{ - if(this.layers.length === 0) - return false - return layer.type === 'mixable' - ? this.layers.some(l => l.type === 'nonmixable') - : false - } + @Output() removeLayerEmitter : EventEmitter<string> = new EventEmitter() - public classVisible(layer:NgLayerInterface):boolean{ + public classVisible(layer:any):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 + checkLocked(ngLayer:NgLayerInterface):boolean{ + if(!this.lockedLayers){ + /* locked layer undefined. always return true for locked layer check */ + return true + }else + return this.lockedLayers.findIndex(l => l === ngLayer.name) >= 0 + } + + removeLayer(layer:any){ + if(this.checkLocked(layer)){ + console.warn('this layer is locked and cannot be removed') + }else{ + console.log(layer) + // this.removeLayerEmitter.emit() + } + } } diff --git a/src/ui/layerbrowser/layerbrowser.style.css b/src/ui/layerbrowser/layerbrowser.style.css index 4c22988791e78455376f8b797d1e632328be7b73..19ba552066ec297705717154ad777ce7e911c6e0 100644 --- a/src/ui/layerbrowser/layerbrowser.style.css +++ b/src/ui/layerbrowser/layerbrowser.style.css @@ -21,6 +21,17 @@ div[body] .muted { - text-decoration: line-through; opacity : 0.5; +} + +.muted-text +{ + text-decoration: line-through; +} + +.layerContainer +{ + display: flex; + flex-direction: row; + align-items: center; } \ No newline at end of file diff --git a/src/ui/layerbrowser/layerbrowser.template.html b/src/ui/layerbrowser/layerbrowser.template.html index 26c068997bc9983a155c0797a39121f668e22327..06bdeb651bc0b051eacf34165119a84fb6c887df 100644 --- a/src/ui/layerbrowser/layerbrowser.template.html +++ b/src/ui/layerbrowser/layerbrowser.template.html @@ -1,27 +1,47 @@ <div container> - <panel-component - [ngClass] = "{'muted' : !classVisible(ngLayer)}" - class = "layerContainer" + <div + class="layerContainer" *ngFor = "let ngLayer of ngLayers"> - <div heading> - {{ ngLayer.name }} : {{ ngLayer.type }} - </div> + <div> + <i + class = "glyphicon" + [ngClass] = "ngLayer.visible ? 'glyphicon-eye-open' : 'glyphicon-eye-close'"> - <div body> - {{ ngLayer.source }} + </i> </div> - </panel-component> - <!-- <panel-component - [ngClass] = "{'muted' : muteClass(layer)}" - class = "layerContainer" - *ngFor = "let layer of layers"> - - <div heading> - {{ layer.name }} + <div> + <i + container = "body" + placement = "bottom" + [tooltip] = "ngLayer.type === 'segmentation' ? null : 'only segmentation layer can hide/show segments'" + class = "glyphicon" + [ngClass] = "ngLayer.type === 'segmentation' ? 'glyphicon-th-large' : 'glyphicon-lock muted' "> + + </i> </div> - <div body> - {{ layer.url }} + <div> + <i + (click) = "removeLayer(ngLayer)" + container = "body" + placement = "bottom" + [tooltip] = "checkLocked(ngLayer) ? 'base layers cannot be removed' : null" + class = "glyphicon" + [ngClass] = "checkLocked(ngLayer) ? 'glyphicon-lock muted' : 'glyphicon-remove-circle'"> + + </i> </div> - </panel-component> --> + + <panel-component + [ngClass] = "{'muted-text muted' : !classVisible(ngLayer)}"> + + <div heading> + {{ ngLayer.name }} : {{ ngLayer.type }} + </div> + + <div body> + {{ ngLayer.source }} + </div> + </panel-component> + </div> </div> \ No newline at end of file diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts index 8c955e73bd32a578500254d0dd7884fe741a2122..086053ae0000db47df6ec0a11d3363f26660b8da 100644 --- a/src/ui/nehubaContainer/nehubaContainer.component.ts +++ b/src/ui/nehubaContainer/nehubaContainer.component.ts @@ -316,7 +316,6 @@ 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) }