From 5ea4996addfe0fee8f2f4bdb62d793ba55dfcd86 Mon Sep 17 00:00:00 2001 From: Xiao Gui <xgui3783@gmail.com> Date: Fri, 8 Jan 2021 18:40:30 +0100 Subject: [PATCH] chore: add touch contrl --- .../nehubaContainer.component.ts | 1181 ----------------- .../nehubaContainer/nehubaContainer.style.css | 182 --- .../nehubaContainer.template.html | 844 ------------ src/viewerModule/module.ts | 305 ----- .../nehubaViewerGlue.component.ts | 4 +- .../nehubaViewerGlue.template.html | 18 +- 6 files changed, 16 insertions(+), 2518 deletions(-) delete mode 100644 src/ui/nehubaContainer/nehubaContainer.component.ts delete mode 100644 src/ui/nehubaContainer/nehubaContainer.style.css delete mode 100644 src/ui/nehubaContainer/nehubaContainer.template.html diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts deleted file mode 100644 index 3582fc984..000000000 --- a/src/ui/nehubaContainer/nehubaContainer.component.ts +++ /dev/null @@ -1,1181 +0,0 @@ -// import { Component, ElementRef, Input, OnChanges, OnDestroy, OnInit, ViewChild, ChangeDetectorRef, Output, EventEmitter, Inject, Optional } from "@angular/core"; -// import { select, Store } from "@ngrx/store"; -// import { combineLatest, fromEvent, merge, Observable, of, Subscription, timer, asyncScheduler, BehaviorSubject, Subject } from "rxjs"; -// import { buffer, debounceTime, distinctUntilChanged, filter, map, mapTo, scan, shareReplay, skip, startWith, switchMap, switchMapTo, take, tap, withLatestFrom, delayWhen, throttleTime } from "rxjs/operators"; -// import { trigger, state, style, animate, transition } from '@angular/animations' -// import { MatDrawer } from "@angular/material/sidenav"; - -// import { LoggingService } from "src/logging"; -// import { -// CHANGE_NAVIGATION, -// getMultiNgIdsRegionsLabelIndexMap, -// getNgIds, -// ILandmark, -// IOtherLandmarkGeometry, -// IPlaneLandmarkGeometry, -// IPointLandmarkGeometry, -// isDefined, -// MOUSE_OVER_LANDMARK, -// NgViewerStateInterface -// } from "src/services/stateStore.service"; - -// import { getExportNehuba, isSame } from "src/util/fn"; -// import { API_SERVICE_SET_VIEWER_HANDLE_TOKEN, IUserLandmark } from "src/atlasViewer/atlasViewer.apiService.service"; -// import { NehubaViewerUnit } from "./nehubaViewer/nehubaViewer.component"; -// import { compareLandmarksChanged } from "src/util/constants"; -// import { PureContantService } from "src/util"; -// import { ARIA_LABELS, IDS, CONST } from 'common/constants' -// import { serialiseParcellationRegion } from "common/util" -// import { ngViewerActionSetPerspOctantRemoval, PANELS, ngViewerActionToggleMax, ngViewerActionAddNgLayer, ngViewerActionRemoveNgLayer } from "src/services/state/ngViewerState.store.helper"; -// import { viewerStateSelectRegionWithIdDeprecated, viewerStateAddUserLandmarks, viewreStateRemoveUserLandmarks, viewerStateCustomLandmarkSelector, viewerStateSelectedParcellationSelector, viewerStateSelectedTemplateSelector, viewerStateSelectedRegionsSelector } from 'src/services/state/viewerState.store.helper' -// import { SwitchDirective } from "src/util/directives/switch.directive"; -// import { -// viewerStateDblClickOnViewer, -// } from "src/services/state/viewerState.store.helper"; - -// import { getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree, calculateSliceZoomFactor, scanSliceViewRenderFn as scanFn, takeOnePipe } from "./util"; -// import { NehubaViewerContainerDirective } from "./nehubaViewerInterface/nehubaViewerInterface.directive"; -// import { ITunableProp } from "./mobileOverlay/mobileOverlay.component"; -// import { viewerStateMouseOverCustomLandmark } from "src/services/state/viewerState/actions"; -// import { ngViewerSelectorNehubaReady, ngViewerSelectorOctantRemoval, ngViewerSelectorPanelMode, ngViewerSelectorPanelOrder } from "src/services/state/ngViewerState/selectors"; -// import { REGION_OF_INTEREST } from "src/util/interfaces"; -// import { uiActionHideAllDatasets, uiActionHideDatasetWithId } from "src/services/state/uiState/actions"; - -// const { MESH_LOADING_STATUS } = IDS - -// const sortByFreshness: (acc: any[], curr: any[]) => any[] = (acc, curr) => { - -// const getLayerName = ({layer} = {layer: {}}) => { -// const { name } = layer as any -// return name -// } - -// const newEntries = (curr && curr.filter(entry => { -// const name = getLayerName(entry) -// return acc.map(getLayerName).indexOf(name) < 0 -// })) || [] - -// const entryChanged: (itemPrevState, newArr) => boolean = (itemPrevState, newArr) => { -// const layerName = getLayerName(itemPrevState) -// const { segment } = itemPrevState -// const foundItem = newArr?.find((_item) => -// getLayerName(_item) === layerName) - -// if (foundItem) { -// const { segment: foundSegment } = foundItem -// return segment !== foundSegment -// } else { -// /** -// * if item was not found in the new array, meaning hovering nothing -// */ -// return segment !== null -// } -// } - -// const getItemFromLayerName = (item, arr) => { -// const foundItem = arr?.find(i => getLayerName(i) === getLayerName(item)) -// return foundItem -// ? foundItem -// : { -// layer: item.layer, -// segment: null, -// } -// } - -// const getReduceExistingLayers = (newArr) => ([changed, unchanged], _curr) => { -// const changedFlag = entryChanged(_curr, newArr) -// return changedFlag -// ? [ changed.concat( getItemFromLayerName(_curr, newArr) ), unchanged ] -// : [ changed, unchanged.concat(_curr) ] -// } - -// /** -// * now, for all the previous layers, separate into changed and unchanged layers -// */ -// const [changed, unchanged] = acc.reduce(getReduceExistingLayers(curr), [[], []]) -// return [...newEntries, ...changed, ...unchanged] -// } - -// const { -// ZOOM_IN, -// ZOOM_OUT, -// TOGGLE_FRONTAL_OCTANT, -// TOGGLE_SIDE_PANEL, -// EXPAND, -// COLLAPSE, -// ADDITIONAL_VOLUME_CONTROL, -// } = ARIA_LABELS - -// @Component({ -// selector : 'ui-nehuba-container', -// templateUrl : './nehubaContainer.template.html', -// styleUrls : [ -// `./nehubaContainer.style.css`, -// ], -// animations: [ -// trigger('openClose', [ -// state('open', style({ -// transform: 'translateY(0)', -// opacity: 1 -// })), -// state('closed', style({ -// transform: 'translateY(-100vh)', -// opacity: 0 -// })), -// transition('open => closed', [ -// animate('200ms cubic-bezier(0.35, 0, 0.25, 1)') -// ]), -// transition('closed => open', [ -// animate('200ms cubic-bezier(0.35, 0, 0.25, 1)') -// ]) -// ]), -// trigger('openCloseAnchor', [ -// state('open', style({ -// transform: 'translateY(0)' -// })), -// state('closed', style({ -// transform: 'translateY(100vh)' -// })), -// transition('open => closed', [ -// animate('200ms cubic-bezier(0.35, 0, 0.25, 1)') -// ]), -// transition('closed => open', [ -// animate('200ms cubic-bezier(0.35, 0, 0.25, 1)') -// ]) -// ]), -// ], -// exportAs: 'uiNehubaContainer', -// providers: [ -// { -// provide: REGION_OF_INTEREST, -// useFactory: (store: Store<any>) => store.pipe( -// select(viewerStateSelectedRegionsSelector), -// map(rs => rs[0] || null) -// ), -// deps: [ -// Store -// ] -// } -// ] -// }) - -// export class NehubaContainer implements OnInit, OnChanges, OnDestroy { - -// public CONST = CONST -// public ARIA_LABEL_ZOOM_IN = ZOOM_IN -// public ARIA_LABEL_ZOOM_OUT = ZOOM_OUT -// public ARIA_LABEL_TOGGLE_FRONTAL_OCTANT = TOGGLE_FRONTAL_OCTANT -// public ARIA_LABEL_TOGGLE_SIDE_PANEL = TOGGLE_SIDE_PANEL -// public ARIA_LABEL_EXPAND = EXPAND -// public ARIA_LABEL_COLLAPSE = COLLAPSE -// public ARIA_LABEL_ADDITIONAL_VOLUME_CONTROL = ADDITIONAL_VOLUME_CONTROL - -// public ID_MESH_LOADING_STATUS = MESH_LOADING_STATUS - -// @ViewChild(NehubaViewerContainerDirective,{static: true}) -// public nehubaContainerDirective: NehubaViewerContainerDirective - -// // @ViewChild('sideNavMasterSwitch', { static: true }) -// // public navSideDrawerMainSwitch: SwitchDirective -// // @ViewChild('sideNavSwitch', { static: true }) -// // public navSideDrawerMinorSwitch: SwitchDirective - -// @ViewChild('matDrawerMaster', {static: true}) -// public matDrawerMain: MatDrawer -// @ViewChild('matDrawerMinor', { static: true }) -// public matDrawerMinor: MatDrawer - -// @Output() -// public nehubaViewerLoaded: EventEmitter<boolean> = new EventEmitter() - -// @Output() -// public forceUI$: Observable<{ target: 'perspective:octantRemoval', mode: boolean, message?: string }> - -// public disableOctantRemoval$: Observable<{ message?: string, mode: boolean }> - -// public handleViewerLoadedEvent(flag: boolean){ -// this.viewerLoaded = flag -// this.nehubaViewerLoaded.emit(flag) -// } - -// public viewerLoaded: boolean = false - -// private sliceRenderEvent$: Observable<CustomEvent> -// public sliceViewLoadingMain$: Observable<[boolean, boolean, boolean]> -// public perspectiveViewLoading$: Observable<string|null> -// public showPerpsectiveScreen$: Observable<string> - -// public templateSelected$: Observable<any> = this.store.pipe( -// select(viewerStateSelectedTemplateSelector), -// distinctUntilChanged(isSame), -// ) - -// private newViewer$: Observable<any> = this.templateSelected$.pipe( -// filter(v => !!v), -// ) - -// private selectedParcellation$: Observable<any> = this.store.pipe( -// select(viewerStateSelectedParcellationSelector), -// distinctUntilChanged(), -// filter(v => !!v) -// ) -// public selectedRegions: any[] = [] -// public selectedRegions$: Observable<any[]> = this.store.pipe( -// select(viewerStateSelectedRegionsSelector), -// filter(rs => !!rs), -// ) - -// public selectedLandmarks$: Observable<any[]> -// public selectedPtLandmarks$: Observable<any[]> -// public customLandmarks$: Observable<any> = this.store.pipe( -// select(viewerStateCustomLandmarkSelector), -// map(lms => lms.map(lm => ({ -// ...lm, -// geometry: { -// position: lm.position -// } -// }))) -// ) -// private hideSegmentations$: Observable<boolean> - -// private fetchedSpatialDatasets$: Observable<ILandmark[]> -// private userLandmarks$: Observable<IUserLandmark[]> - -// public nehubaViewerPerspectiveOctantRemoval$: Observable<boolean> - -// @Input() -// private currentOnHover: {segments: any, landmark: any, userLandmark: any} - -// @Input() -// currentOnHoverObs$: Observable<{segments: any, landmark: any, userLandmark: any}> - -// public iavAdditionalLayers$ = new Subject<any[]>() - -// // public alwaysHideMinorPanel$: Observable<boolean> = combineLatest( -// // this.selectedRegions$, -// // this.iavAdditionalLayers$.pipe( -// // startWith([]) -// // ) -// // ).pipe( -// // map(([ regions, layers ]) => regions.length === 0 && layers.length === 0) -// // ) - -// public onHoverSegments$: BehaviorSubject<any[]> = new BehaviorSubject([]) -// public onHoverSegment$: Observable<any> = this.onHoverSegments$.pipe( -// scan(sortByFreshness, []), -// /** -// * take the first element after sort by freshness -// */ -// map(arr => arr[0]), -// /** -// * map to the older interface -// */ -// filter(v => !!v), -// map(({ segment }) => { -// return { -// labelIndex: (isNaN(segment) && Number(segment.labelIndex)) || null, -// foundRegion: (isNaN(segment) && segment) || null, -// } -// }), -// ) - -// public selectedTemplate: any | null -// private selectedRegionIndexSet: Set<string> = new Set() -// public fetchedSpatialData: ILandmark[] = [] - -// private ngLayersRegister: Partial<NgViewerStateInterface> = {layers : [], forceShowSegment: null} -// private ngLayers$: Observable<NgViewerStateInterface> - -// public selectedParcellation: any | null - -// public nehubaViewer: NehubaViewerUnit = null -// private multiNgIdsRegionsLabelIndexMap: Map<string, Map<number, any>> = new Map() -// private landmarksLabelIndexMap: Map<number, any> = new Map() -// private landmarksNameMap: Map<string, number> = new Map() - -// private subscriptions: Subscription[] = [] - -// public nanometersToOffsetPixelsFn: Array<(...arg) => any> = [] - -// public viewPanels: [HTMLElement, HTMLElement, HTMLElement, HTMLElement] = [null, null, null, null] -// public panelMode$: Observable<string> - -// public panelOrder$: Observable<string> -// private redrawLayout$: Observable<[string, string]> - -// public hoveredPanelIndices$: Observable<number> - -// public connectivityNumber: string - -// constructor( -// private pureConstantService: PureContantService, -// @Optional() @Inject(API_SERVICE_SET_VIEWER_HANDLE_TOKEN) private setViewerHandle: (arg) => void, -// private store: Store<any>, -// private elementRef: ElementRef, -// private log: LoggingService, -// private cdr: ChangeDetectorRef, -// @Optional() @Inject(REGION_OF_INTEREST) public regionOfInterest$: Observable<any> -// ) { - -// this.useMobileUI$ = this.pureConstantService.useTouchUI$ - -// // this.nehubaViewerPerspectiveOctantRemoval$ = this.store.pipe( -// // select(ngViewerSelectorOctantRemoval), -// // ) - -// // this.panelMode$ = this.store.pipe( -// // select(ngViewerSelectorPanelMode), -// // distinctUntilChanged(), -// // shareReplay(1), -// // ) - -// // this.panelOrder$ = this.store.pipe( -// // select(ngViewerSelectorPanelOrder), -// // distinctUntilChanged(), -// // shareReplay(1), -// // ) - -// // this.redrawLayout$ = this.store.pipe( -// // select(ngViewerSelectorNehubaReady), -// // distinctUntilChanged(), -// // filter(v => !!v), -// // switchMapTo(combineLatest([ -// // this.panelMode$, -// // this.panelOrder$, -// // ])), -// // ) - -// this.selectedLandmarks$ = this.store.pipe( -// select('viewerState'), -// select('landmarksSelected'), -// ) - -// this.selectedPtLandmarks$ = this.selectedLandmarks$.pipe( -// map(lms => lms.filter(lm => lm.geometry.type === 'point')), -// ) - -// this.fetchedSpatialDatasets$ = this.store.pipe( -// select('dataStore'), -// select('fetchedSpatialData'), -// distinctUntilChanged(compareLandmarksChanged), -// filter(v => !!v), -// startWith([]), -// debounceTime(300), -// ) - -// // this.userLandmarks$ = this.store.pipe( -// // select(viewerStateCustomLandmarkSelector), -// // distinctUntilChanged(), -// // ) - -// /** -// * in future, perhaps add other force UI optinos here -// */ -// // this.forceUI$ = this.userLandmarks$.pipe( -// // map(lm => { -// // if (lm.length > 0) { -// // return { -// // target: 'perspective:octantRemoval', -// // mode: false, -// // message: `octant control disabled: showing landmarks.` -// // } -// // } else { -// // return { -// // target: 'perspective:octantRemoval', -// // mode: null -// // } -// // } -// // }) -// // ) - -// // this.disableOctantRemoval$ = this.forceUI$.pipe( -// // filter(({ target }) => target === 'perspective:octantRemoval'), -// // ) - -// // this.sliceRenderEvent$ = fromEvent(this.elementRef.nativeElement, 'sliceRenderEvent').pipe( -// // map(ev => ev as CustomEvent) -// // ) - -// // this.sliceViewLoadingMain$ = this.sliceRenderEvent$.pipe( -// // scan(scanFn, [null, null, null]), -// // startWith([true, true, true] as [boolean, boolean, boolean]), -// // shareReplay(1), -// // ) - -// // this.showPerpsectiveScreen$ = this.newViewer$.pipe( -// // switchMapTo(this.sliceRenderEvent$.pipe( -// // scan((acc, curr) => { - -// // /** -// // * if at any point, all chunks have been loaded, always return loaded state -// // */ -// // if (acc.every(v => v === 0)) return [0, 0, 0] -// // const { detail = {}, target } = curr || {} -// // const { missingChunks = -1, missingImageChunks = -1 } = detail -// // const idx = this.findPanelIndex(target as HTMLElement) -// // const returnAcc = [...acc] -// // if (idx >= 0) { -// // returnAcc[idx] = missingChunks + missingImageChunks -// // } -// // return returnAcc -// // }, [-1, -1, -1]), -// // map(arr => { -// // let sum = 0 -// // let uncertain = false -// // for (const num of arr) { -// // if (num < 0) { -// // uncertain = true -// // } else { -// // sum += num -// // } -// // } -// // return sum > 0 -// // ? `Loading ${sum}${uncertain ? '+' : ''} chunks ...` -// // : null -// // }), -// // distinctUntilChanged(), -// // startWith('Loading ...'), -// // throttleTime(100, asyncScheduler, { leading: true, trailing: true }), -// // shareReplay(1), -// // )) -// // ) - -// /* missing chunk perspective view */ -// // this.perspectiveViewLoading$ = fromEvent(this.elementRef.nativeElement, 'perpspectiveRenderEvent') -// // .pipe( -// // filter(event => isDefined(event) && isDefined((event as any).detail) && isDefined((event as any).detail.lastLoadedMeshId) ), -// // map(event => { - -// // /** -// // * TODO dig into event detail to see if the exact mesh loaded -// // */ -// // const { meshesLoaded, meshFragmentsLoaded, lastLoadedMeshId } = (event as any).detail -// // return meshesLoaded >= this.nehubaViewer.numMeshesToBeLoaded -// // ? null -// // : 'Loading meshes ...' -// // }), -// // distinctUntilChanged() -// // ) - -// this.ngLayers$ = this.store.pipe( -// select('ngViewerState'), -// ) - -// this.hideSegmentations$ = this.ngLayers$.pipe( -// map(state => isDefined(state) -// ? state.layers?.findIndex(l => l.mixability === 'nonmixable') >= 0 -// : false), -// ) - -// /** -// * fixes -// * https://github.com/HumanBrainProject/interactive-viewer/issues/800 -// */ -// this.subscriptions.push( -// this.nehubaViewerLoaded.pipe( -// debounceTime(500), -// filter(v => !v), -// ).subscribe(() => { -// this.matDrawerMain.close() -// this.matDrawerMinor.close() -// }) -// ) -// } - -// public useMobileUI$: Observable<boolean> - -// // private removeExistingPanels() { -// // const element = this.nehubaViewer.nehubaViewer.ngviewer.layout.container.componentValue.element as HTMLElement -// // while (element.childElementCount > 0) { -// // element.removeChild(element.firstElementChild) -// // } -// // return element -// // } - -// // private findPanelIndex = (panel: HTMLElement) => this.viewPanels?.findIndex(p => p === panel) - -// private _exportNehuba: any -// get exportNehuba() { -// if (!this._exportNehuba) { -// this._exportNehuba = getExportNehuba() -// } -// return this._exportNehuba -// } - -// public ngOnInit() { -// // this.hoveredPanelIndices$ = fromEvent(this.elementRef.nativeElement, 'mouseover').pipe( -// // switchMap((ev: MouseEvent) => merge( -// // of(this.findPanelIndex(ev.target as HTMLElement)), -// // fromEvent(this.elementRef.nativeElement, 'mouseout').pipe( -// // mapTo(null), -// // ), -// // )), -// // debounceTime(20), -// // shareReplay(1), -// // ) - -// // TODO deprecate -// /* each time a new viewer is initialised, take the first event to get the translation function */ -// // this.subscriptions.push( -// // this.newViewer$.pipe( -// // switchMapTo(this.sliceRenderEvent$.pipe( -// // takeOnePipe() -// // )) -// // ).subscribe((events) => { -// // for (const idx in [0, 1, 2]) { -// // const ev = events[idx] as CustomEvent -// // this.viewPanels[idx] = ev.target as HTMLElement -// // this.nanometersToOffsetPixelsFn[idx] = ev.detail.nanometersToOffsetPixels -// // } -// // }), -// // ) - -// // this.subscriptions.push( -// // this.newViewer$.pipe( -// // switchMapTo(fromEvent(this.elementRef.nativeElement, 'perpspectiveRenderEvent').pipe( -// // take(1), -// // )), -// // ).subscribe(ev => this.viewPanels[3] = ((ev as CustomEvent).target) as HTMLElement), -// // ) - -// // this.subscriptions.push( -// // this.redrawLayout$.subscribe(([mode, panelOrder]) => { -// // const viewPanels = panelOrder.split('').map(v => Number(v)).map(idx => this.viewPanels[idx]) as [HTMLElement, HTMLElement, HTMLElement, HTMLElement] -// // /** -// // * TODO be smarter with event stream -// // */ -// // if (!this.nehubaViewer) { return } - -// // /** -// // * TODO smarter with event stream -// // */ -// // if (!viewPanels.every(v => !!v)) { return } - -// // switch (mode) { -// // case PANELS.H_ONE_THREE: { -// // const element = this.removeExistingPanels() -// // const newEl = getHorizontalOneThree(viewPanels) -// // element.appendChild(newEl) -// // break; -// // } -// // case PANELS.V_ONE_THREE: { -// // const element = this.removeExistingPanels() -// // const newEl = getVerticalOneThree(viewPanels) -// // element.appendChild(newEl) -// // break; -// // } -// // case PANELS.FOUR_PANEL: { -// // const element = this.removeExistingPanels() -// // const newEl = getFourPanel(viewPanels) -// // element.appendChild(newEl) -// // break; -// // } -// // case PANELS.SINGLE_PANEL: { -// // const element = this.removeExistingPanels() -// // const newEl = getSinglePanel(viewPanels) -// // element.appendChild(newEl) -// // break; -// // } -// // default: -// // } -// // for (const panel of viewPanels) { -// // (panel as HTMLElement).classList.add('neuroglancer-panel') -// // } - -// // // TODO needed to redraw? -// // // see https://trello.com/c/oJOnlc6v/60-enlarge-panel-allow-user-rearrange-panel-position -// // // further investigaation required -// // this.nehubaViewer.redraw() -// // }), -// // ) - -// this.subscriptions.push( -// this.fetchedSpatialDatasets$.subscribe(datasets => { -// this.landmarksLabelIndexMap = new Map(datasets.map((v, idx) => [idx, v]) as Array<[number, any]>) -// this.landmarksNameMap = new Map(datasets.map((v, idx) => [v.name, idx] as [string, number])) -// }), -// ) - -// /** -// * TODO deprecate, but document the method -// */ -// this.subscriptions.push( -// combineLatest( -// this.fetchedSpatialDatasets$, -// ).subscribe(([fetchedSpatialData]) => { -// this.fetchedSpatialData = fetchedSpatialData - -// if (this.fetchedSpatialData?.length > 0) { -// this.nehubaViewer.addSpatialSearch3DLandmarks( -// this.fetchedSpatialData -// .map(data => data.geometry.type === 'point' -// ? (data.geometry as IPointLandmarkGeometry).position -// : data.geometry.type === 'plane' -// ? [ -// (data.geometry as IPlaneLandmarkGeometry).corners, -// [[0, 1, 2], [0, 2, 3]], -// ] -// : data.geometry.type === 'mesh' -// ? [ -// (data.geometry as IOtherLandmarkGeometry).vertices, -// (data.geometry as IOtherLandmarkGeometry).meshIdx, -// ] -// : null), -// ) -// } else { -// if (this.nehubaViewer && this.nehubaViewer.removeSpatialSearch3DLandmarks instanceof Function) { -// this.nehubaViewer.removeSpatialSearch3DLandmarks() -// } -// } -// }), -// ) - -// // this.subscriptions.push( -// // this.userLandmarks$.pipe( -// // withLatestFrom( -// // this.nehubaViewerPerspectiveOctantRemoval$ -// // ) -// // ).subscribe(([landmarks, flag]) => { -// // if (this.nehubaContainerDirective) { -// // this.nehubaContainerDirective.toggleOctantRemoval( -// // landmarks.length > 0 ? false : flag -// // ) -// // } -// // if (this.nehubaViewer) { -// // this.nehubaViewer.updateUserLandmarks(landmarks) -// // } -// // }), -// // ) - -// // this.subscriptions.push( -// // this.newViewer$.pipe( -// // skip(1), -// // ).subscribe(() => { - -// // /* on selecting of new template, remove additional nglayers */ -// // const baseLayerNames = Object.keys(this.selectedTemplate.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.subscriptions.push( -// this.templateSelected$.subscribe(() => this.destroynehuba()), -// ) - -// /* order of subscription will determine the order of execution */ -// // this.subscriptions.push( -// // this.newViewer$.pipe( -// // map(templateSelected => { -// // const deepCopiedState = JSON.parse(JSON.stringify(templateSelected)) -// // const navigation = deepCopiedState.nehubaConfig.dataset.initialNgState.navigation -// // if (!navigation) { -// // return deepCopiedState -// // } -// // navigation.zoomFactor = calculateSliceZoomFactor(navigation.zoomFactor) -// // deepCopiedState.nehubaConfig.dataset.initialNgState.navigation = navigation -// // return deepCopiedState -// // }), -// // withLatestFrom( -// // this.selectedParcellation$.pipe( -// // startWith(null), -// // ) -// // ), -// // ).subscribe(([templateSelected, parcellationSelected]) => { - -// // this.selectedTemplate = templateSelected -// // this.createNewNehuba(templateSelected) -// // const foundParcellation = parcellationSelected -// // && templateSelected?.parcellations?.find(parcellation => parcellationSelected.name === parcellation.name) -// // this.handleParcellation(foundParcellation || templateSelected.parcellations[0]) - -// // const nehubaConfig = templateSelected.nehubaConfig -// // const initialSpec = nehubaConfig.dataset.initialNgState -// // const {layers} = initialSpec - -// // const dispatchLayers = Object.keys(layers).map(key => { -// // const layer = { -// // name : key, -// // source : layers[key].source, -// // mixability : layers[key].type === 'image' -// // ? 'base' -// // : 'mixable', -// // visible : typeof layers[key].visible === 'undefined' -// // ? true -// // : layers[key].visible, -// // transform : typeof layers[key].transform === 'undefined' -// // ? null -// // : layers[key].transform, -// // } -// // this.ngLayersRegister.layers.push(layer) -// // return layer -// // }) - -// // this.store.dispatch(ngViewerActionAddNgLayer({ -// // layer: dispatchLayers -// // })) -// // }) -// // ) - -// let prevParcellation = null - -// // this.subscriptions.push( - -// // combineLatest([ -// // this.selectedRegions$.pipe( -// // distinctUntilChanged(), -// // ), -// // this.hideSegmentations$.pipe( -// // distinctUntilChanged(), -// // ), -// // this.ngLayers$.pipe( -// // map(state => state.forceShowSegment), -// // distinctUntilChanged(), -// // ), -// // this.selectedParcellation$, -// // this.store.pipe( -// // select('viewerState'), -// // select('overwrittenColorMap'), -// // distinctUntilChanged() -// // ) -// // ]).pipe( -// // delayWhen(() => timer()) -// // ).subscribe(([regions, hideSegmentFlag, forceShowSegment, selectedParcellation, overwrittenColorMap]) => { -// // if (!this.nehubaViewer) { return } - -// // const { ngId: defaultNgId } = selectedParcellation - -// // /* selectedregionindexset needs to be updated regardless of forceshowsegment */ -// // this.selectedRegionIndexSet = !prevParcellation || prevParcellation === selectedParcellation? -// // new Set(regions.map(({ngId = defaultNgId, labelIndex}) => serialiseParcellationRegion({ ngId, labelIndex }))) : new Set() - -// // if ( forceShowSegment === false || (forceShowSegment === null && hideSegmentFlag) ) { -// // this.nehubaViewer.hideAllSeg() -// // return -// // } - -// // this.selectedRegionIndexSet.size > 0 && !overwrittenColorMap -// // ? this.nehubaViewer.showSegs([...this.selectedRegionIndexSet]) -// // : this.nehubaViewer.showAllSeg() - -// // prevParcellation = selectedParcellation -// // }), -// // ) - -// // this.subscriptions.push( -// // this.ngLayers$.subscribe(ngLayersInterface => { -// // if (!this.nehubaViewer) { return } - -// // const newLayers = ngLayersInterface.layers.filter(l => this.ngLayersRegister.layers?.findIndex(ol => ol.name === l.name) < 0) -// // const removeLayers = this.ngLayersRegister.layers.filter(l => ngLayersInterface.layers?.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}) -// // }) - -// // 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.nehubaViewer.removeLayer({ -// // name : l.name, -// // })) { -// // this.ngLayersRegister.layers = this.ngLayersRegister.layers.filter(rl => rl.name !== l.name) -// // } -// // }) -// // } -// // }), -// // ) - -// this.subscriptions.push( -// this.selectedParcellation$.subscribe(this.handleParcellation.bind(this)) -// ) - -// /* setup init view state */ - -// this.subscriptions.push( -// this.selectedRegions$.pipe( -// filter(() => !!this.nehubaViewer), -// ).subscribe(regions => { -// this.nehubaViewer.initRegions = regions.map(({ ngId, labelIndex }) => serialiseParcellationRegion({ ngId, labelIndex })) -// }) -// ) - -// this.subscriptions.push(this.selectedRegions$.subscribe(sr => { -// this.selectedRegions = sr -// })) - -// /** switch side nav */ -// // this.subscriptions.push( -// // this.alwaysHideMinorPanel$.pipe( -// // distinctUntilChanged() -// // ).subscribe(flag => { -// // if (!flag) { -// // this.matDrawerMinor && this.matDrawerMinor.open() -// // this.navSideDrawerMainSwitch && this.navSideDrawerMainSwitch.open() -// // } -// // }) -// // ) - -// this.subscriptions.push( -// this.selectedRegions$.subscribe(regions => { -// this.selectedRegions = regions -// }) -// ) - -// /* handler to open/select landmark */ -// const clickObs$ = fromEvent(this.elementRef.nativeElement, 'click') - -// this.subscriptions.push( -// clickObs$.pipe( -// buffer( -// clickObs$.pipe( -// debounceTime(200), -// ), -// ), -// filter(arr => arr?.length >= 2), -// ) -// .subscribe(() => { -// const { currentOnHover } = this -// this.store.dispatch(viewerStateDblClickOnViewer({ -// payload: { ...currentOnHover } -// })) -// }), -// ) - -// // this.subscriptions.push( -// // this.selectedLandmarks$.pipe( -// // map(lms => lms.map(lm => this.landmarksNameMap.get(lm.name))), -// // debounceTime(16), -// // ).subscribe(indices => { -// // const filteredIndices = indices.filter(v => typeof v !== 'undefined' && v !== null) -// // if (this.nehubaViewer) { -// // this.nehubaViewer.spatialLandmarkSelectionChanged(filteredIndices) -// // } -// // }), -// // ) -// } - -// // datasetViewerRegistry : Set<string> = new Set() -// public showObliqueScreen$: Observable<boolean> -// public showObliqueSelection$: Observable<boolean> -// public showObliqueRotate$: Observable<boolean> - -// private currOnHoverObsSub: Subscription -// public ngOnChanges() { -// this.currOnHoverObsSub && this.currOnHoverObsSub.unsubscribe() -// if (this.currentOnHoverObs$) { -// this.currOnHoverObsSub = this.currentOnHoverObs$.subscribe(({ segments }) => this.onHoverSegments$.next(segments)) -// } -// } - -// public ngOnDestroy() { -// this.subscriptions.forEach(s => s.unsubscribe()) -// } - -// // public toggleMaximiseMinimise(index: number) { -// // this.store.dispatch(ngViewerActionToggleMax({ -// // payload: { index } -// // })) -// // } - -// public tunableMobileProperties: ITunableProp[] = [] - - -// public selectedProp = null - -// // public returnTruePos(quadrant: number, data: any) { -// // const pos = quadrant > 2 -// // ? [0, 0, 0] -// // : this.nanometersToOffsetPixelsFn && this.nanometersToOffsetPixelsFn[quadrant] -// // ? this.nanometersToOffsetPixelsFn[quadrant](data.geometry.position.map(n => n * 1e6)) -// // : [0, 0, 0] -// // return pos -// // } - -// // public getPositionX(quadrant: number, data: any) { -// // return this.returnTruePos(quadrant, data)[0] -// // } -// // public getPositionY(quadrant: number, data: any) { -// // return this.returnTruePos(quadrant, data)[1] -// // } -// // public getPositionZ(quadrant: number, data: any) { -// // return this.returnTruePos(quadrant, data)[2] -// // } - -// // public handleMouseEnterCustomLandmark(lm) { -// // this.store.dispatch( -// // viewerStateMouseOverCustomLandmark({ -// // payload: { userLandmark: lm } -// // }) -// // ) -// // } - -// // public handleMouseLeaveCustomLandmark(lm) { -// // this.store.dispatch( -// // viewerStateMouseOverCustomLandmark({ -// // payload: { userLandmark: null } -// // }) -// // ) -// // } - -// // handles mouse enter/leave landmarks in 2D -// public handleMouseEnterLandmark(spatialData: any) { -// spatialData.highlight = true -// this.store.dispatch({ -// type : MOUSE_OVER_LANDMARK, -// landmark : spatialData._label, -// }) -// } - -// public handleMouseLeaveLandmark(spatialData: any) { -// spatialData.highlight = false -// this.store.dispatch({ -// type : MOUSE_OVER_LANDMARK, -// landmark : null, -// }) -// } - -// // private handleParcellation(parcellation: any) { -// // /** -// // * parcellaiton may be undefined -// // */ -// // if ( !(parcellation && parcellation.regions)) { -// // return -// // } - -// // /** -// // * first, get all all the ngIds, including parent id from parcellation (if defined) -// // */ -// // const ngIds = getNgIds(parcellation.regions).concat( parcellation.ngId ? parcellation.ngId : []) - -// // this.multiNgIdsRegionsLabelIndexMap = getMultiNgIdsRegionsLabelIndexMap(parcellation) - -// // this.nehubaViewer.multiNgIdsLabelIndexMap = this.multiNgIdsRegionsLabelIndexMap -// // this.nehubaViewer.auxilaryMeshIndices = parcellation.auxillaryMeshIndices || [] - -// // /* TODO replace with proper KG id */ -// // /** -// // * need to set unique array of ngIds, or else workers will be overworked -// // */ -// // this.nehubaViewer.ngIds = Array.from(new Set(ngIds)) -// // this.selectedParcellation = parcellation -// // } - -// /* related spatial search */ -// public spatialSearchPagination: number = 0 - -// private destroynehuba() { -// /** -// * TODO if plugin subscribes to viewerHandle, and then new template is selected, changes willl not be be sent -// * could be considered as a bug. -// */ -// this.setViewerHandle && this.setViewerHandle(null) -// this.nehubaContainerDirective.clear() - -// this.nehubaViewer = null - -// this.cdr.detectChanges() -// } - -// private createNewNehuba(template: any) { - -// this.nehubaContainerDirective.createNehubaInstance(template) -// this.nehubaViewer = this.nehubaContainerDirective.nehubaViewerInstance - -// this.setupViewerHandleApi() -// } - -// private setupViewerHandleApi() { -// const viewerHandle = { -// setNavigationLoc : (coord, realSpace?) => this.nehubaViewer.setNavigationState({ -// position : coord, -// positionReal : typeof realSpace !== 'undefined' ? realSpace : true, -// }), -// /* TODO introduce animation */ -// moveToNavigationLoc : (coord, realSpace?) => { -// this.store.dispatch({ -// type: CHANGE_NAVIGATION, -// navigation: { -// position: coord, -// animation: {}, -// }, -// }) -// }, -// setNavigationOri : (quat) => this.nehubaViewer.setNavigationState({ -// orientation : quat, -// }), -// /* TODO introduce animation */ -// moveToNavigationOri : (quat) => this.nehubaViewer.setNavigationState({ -// orientation : quat, -// }), -// showSegment : (_labelIndex) => { -// /** -// * TODO reenable with updated select_regions api -// */ -// this.log.warn(`showSegment is temporarily disabled`) - -// // if(!this.selectedRegionIndexSet.has(labelIndex)) -// // this.store.dispatch({ -// // type : SELECT_REGIONS, -// // selectRegions : [labelIndex, ...this.selectedRegionIndexSet] -// // }) -// }, -// add3DLandmarks : landmarks => { -// // TODO check uniqueness of ID -// if (!landmarks.every(l => isDefined(l.id))) { -// throw new Error('every landmarks needs to be identified with the id field') -// } -// if (!landmarks.every(l => isDefined(l.position))) { -// throw new Error('every landmarks needs to have position defined') -// } -// if (!landmarks.every(l => l.position.constructor === Array) || !landmarks.every(l => l.position.every(v => !isNaN(v))) || !landmarks.every(l => l.position.length == 3)) { -// throw new Error('position needs to be a length 3 tuple of numbers ') -// } - -// this.store.dispatch(viewerStateAddUserLandmarks({ -// landmarks -// })) -// }, -// remove3DLandmarks : landmarkIds => { -// this.store.dispatch(viewreStateRemoveUserLandmarks({ -// payload: { landmarkIds } -// })) -// }, -// hideSegment : (_labelIndex) => { -// /** -// * TODO reenable with updated select_regions api -// */ -// this.log.warn(`hideSegment is temporarily disabled`) - -// // if(this.selectedRegionIndexSet.has(labelIndex)){ -// // this.store.dispatch({ -// // type :SELECT_REGIONS, -// // selectRegions : [...this.selectedRegionIndexSet].filter(num=>num!==labelIndex) -// // }) -// // } -// }, -// showAllSegments : () => { -// const selectRegionIds = [] -// this.multiNgIdsRegionsLabelIndexMap.forEach((map, ngId) => { -// Array.from(map.keys()).forEach(labelIndex => { -// selectRegionIds.push(serialiseParcellationRegion({ ngId, labelIndex })) -// }) -// }) -// this.store.dispatch(viewerStateSelectRegionWithIdDeprecated({ -// selectRegionIds -// })) -// }, -// hideAllSegments : () => { -// this.store.dispatch(viewerStateSelectRegionWithIdDeprecated({ -// selectRegionIds: [] -// })) -// }, -// segmentColourMap : new Map(), -// getLayersSegmentColourMap: () => { -// const newMainMap = new Map() -// for (const [key, colormap] of this.nehubaViewer.multiNgIdColorMap.entries()) { -// const newColormap = new Map() -// newMainMap.set(key, newColormap) - -// for (const [lableIndex, entry] of colormap.entries()) { -// newColormap.set(lableIndex, JSON.parse(JSON.stringify(entry))) -// } -// } -// return newMainMap -// }, -// applyColourMap : (_map) => { -// throw new Error(`apply color map has been deprecated. use applyLayersColourMap instead`) -// }, -// applyLayersColourMap: (map) => { -// this.nehubaViewer.setColorMap(map) -// }, -// loadLayer : (layerObj) => this.nehubaViewer.loadLayer(layerObj), -// removeLayer : (condition) => this.nehubaViewer.removeLayer(condition), -// setLayerVisibility : (condition, visible) => this.nehubaViewer.setLayerVisibility(condition, visible), -// mouseEvent : merge( -// fromEvent(this.elementRef.nativeElement, 'click').pipe( -// map((ev: MouseEvent) => ({eventName : 'click', event: ev})), -// ), -// fromEvent(this.elementRef.nativeElement, 'mousemove').pipe( -// map((ev: MouseEvent) => ({eventName : 'mousemove', event: ev})), -// ), -// /** -// * neuroglancer prevents propagation, so use capture instead -// */ -// Observable.create(observer => { -// this.elementRef.nativeElement.addEventListener('mousedown', event => observer.next({eventName: 'mousedown', event}), true) -// }) as Observable<{eventName: string, event: MouseEvent}>, -// fromEvent(this.elementRef.nativeElement, 'mouseup').pipe( -// map((ev: MouseEvent) => ({eventName : 'mouseup', event: ev})), -// ), -// ) , -// mouseOverNehuba : this.onHoverSegment$.pipe( -// tap(() => console.warn('mouseOverNehuba observable is becoming deprecated. use mouseOverNehubaLayers instead.')), -// ), -// mouseOverNehubaLayers: this.onHoverSegments$, -// mouseOverNehubaUI: this.currentOnHoverObs$.pipe( -// map(({ landmark, segments, userLandmark: customLandmark }) => ({ segments, landmark, customLandmark })), -// shareReplay(1), -// ), -// getNgHash : this.nehubaViewer.getNgHash, -// } - -// this.setViewerHandle && this.setViewerHandle(viewerHandle) -// } - -// // public setOctantRemoval(octantRemovalFlag: boolean) { -// // this.store.dispatch( -// // ngViewerActionSetPerspOctantRemoval({ -// // octantRemovalFlag -// // }) -// // ) -// // } - -// // public zoomNgView(panelIndex: number, factor: number) { -// // const ngviewer = this.nehubaViewer?.nehubaViewer?.ngviewer -// // if (!ngviewer) throw new Error(`ngviewer not defined!`) - -// // /** -// // * panelIndex < 3 === slice view -// // */ -// // if (panelIndex < 3) { -// // /** -// // * factor > 1 === zoom out -// // */ -// // ngviewer.navigationState.zoomBy(factor) -// // } else { -// // ngviewer.perspectiveNavigationState.zoomBy(factor) -// // } -// // } - -// // public clearPreviewingDataset(id: string){ -// // /** -// // * clear all preview -// // */ -// // this.store.dispatch( -// // id -// // ? uiActionHideDatasetWithId({ id }) -// // : uiActionHideAllDatasets() -// // ) -// // } -// } diff --git a/src/ui/nehubaContainer/nehubaContainer.style.css b/src/ui/nehubaContainer/nehubaContainer.style.css deleted file mode 100644 index 956ab1237..000000000 --- a/src/ui/nehubaContainer/nehubaContainer.style.css +++ /dev/null @@ -1,182 +0,0 @@ -:host -{ - width:100%; - height:100%; - position:relative; -} - -atlas-layer-container -{ - margin-bottom: 1em; - margin-left: 1em; - width: 30em; - height: 50em; -} - -current-layout -{ - top: 0; - left: 0; - /** z index of current layout has to be higher than that of layout-floating-container, or status container will cover panel control */ - /** TODO decide which behaviour is more nature */ - z-index: 6; -} - -div.loadingIndicator -{ - left: auto; - top: auto; - right: 0; - bottom: 0; - margin-right: 0.2em; - margin-bottom: 0.2em; - width: 100%; - position:absolute; - height:2em; - display: flex; - flex-direction: row-reverse; -} - -div.loadingIndicator >>> div.spinnerAnimationCircle -{ - font-size:150%; -} - -[perspectiveLoadingText] -{ - margin-right: 1em; -} - -:host-context([darktheme="true"]) [perspectiveLoadingText] -{ - color:rgba(255,255,255,0.8); -} - -div#scratch-pad -{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - pointer-events: none; -} - -.overlay-btn-container -{ - position: absolute; - bottom: 0; - right: 0; -} - -/* if not mobile, then show on hover */ - -.opacity-crossfade -{ - transition: opacity 170ms ease-in-out, - transform 250ms ease-in-out; -} - -.opacity-crossfade -{ - - opacity: 0.0; - pointer-events: none; -} - -.opacity-crossfade.onHover, -.opacity-crossfade:hover, -:host-context([ismobile="true"]) .opacity-crossfade.always-show-touchdevice -{ - opacity: 1.0 !important; - pointer-events: all !important; -} - -.screen-overlay -{ - background-color: rgba(255, 255, 255, 0.7); -} - -:host-context([darktheme="true"]) .screen-overlay -{ - background-color: rgba(0, 0, 0, 0.7); -} - -.feature-card -{ - - height: 20em; - max-height: 20em; - flex: 0 0 20em; - align-items: flex-start; -} - -.region-populated .feature-card -{ - height: 25em; - max-height: 25em; - flex: 0 0 25em; - align-items: flex-start; -} - -.region-text-search-autocomplete-position -{ - z-index: 10; - position: sticky; - top: 0.5rem; -} - -.collapse-position -{ - z-index: 10; - position: sticky; - bottom: 0.5rem; -} - -.placeholder-region-detail -{ - padding: 6rem 1rem 1rem 1rem; -} - -.explore-btn -{ - margin-top: 4.5rem; - width: 100%; -} - -.modality-card-container -{ - overflow-x: scroll; -} - -.modality-card -{ - width: 10em; -} - -.spacer -{ - height: 6rem; -} - -.content-transclusion-top-left -{ - margin-left: 3.5rem; -} - -.tab-toggle -{ - margin-left: -2rem; - padding-right: 0.75rem; - margin-right: 1rem; - text-align: right; -} - -.accordion-icon -{ - width:1.5rem; -} -.tab-toggle-container -{ - margin-top: 1.5rem; -} diff --git a/src/ui/nehubaContainer/nehubaContainer.template.html b/src/ui/nehubaContainer/nehubaContainer.template.html deleted file mode 100644 index 921151abb..000000000 --- a/src/ui/nehubaContainer/nehubaContainer.template.html +++ /dev/null @@ -1,844 +0,0 @@ -<div class="position-absolute h-100 w-100" - (touchmove)="$event.preventDefault()" - iav-viewer-touch-interface - [iav-viewer-touch-interface-v-panels]="viewPanels" - [iav-viewer-touch-interface-vp-to-data]="iavContainer?.viewportToDatas" - [iav-viewer-touch-interface-ngviewer]="nehubaViewer?.nehubaViewer?.ngviewer" - [iav-viewer-touch-interface-nehuba-config]="selectedTemplate?.nehubaConfig"> - <div - iav-nehuba-viewer-container - (iavNehubaViewerContainerViewerLoading)="handleViewerLoadedEvent($event)" - #iavContainer="iavNehubaViewerContainer"> - </div> -</div> - -<ui-splashscreen iav-stop="mousedown mouseup touchstart touchmove touchend" *ngIf="!viewerLoaded"> -</ui-splashscreen> - -<!-- spatial landmarks overlay --> -<!-- loading indicator --> - -<current-layout *ngIf="viewerLoaded" class="position-absolute w-100 h-100 d-block pe-none"> - <div class="w-100 h-100 position-relative" cell-i> - <ng-content *ngTemplateOutlet="ngPanelOverlayTmpl; context: { panelIndex: panelOrder$ | async | getNthElement : 0 | parseAsNumber }"></ng-content> - </div> - <div class="w-100 h-100 position-relative" cell-ii> - <ng-content *ngTemplateOutlet="ngPanelOverlayTmpl; context: { panelIndex: panelOrder$ | async | getNthElement : 1 | parseAsNumber }"></ng-content> - </div> - <div class="w-100 h-100 position-relative" cell-iii> - <ng-content *ngTemplateOutlet="ngPanelOverlayTmpl; context: { panelIndex: panelOrder$ | async | getNthElement : 2 | parseAsNumber }"></ng-content> - </div> - <div class="w-100 h-100 position-relative" cell-iv> - <ng-content *ngTemplateOutlet="ngPanelOverlayTmpl; context: { panelIndex: panelOrder$ | async | getNthElement : 3 | parseAsNumber }"></ng-content> - </div> -</current-layout> - -<layout-floating-container - class="overflow-hidden w-100 h-100" - [zIndex]="10"> - - <!-- drawer #1 --> - <mat-drawer-container - [iav-switch-initstate]="false" - iav-switch - #sideNavMasterSwitch="iavSwitch" - class="mat-drawer-content-overflow-visible w-100 h-100 position-absolute invisible" - [hasBackdrop]="false"> - - <!-- sidenav-content --> - <mat-drawer class="box-shadow-none border-0 pe-none bg-none col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2" - mode="side" - [attr.data-mat-drawer-primary-open]="matDrawerMaster.opened" - [opened]="sideNavMasterSwitch.switchState" - [autoFocus]="false" - (closedStart)="sideNavSwitch.switchState && matDrawerMinor.close()" - (openedStart)="sideNavSwitch.switchState && matDrawerMinor.open()" - [disableClose]="true" - #matDrawerMaster="matDrawer"> - - <div class="h-0 w-100 region-text-search-autocomplete-position"> - <ng-container *ngTemplateOutlet="autocompleteTmpl"> - </ng-container> - </div> - - <button mat-raised-button - *ngIf="!(alwaysHideMinorPanel$ | async)" - [attr.aria-label]="ARIA_LABEL_EXPAND" - (click)="matDrawerMinor.open()" - class="explore-btn pe-all" - [ngClass]="{ - 'darktheme': iavRegion.rgbDarkmode === true, - 'lighttheme': iavRegion.rgbDarkmode === false - }" - [style.backgroundColor]="iavRegion?.rgbString || 'accent'"> - <span class="text iv-custom-comp"> - Explore - </span> - - <div class="hidden" - iav-region - [region]="(selectedRegions$ | async) && (selectedRegions$ | async)[0]" - #iavRegion="iavRegion"> - </div> - - </button> - </mat-drawer> - <mat-drawer-content class="visible position-relative"> - - <!-- top left overlay --> - <div class="content-transclusion-top-left position-absolute top-0 left-0 w-100 d-inline-block pe-none"> - <ng-content select="[ui-nehuba-container-overlay-top-left]"> - </ng-content> - </div> - - <!-- top right overlay --> - <div class="position-absolute top-0 right-0 w-100 d-inline-block pe-none"> - <ng-content select="[ui-nehuba-container-overlay-top-right]"> - </ng-content> - </div> - - <div *ngIf="viewerLoaded" class="position-absolute z-index-6 top-0 left-0 pe-none tab-toggle-container"> - <ng-container *ngTemplateOutlet="tabTmpl; context: { - isOpen: sideNavMasterSwitch.switchState, - regionSelected: selectedRegions$ | async, - iavAdditionallayers: iavAdditionalLayers$ | async - }"> - - </ng-container> - </div> - - </mat-drawer-content> - </mat-drawer-container> - - <!-- drawer #2 --> - <mat-drawer-container - [iav-switch-initstate]="!(alwaysHideMinorPanel$ | async)" - iav-switch - #sideNavSwitch="iavSwitch" - class="mat-drawer-content-overflow-visible w-100 h-100 position-absolute invisible" - [hasBackdrop]="false"> - - <!-- sidenav-content --> - <mat-drawer class="darker-bg iv-custom-comp visible col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2 d-flex flex-column pe-all" - mode="push" - [attr.data-mat-drawer-secondary-open]="matDrawerMinor.opened" - [autoFocus]="false" - #matDrawerMinor="matDrawer" - (openedChange)="$event && sideNavSwitch.open()" - [disableClose]="true" - [@openClose]="sideNavMasterSwitch.switchState && sideNavSwitch.switchState ? 'open' : 'closed'" - (@openClose.done)="$event.toState === 'closed' && matDrawerMinor.close()"> - - <div class="position-relative d-flex flex-column h-100"> - - <!-- TODO dataset preview will become deprecated in the future. - Regional feature/data feature will replace it --> - - <div class="hidden" - iav-shown-dataset - #iavShownDataset="iavShownDataset"> - </div> - - <div class="hidden" - iav-shown-previews - (emitter)="iavAdditionalLayers$.next($event)" - #previews="iavShownPreviews"> - </div> - - <!-- sidenav datasets --> - <ng-container *ngIf="iavShownDataset.shownDatasetId$ | async as shownDatasetId"> - <ng-template [ngIf]="shownDatasetId.length > 0" [ngIfElse]="sideNavVolumePreview"> - - <!-- single dataset side nav panel --> - <single-dataset-sidenav-view *ngFor="let id of shownDatasetId" - (clear)="clearPreviewingDataset(id)" - [fullId]="id" - class="bs-border-box ml-15px-n mr-15px-n"> - <mat-chip *ngIf="regionOfInterest$ && regionOfInterest$ | async as region" - region-of-interest - iav-region - [region]="region" - [ngClass]="{ - 'darktheme':regionDirective.rgbDarkmode === true, - 'lighttheme': regionDirective.rgbDarkmode === false - }" - [style.backgroundColor]="regionDirective.rgbString" - #regionDirective="iavRegion"> - <span class="iv-custom-comp text text-truncate d-inline"> - {{ region.name }} - </span> - </mat-chip> - </single-dataset-sidenav-view> - </ng-template> - </ng-container> - - <!-- preview volumes --> - <ng-template #sideNavVolumePreview> - <ng-container *ngIf="previews.iavAdditionalLayers$ | async | filterPreviewByType : [previews.FILETYPES.VOLUMES] as volumePreviews"> - <ng-template [ngIf]="volumePreviews.length > 0" [ngIfElse]="sidenavRegionTmpl"> - <ng-container *ngFor="let vPreview of volumePreviews"> - <ng-container *ngTemplateOutlet="sidenavDsPreviewTmpl; context: vPreview"> - - </ng-container> - </ng-container> - </ng-template> - </ng-container> - </ng-template> - - </div> - </mat-drawer> - - <!-- main-content --> - <mat-drawer-content class="visible position-relative"> - - <!-- bottom left overlay --> - <div class="position-absolute bottom-0 left-0 w-100 d-inline-block pe-none"> - <ng-content select="[ui-nehuba-container-overlay-bottom-left]"> - </ng-content> - </div> - - </mat-drawer-content> - </mat-drawer-container> - -</layout-floating-container> - -<!-- collapse btn --> -<ng-template #collapseBtn> - - <div class="h-0 w-100 collapse-position d-flex flex-column justify-content-end align-items-center"> - <button mat-raised-button class="mat-elevation-z8" - [attr.aria-label]="ARIA_LABEL_COLLAPSE" - (click)="sideNavSwitch.close()" - color="basic"> - <i class="fas fa-chevron-up"></i> - <span> - collapse - </span> - </button> - </div> -</ng-template> - -<!-- region sidenav tmpl --> -<ng-template #sidenavRegionTmpl> - - <!-- region search autocomplete --> - - <div class="h-0 w-100 region-text-search-autocomplete-position" - [@openCloseAnchor]="sideNavSwitch.switchState ? 'open' : 'closed'"> - <ng-container *ngTemplateOutlet="autocompleteTmpl"> - </ng-container> - </div> - - <div class="flex-shrink-1 flex-grow-1 d-flex flex-column" - [ngClass]="{'region-populated': (selectedRegions$ | async).length > 0 }"> - <!-- region detail --> - <ng-container *ngIf="selectedRegions$ | async as selectedRegions; else selectRegionErrorTmpl"> - - <!-- single-region-wrapper --> - <ng-template [ngIf]="selectedRegions.length === 1" [ngIfElse]="multiRegionWrapperTmpl"> - <!-- a series of bugs result in requiring this hacky --> - <!-- see https://github.com/HumanBrainProject/interactive-viewer/issues/698 --> - <ng-container *ngFor="let region of selectedRegions"> - <ng-container *ngTemplateOutlet="singleRegionTmpl; context: { region: region }"> - </ng-container> - </ng-container> - </ng-template> - - <!-- multi region wrapper --> - <ng-template #multiRegionWrapperTmpl> - <ng-container *ngTemplateOutlet="multiRegionTmpl; context: { - regions: selectedRegions - }"> - </ng-container> - <!-- This is a wrapper for multiregion consisting of {{ selectedRegions.length }} regions --> - </ng-template> - - <!-- place holder if length === 0 --> - <ng-container *ngIf="selectedRegions.length === 0"> - <ng-container *ngTemplateOutlet="singleRegionTmpl; context: { region: false }"> - </ng-container> - </ng-container> - </ng-container> - - <div class="spacer"> - </div> - </div> - - <!-- collapse btn --> - <ng-container *ngTemplateOutlet="collapseBtn"> - </ng-container> -</ng-template> - -<ng-template #sidenavDsPreviewTmpl let-file="file" let-filename="filename" let-datasetId="datasetId"> - <div class="w-100 flex-grow-1 d-flex flex-column"> - - <preview-card class="d-block bs-border-box ml-15px-n mr-15px-n flex-grow-1" - [attr.aria-label]="ARIA_LABEL_ADDITIONAL_VOLUME_CONTROL" - [datasetId]="datasetId" - [filename]="filename"> - </preview-card> - - <!-- collapse btn --> - <ng-container *ngTemplateOutlet="collapseBtn"> - </ng-container> - </div> -</ng-template> - -<ng-template #empty> -</ng-template> - -<ng-template #autocompleteTmpl> - <div class="iv-custom-comp bg card w-100 mat-elevation-z8 pe-all"> - <region-text-search-autocomplete class="w-100 pt-2 flex-shrink-0 flex-grow-0"> - </region-text-search-autocomplete> - </div> -</ng-template> - -<ng-template #selectRegionErrorTmpl> - SELECT REGION ERROR -</ng-template> - -<!-- single region template --> -<div id="scratch-pad"> -</div> - -<!-- mobile nub. may be required when more advanced control is required on mobile. for now, disabled --> -<mobile-overlay - *ngIf="false && (useMobileUI$ | async) && viewerLoaded" - [iav-mobile-overlay-guide-tmpl]="mobileOverlayGuide" - [tunableProperties]="tunableMobileProperties" - [iav-mobile-overlay-hide-ctrl-btn]="(panelMode$ | async) !== 'SINGLE_PANEL'" - [iav-mobile-overlay-ctrl-btn-pos]="panelMode$ | async | mobileControlNubStylePipe"> - -</mobile-overlay> - -<ng-template #mobileOverlayGuide> - <div> - <i class="fas fa-arrows-alt-v"></i> - <span> - Select item - </span> - </div> - <div> - <i class="fas fa-arrows-alt-h"></i> - <span> - Modify item value - </span> - </div> -</ng-template> - -<!-- region tmpl placeholder --> -<ng-template #regionPlaceholderTmpl> - <div class="placeholder-region-detail bs-border-box ml-15px-n mr-15px-n mat-elevation-z4"> - <span class="text-muted"> - Select a region by clicking on the viewer or search from above - </span> - </div> -</ng-template> - -<!-- expansion tmpl --> -<ng-template #ngMatAccordionTmpl - let-title="title" - let-desc="desc" - let-iconClass="iconClass" - let-iconTooltip="iconTooltip" - let-iavNgIf="iavNgIf" - let-content="content"> - <mat-expansion-panel - [attr.data-opened]="expansionPanel.expanded" - [attr.data-mat-expansion-title]="title" - hideToggle - *ngIf="iavNgIf" - #expansionPanel="matExpansionPanel"> - - <mat-expansion-panel-header> - - <!-- title --> - <mat-panel-title> - {{ title }} - </mat-panel-title> - - <!-- desc + icon --> - <mat-panel-description class="d-flex align-items-center justify-content-end" - [matTooltip]="iconTooltip"> - <span class="mr-3">{{ desc }}</span> - <span class="accordion-icon d-inline-flex justify-content-center"> - <i [class]="iconClass"></i> - </span> - </mat-panel-description> - - </mat-expansion-panel-header> - - <!-- content --> - <ng-container *ngTemplateOutlet="content; context: { expansionPanel: expansionPanel }"> - </ng-container> - </mat-expansion-panel> -</ng-template> - - -<!-- multi region tmpl --> -<ng-template #multiRegionTmpl let-regions="regions"> - <ng-template [ngIf]="regions.length > 0" [ngIfElse]="regionPlaceholderTmpl"> - <region-menu - [showRegionInOtherTmpl]="false" - [region]="{ - name: CONST.MULTI_REGION_SELECTION - }" - class="bs-border-box ml-15px-n mr-15px-n mat-elevation-z4"> - </region-menu> - - <!-- other regions detail accordion --> - <mat-accordion class="bs-border-box ml-15px-n mr-15px-n mt-2"> - - <!-- regional features--> - <ng-template #regionalFeaturesTmpl> - <data-browser - [disableVirtualScroll]="true" - [regions]="regions"> - </data-browser> - </ng-template> - - <div class="hidden" - iav-databrowser-directive - [regions]="regions" - #iavDbDirective="iavDatabrowserDirective"> - </div> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: CONST.REGIONAL_FEATURES, - desc: iavDbDirective?.dataentries?.length, - iconClass: 'fas fa-database', - iconTooltip: iavDbDirective?.dataentries?.length | regionAccordionTooltipTextPipe : 'regionalFeatures', - iavNgIf: iavDbDirective?.dataentries?.length, - content: regionalFeaturesTmpl - }"> - </ng-container> - - <!-- Multi regions include --> - <ng-template #multiRegionInclTmpl> - <mat-chip-list> - <mat-chip *ngFor="let r of regions" - iav-region - [region]="r" - [ngClass]="{ - 'darktheme':regionDirective.rgbDarkmode === true, - 'lighttheme': regionDirective.rgbDarkmode === false - }" - [style.backgroundColor]="regionDirective.rgbString" - #regionDirective="iavRegion"> - <span class="iv-custom-comp text text-truncate d-inline pl-4"> - {{ r.name }} - </span> - </mat-chip> - </mat-chip-list> - </ng-template> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: 'Brain regions', - desc: regions.length, - iconClass: 'fas fa-brain', - iavNgIf: true, - content: multiRegionInclTmpl - }"> - </ng-container> - - </mat-accordion> - </ng-template> -</ng-template> - - -<!-- single region tmpl --> -<ng-template #singleRegionTmpl let-region="region"> - <!-- region detail --> - <ng-container *ngIf="region; else regionPlaceholderTmpl"> - <region-menu - [showRegionInOtherTmpl]="false" - [region]="region" - class="bs-border-box ml-15px-n mr-15px-n mat-elevation-z4"> - </region-menu> - </ng-container> - - <!-- other region detail accordion --> - <mat-accordion *ngIf="region" - class="bs-border-box ml-15px-n mr-15px-n mt-2" - iav-region - [region]="region" - #iavRegion="iavRegion"> - - <!-- desc --> - <ng-container *ngFor="let ods of (region.originDatasets || [])"> - <ng-template #regionDescTmpl> - <single-dataset-view - [hideTitle]="true" - [hideExplore]="true" - [hidePreview]="true" - [hidePinBtn]="true" - [hideDownloadBtn]="true" - [kgSchema]="ods.kgSchema" - [kgId]="ods.kgId"> - - </single-dataset-view> - </ng-template> - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: 'Description', - iconClass: 'fas fa-info', - iavNgIf: true, - content: regionDescTmpl - }"> - - </ng-container> - </ng-container> - - <!-- Explore in other template --> - <ng-container *ngIf="iavRegion.regionInOtherTemplates$ | async as regionInOtherTemplates"> - - <ng-template #exploreInOtherTmpl> - <mat-card *ngFor="let sameRegion of regionInOtherTemplates" - class="p-0 border-0 box-shadow-none mt-1 tb-1 cursor-pointer" - (click)="iavRegion.changeView(sameRegion)" - [matTooltip]="sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '')" - mat-ripple> - <small> - {{ sameRegion.template.name + (sameRegion.hemisphere ? (' - ' + sameRegion.hemisphere) : '') }} - </small> - </mat-card> - </ng-template> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: 'Explore in other templates', - desc: regionInOtherTemplates.length, - iconClass: 'fas fa-brain', - iconTooltip: regionInOtherTemplates.length | regionAccordionTooltipTextPipe : 'regionInOtherTmpl', - iavNgIf: regionInOtherTemplates.length, - content: exploreInOtherTmpl - }"> - - - </ng-container> - </ng-container> - - <!-- regional features--> - <ng-template #regionalFeaturesTmpl let-expansionPanel="expansionPanel"> - - <data-browser - *ngIf="expansionPanel.expanded" - [disableVirtualScroll]="true" - [regions]="[region]"> - </data-browser> - </ng-template> - - <div class="hidden" iav-databrowser-directive - [regions]="[region]" - #iavDbDirective="iavDatabrowserDirective"> - </div> - - <!-- if dataset is loading --> - <ng-template [ngIf]="iavDbDirective?.fetchingFlag" [ngIfElse]="featureLoadedTmpl"> - <div class="d-flex justify-content-center"> - <spinner-cmp></spinner-cmp> - </div> - </ng-template> - - <ng-template #featureLoadedTmpl> - - <!-- place holder content, if no regional features or connectivity or change ref space options are available --> - <ng-template [ngIf]="iavDbDirective?.dataentries?.length === 0 - && !(selectedParcellation?.hasAdditionalViewMode?.includes('connectivity'))"> - <div class="p-4"> - {{ CONST.NO_ADDIONTAL_INFO_AVAIL }} - </div> - </ng-template> - - </ng-template> - - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: CONST.REGIONAL_FEATURES, - desc: iavDbDirective?.dataentries?.length, - iconClass: 'fas fa-database', - iconTooltip: iavDbDirective?.dataentries?.length | regionAccordionTooltipTextPipe : 'regionalFeatures', - iavNgIf: iavDbDirective?.dataentries?.length, - content: regionalFeaturesTmpl - }"> - </ng-container> - - <!-- Connectivity --> - <ng-template #connectivityContentTmpl let-expansionPanel="expansionPanel"> - <mat-card-content class="flex-grow-1 flex-shrink-1 w-100"> - <ng-container *ngFor="let region of selectedRegions$ | async"> - <connectivity-browser class="pe-all flex-shrink-1" - [region]="region" - [parcellationId]="selectedParcellation['@id']" - (setOpenState)="expansionPanel.expanded = $event" - (connectivityNumberReceived)="connectivityNumber = $event" - [accordionExpanded]="expansionPanel.expanded"> - </connectivity-browser> - </ng-container> - </mat-card-content> - </ng-template> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: 'Connectivity', - desc: connectivityNumber? connectivityNumber : connectedCounterDir.value, - iconClass: 'fas fa-braille', - iconTooltip: connectedCounterDir.value | regionAccordionTooltipTextPipe : 'connectivity', - iavNgIf: selectedParcellation?.hasAdditionalViewMode?.includes('connectivity'), - content: connectivityContentTmpl - }"> - </ng-container> - - <div class="w-0 h-0" - iav-counter - #connectedCounterDir="iavCounter"> - <!-- TODO figure out why conn browser does not work here --> - <!-- @fsdavid, can you take a look why this component is not emitting connectivityNumberReceived event? --> - <connectivity-browser *ngIf="region && region.name" - class="d-block h-0 w-0 overflow-hidden" - [region]="region" - [parcellationId]="selectedParcellation['@id']" - [accordionExpanded]="true" - (connectivityNumberReceived)="connectedCounterDir.value = $event"> - - </connectivity-browser> - </div> - </mat-accordion> -</ng-template> - -<!-- overlay templates --> - -<!-- slice view overlay tmpl --> -<ng-template #ngPanelOverlayTmpl let-panelIndex="panelIndex"> - - <!-- perspective view tmpl --> - <ng-template #overlayPerspectiveTmpl> - <layout-floating-container class="tmp" landmarkContainer> - - <div class="d-flex flex-column justify-content-center align-items-center w-100 h-100 position-absolute opacity-crossfade screen-overlay pe-none" - [ngClass]="{onHover: !!(showPerpsectiveScreen$ | async)}" - [attr.id]="ID_MESH_LOADING_STATUS" - role="status"> - - <spinner-cmp *ngIf="showPerpsectiveScreen$ | async"> - </spinner-cmp> - - <mat-list> - <mat-list-item> - {{ showPerpsectiveScreen$ | async }} - </mat-list-item> - </mat-list> - </div> - - <!-- maximise/minimise button --> - <ng-container *ngTemplateOutlet="panelCtrlTmpl; context: { - panelIndex: panelIndex, - visible: (hoveredPanelIndices$ | async) === panelIndex - }"> - </ng-container> - - <!-- mesh loading is still weird --> - <!-- if the precomputed server does not have the necessary fragment file, then the numberws will not collate --> - <div *ngIf="false && (perspectiveViewLoading$ | async)" class="loadingIndicator"> - <spinner-cmp></spinner-cmp> - - <div *ngIf="false" perspectiveLoadingText> - {{ perspectiveViewLoading$ | async }} - </div> - </div> - </layout-floating-container> - </ng-template> - - <!-- nb this slice view is not suitable for perspective view! --> - <layout-floating-container *ngIf="panelIndex < 3; else overlayPerspectiveTmpl" - landmarkContainer - class="overflow-hidden"> - - <!-- customLandmarks --> - <landmark-2d-flat-cmp *ngFor="let lm of (customLandmarks$ | async | filterByProperty : 'showInSliceView')" - (mouseenter)="handleMouseEnterCustomLandmark(lm)" - (mouseleave)="handleMouseLeaveCustomLandmark(lm)" - [color]="lm.color || [255, 255, 255]" - [positionX]="getPositionX(panelIndex, lm)" - [positionY]="getPositionY(panelIndex, lm)" - [positionZ]="getPositionZ(panelIndex, lm)"> - - </landmark-2d-flat-cmp> - - <!-- only show landmarks in slice views --> - - <landmark-2d-flat-cmp *ngFor="let spatialData of (selectedPtLandmarks$ | async)" - (mouseenter)="handleMouseEnterLandmark(spatialData)" - (mouseleave)="handleMouseLeaveLandmark(spatialData)" - [color]="spatialData.highlight ? [255, 0, 0] : [255, 255, 255]" - [positionX]="getPositionX(panelIndex, spatialData)" - [positionY]="getPositionY(panelIndex, spatialData)" - [positionZ]="getPositionZ(panelIndex, spatialData)"> - </landmark-2d-flat-cmp> - - <!-- maximise/minimise button --> - <ng-container *ngTemplateOutlet="panelCtrlTmpl; context: { - panelIndex: panelIndex, - visible: (hoveredPanelIndices$ | async) === panelIndex - }"> - </ng-container> - - <div *ngIf="(sliceViewLoadingMain$ | async)[panelIndex]" class="loadingIndicator"> - <spinner-cmp></spinner-cmp> - </div> - </layout-floating-container> - -</ng-template> - -<!-- panel control template --> -<ng-template - #panelCtrlTmpl - let-panelIndex="panelIndex" - let-visible="visible"> - - <div class="opacity-crossfade always-show-touchdevice pe-all overlay-btn-container" - [ngClass]="{ onHover: visible }" - [attr.data-viewer-controller-visible]="visible" - [attr.data-viewer-controller-index]="panelIndex"> - - <!-- perspective specific control --> - <ng-container *ngIf="panelIndex === 3"> - <ng-container *ngTemplateOutlet="perspectiveOctantRemovalTmpl; context: { - state: (nehubaViewerPerspectiveOctantRemoval$ | async), - disableOctantRemoval: disableOctantRemoval$ | async - }"> - - </ng-container> - </ng-container> - - <!-- factor < 1.0 === zoom in --> - <button mat-icon-button color="primary" - (click)="zoomNgView(panelIndex, 0.9)" - [attr.aria-label]="ARIA_LABEL_ZOOM_IN"> - <i class="fas fa-search-plus"></i> - </button> - - <!-- factor > 1.0 === zoom out --> - <button mat-icon-button color="primary" - (click)="zoomNgView(panelIndex, 1.1)" - [attr.aria-label]="ARIA_LABEL_ZOOM_OUT"> - <i class="fas fa-search-minus"></i> - </button> - - <maximise-panel-button - (click)="toggleMaximiseMinimise(panelIndex)" - [touch-side-class]="panelIndex"> - </maximise-panel-button> - </div> - -</ng-template> - - -<ng-template #perspectiveOctantRemovalTmpl let-state="state" let-disableOctantRemoval="disableOctantRemoval"> - <div class="d-inline-block" - [matTooltip]="disableOctantRemoval?.mode !== null ? disableOctantRemoval.message : null"> - <button - (click)="setOctantRemoval(!state)" - mat-icon-button - [disabled]="disableOctantRemoval?.mode !== null" - [attr.aria-label]="ARIA_LABEL_TOGGLE_FRONTAL_OCTANT" - color="primary"> - - <!-- octant removal is true --> - <ng-template [ngIf]="disableOctantRemoval?.mode !== null ? disableOctantRemoval.mode : state" [ngIfElse]="octantRemovalOffTmpl"> - <i class="fas fa-eye-slash"></i> - </ng-template> - - <!-- octant removal is false --> - <ng-template #octantRemovalOffTmpl> - <i class="fas fa-eye"></i> - </ng-template> - </button> - </div> -</ng-template> - - -<!-- template for rendering tab --> -<ng-template #tabTmpl - let-isOpen="isOpen" - let-regionSelected="regionSelected" - let-iavAdditionallayers="iavAdditionallayers"> - - <!-- if mat drawer is open --> - <ng-template [ngIf]="isOpen" [ngIfElse]="tabTmpl_closedTmpl"> - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'basic', - fontIcon: 'fa-chevron-left' - }"> - </ng-container> - </ng-template> - - <!-- if matdrawer is closed --> - <ng-template #tabTmpl_closedTmpl> - - <!-- if additional layers are being shown --> - <ng-template [ngIf]="iavAdditionallayers?.length > 0" [ngIfElse]="tabTmpl_noAdditionalLayers"> - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'accent', - fontIcon: 'fa-database', - tooltip: 'Explore dataset preview' - }"> - </ng-container> - </ng-template> - - <!-- if additional layers not not being shown --> - <ng-template #tabTmpl_noAdditionalLayers> - - <!-- if region selected > 0 --> - <ng-template [ngIf]="regionSelected?.length > 0" [ngIfElse]="tabTmpl_nothingSelected"> - <div class="hidden" - iav-region - [region]="regionSelected[0]" - #tabTmpl_iavRegion="iavRegion"> - </div> - - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'accent', - customColor: tabTmpl_iavRegion.rgbString, - customColorDarkmode: tabTmpl_iavRegion.rgbDarkmode, - fontIcon: 'fa-brain', - tooltip: 'Explore ' + tabTmpl_iavRegion.region.name - }"> - - </ng-container> - </ng-template> - - <!-- nothing is selected --> - <ng-template #tabTmpl_nothingSelected> - <ng-container *ngTemplateOutlet="tabTmpl_defaultTmpl; context: { - matColor: 'primary', - fontIcon: 'fa-sitemap', - tooltip: 'Explore regions' - }"> - </ng-container> - </ng-template> - </ng-template> - </ng-template> - - <ng-template #tabTmpl_defaultTmpl - let-matColor="matColor" - let-fontIcon="fontIcon" - let-customColor="customColor" - let-customColorDarkmode="customColorDarkmode" - let-tooltip="tooltip"> - <button mat-raised-button - [attr.aria-label]="ARIA_LABEL_TOGGLE_SIDE_PANEL" - [matTooltip]="tooltip" - class="pe-all tab-toggle" - [ngClass]="{ - 'darktheme': customColorDarkmode === true, - 'lighttheme': customColorDarkmode === false - }" - [style.backgroundColor]="customColor" - (click)="sideNavMasterSwitch.toggle()" - [color]="(!customColor && matColor) ? matColor : null"> - - <span [ngClass]="{'iv-custom-comp text': !!customColor}"> - <i class="fas" [ngClass]="fontIcon || 'fa-question'"></i> - </span> - </button> - </ng-template> -</ng-template> diff --git a/src/viewerModule/module.ts b/src/viewerModule/module.ts index b9359cbf6..60663cff4 100644 --- a/src/viewerModule/module.ts +++ b/src/viewerModule/module.ts @@ -42,308 +42,3 @@ import { ViewerCmp } from "./viewerCmp/viewerCmp.component"; }) export class ViewerModule{} - -/** - <ui-nehuba-container - class="z-index-10" - #uiNehubaContainer="uiNehubaContainer" - iav-mouse-hover - #iavMouseHoverEl="iavMouseHover" - [currentOnHoverObs$]="iavMouseHoverEl.currentOnHoverObs$" - [currentOnHover]="iavMouseHoverEl.currentOnHoverObs$ | async" - iav-captureClickListenerDirective - [iav-captureClickListenerDirective-captureDocument]="true" - (iav-captureClickListenerDirective-onUnmovedClick)="mouseClickDocument($event)" - (drag-drop)="localFileService.handleFileDrop($event)"> - - <!-- top right content transclusion --> - <div ui-nehuba-container-overlay-top-right class="d-inline-flex flex-row justify-content-end align-items-start z-index-6 position-absolute pe-none w-100 h-100"> - - <top-menu-cmp - class="mt-3 mr-2" - [parcellationIsSelected]="!!selectedParcellation" - [ismobile]="(media.mediaBreakPoint$ | async) > 3"> - </top-menu-cmp> - - <!-- atlas selector --> - <div *ngIf="uiNehubaContainer.viewerLoaded" - class="iv-custom-comp bg card m-2 mat-elevation-z2"> - <atlas-dropdown-selector class="pe-all mt-2"> - </atlas-dropdown-selector> - </div> - - </div> - - <!-- bottom left content transclusion --> - <div ui-nehuba-container-overlay-bottom-left class="d-inline-flex pe-none w-100 align-items-end m-2 mb-4"> - - <!-- only load atlas layer selector and chips if viewer is loaded --> - <ng-template [ngIf]="uiNehubaContainer.viewerLoaded && !(isStandaloneVolumes$ | async)"> - - <!-- Viewer Selector Container--> - <atlas-layer-selector - #alSelector="atlasLayerSelector" - class="pe-all" - (iav-outsideClick)="alSelector.selectorExpanded = false"> - </atlas-layer-selector> - <mat-chip-list class="mb-2"> - <!-- additional layer --> - - <ng-container> - <ng-container *ngTemplateOutlet="currParcellationTmpl; context: { addParc: (selectedAdditionalLayers$ | async), parc: selectedParcellation }"> - </ng-container> - </ng-container> - - <!-- any selected region(s) --> - <ng-container> - <ng-container *ngTemplateOutlet="selectedRegionTmpl"> - </ng-container> - </ng-container> - - <!-- controls for iav volumes --> - <div class="hidden" iav-shown-previews #previews="iavShownPreviews"></div> - <ng-container *ngTemplateOutlet="selectedDatasetPreview; context: { layers: previews.iavAdditionalLayers$ | async | filterPreviewByType : [previews.FILETYPES.VOLUMES] }"> - </ng-container> - - </mat-chip-list> - - <!-- current layer tmpl --> - - <ng-template #currParcellationTmpl let-parc="parc" let-addParc="addParc"> - - <div [matMenuTriggerFor]="layerVersionMenu" - [matMenuTriggerData]="{ layerVersionMenuTrigger: layerVersionMenuTrigger }" - #layerVersionMenuTrigger="matMenuTrigger"> - - <ng-template [ngIf]="addParc.length > 0" [ngIfElse]="defaultParcTmpl"> - <ng-container *ngFor="let p of addParc"> - <ng-container *ngTemplateOutlet="chipTmpl; context: { - parcel: p, - selected: true, - dismissable: true, - onclick: layerVersionMenuTrigger.toggleMenu.bind(layerVersionMenuTrigger) - }"> - </ng-container> - </ng-container> - </ng-template> - <ng-template #defaultParcTmpl> - <ng-container *ngTemplateOutlet="chipTmpl; context: { - parcel: parc, - selected: false, - dismissable: false, - onclick: layerVersionMenuTrigger.toggleMenu.bind(layerVersionMenuTrigger) - }"> - </ng-container> - </ng-template> - </div> - </ng-template> - - <!-- render parc templ --> - <ng-template #chipTmpl - let-parcel="parcel" - let-selected="selected" - let-dismissable="dismissable" - let-chipClass="class" - let-onclick="onclick"> - <mat-chip class="pe-all position-relative z-index-2 d-inline-flex justify-content-between" - [ngClass]="chipClass" - (click)="onclick && onclick()" - [selected]="selected"> - - <span> - {{ parcel?.groupName ? (parcel?.groupName + ' - ') : '' }}{{ parcel && (parcel.displayName || parcel.name) }} - </span> - - <!-- info icon --> - <ng-template [ngIf]="parcel?.originDatasets?.length > 0" [ngIfElse]="infoIconBasic"> - - <mat-icon - *ngFor="let ds of parcel.originDatasets" - fontSet="fas" - fontIcon="fa-info-circle" - iav-stop="click" - iav-dataset-show-dataset-dialog - [iav-dataset-show-dataset-dialog-kgid]="ds['kgId']" - [iav-dataset-show-dataset-dialog-kgschema]="ds['kgSchema']" - [iav-dataset-show-dataset-dialog-name]="parcel?.properties?.name" - [iav-dataset-show-dataset-dialog-description]="parcel?.properties?.description"> - </mat-icon> - - </ng-template> - - <ng-template #infoIconBasic> - <mat-icon *ngIf="parcel?.properties?.name && parcel?.properties?.description" - fontSet="fas" - fontIcon="fa-info-circle" - iav-stop="click" - iav-dataset-show-dataset-dialog - [iav-dataset-show-dataset-dialog-name]="parcel.properties.name" - [iav-dataset-show-dataset-dialog-description]="parcel.properties.description"> - - </mat-icon> - </ng-template> - - <!-- dismiss icon --> - <mat-icon - *ngIf="dismissable" - (click)="clearAdditionalLayer(parcel); $event.stopPropagation()" - fontSet="fas" - fontIcon="fa-times"> - </mat-icon> - </mat-chip> - </ng-template> - - <!-- layer version selector --> - <mat-menu #layerVersionMenu - class="bg-none box-shadow-none" - [hasBackdrop]="false"> - <ng-template matMenuContent let-layerVersionMenuTrigger="layerVersionMenuTrigger"> - <div (iav-outsideClick)="layerVersionMenuTrigger.closeMenu()"> - <ng-container *ngFor="let parcVer of selectedLayerVersions$ | async"> - <ng-container *ngTemplateOutlet="chipTmpl; context: { - parcel: parcVer, - selected: selectedParcellation && selectedParcellation['@id'] === parcVer['@id'], - dismissable: false, - class: 'w-100', - onclick: bindFns([ - [ selectParcellation.bind(this), parcVer ], - [ layerVersionMenuTrigger.closeMenu.bind(layerVersionMenuTrigger) ] - ]) - }"> - </ng-container> - <div class="mt-1"></div> - </ng-container> - </div> - </ng-template> - </mat-menu> - - <ng-template #selectedRegionTmpl> - - <!-- regions chip --> - <ng-template [ngIf]="selectedRegions$ | async" let-selectedRegions="ngIf"> - <!-- if regions.length > 1 --> - <!-- use group chip --> - <ng-template [ngIf]="selectedRegions.length > 1" [ngIfElse]="singleRegionTmpl"> - <mat-chip - color="primary" - selected - (click)="uiNehubaContainer.matDrawerMinor.open() && uiNehubaContainer.navSideDrawerMainSwitch.open()" - class="pe-all position-relative z-index-1 ml-8-n"> - <span class="iv-custom-comp text text-truncate d-inline pl-4"> - {{ CONST.MULTI_REGION_SELECTION }} - </span> - <mat-icon - (click)="clearSelectedRegions()" - fontSet="fas" - iav-stop="click" - fontIcon="fa-times"> - </mat-icon> - </mat-chip> - </ng-template> - - <!-- if reginos.lengt === 1 --> - <!-- use single region chip --> - <ng-template #singleRegionTmpl> - <ng-container *ngFor="let r of selectedRegions"> - - <!-- region chip for discrete map --> - <mat-chip - iav-region - (click)="uiNehubaContainer.matDrawerMinor.open() && uiNehubaContainer.navSideDrawerMainSwitch.open()" - [region]="r" - class="pe-all position-relative z-index-1 ml-8-n" - [ngClass]="{ - 'darktheme':regionDirective.rgbDarkmode === true, - 'lighttheme': regionDirective.rgbDarkmode === false - }" - [style.backgroundColor]="regionDirective.rgbString" - #regionDirective="iavRegion"> - <span class="iv-custom-comp text text-truncate d-inline pl-4"> - {{ r.name }} - </span> - <mat-icon - class="iv-custom-comp text" - (click)="clearSelectedRegions()" - fontSet="fas" - iav-stop="click" - fontIcon="fa-times"> - </mat-icon> - </mat-chip> - - <!-- chips for previewing origin datasets/continous map --> - <ng-container *ngFor="let originDataset of (r.originDatasets || []); let index = index"> - <div class="hidden" - iav-dataset-preview-dataset-file - [iav-dataset-preview-dataset-file-kgid]="originDataset.kgId" - [iav-dataset-preview-dataset-file-filename]="originDataset.filename" - #previewDirective="iavDatasetPreviewDatasetFile"> - </div> - <mat-chip *ngIf="previewDirective.active" - (click)="uiNehubaContainer.matDrawerMinor.open() && uiNehubaContainer.navSideDrawerMainSwitch.open()" - class="pe-all position-relative ml-8-n"> - <span class="pl-4"> - {{ regionDirective.regionOriginDatasetLabels$ | async | renderViewOriginDatasetlabel : index }} - </span> - <mat-icon (click)="previewDirective.onClick()" - fontSet="fas" - iav-stop="click" - fontIcon="fa-times"> - </mat-icon> - </mat-chip> - - <mat-chip *ngFor="let key of clearViewKeys$ | async" - (click)="uiNehubaContainer.matDrawerMinor.open() && uiNehubaContainer.navSideDrawerMainSwitch.open()" - class="pe-all position-relative ml-8-n"> - <span class="pl-4"> - {{ key }} - </span> - <mat-icon (click)="unsetClearViewByKey(key)" - fontSet="fas" - iav-stop="click" - fontIcon="fa-times"> - - </mat-icon> - </mat-chip> - </ng-container> - - </ng-container> - </ng-template> - </ng-template> - - </ng-template> - - <ng-template #selectedDatasetPreview let-layers="layers"> - - <ng-container *ngFor="let layer of layers"> - <div class="hidden" - iav-dataset-preview-dataset-file - [iav-dataset-preview-dataset-file-kgid]="layer.datasetId" - [iav-dataset-preview-dataset-file-filename]="layer.filename" - #preview="iavDatasetPreviewDatasetFile"> - - </div> - <mat-chip class="pe-all" - (click)="uiNehubaContainer.matDrawerMinor.open() && uiNehubaContainer.navSideDrawerMainSwitch.open()"> - {{ layer.file?.name || layer.filename || 'Unknown data preview' }} - <mat-icon fontSet="fas" fontIcon="fa-times" - (click)="preview.onClick()" - iav-stop="click"> - </mat-icon> - </mat-chip> - </ng-container> - </ng-template> - - </ng-template> - </div> - - <!-- top left content transclusion --> - <div ui-nehuba-container-overlay-top-left class="d-inline-flex pe-none w-100 align-items-start m-2"> - <ui-status-card - *ngIf="uiNehubaContainer.viewerLoaded" - class="pe-all muted-7" - [selectedTemplateName]="uiNehubaContainer?.selectedTemplate?.name" - [nehubaViewer]="uiNehubaContainer?.nehubaViewer"> - </ui-status-card> - </div> - </ui-nehuba-container> - */ \ No newline at end of file diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts index d9b52d1dc..e0bace5b0 100644 --- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts +++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.component.ts @@ -18,7 +18,7 @@ import { IViewer, TViewerEvent } from "../../viewer.interface"; import { NehubaViewerUnit } from "../nehubaViewer/nehubaViewer.component"; import { NehubaViewerContainerDirective } from "../nehubaViewerInterface/nehubaViewerInterface.directive"; import { calculateSliceZoomFactor, getFourPanel, getHorizontalOneThree, getSinglePanel, getVerticalOneThree, NEHUBA_INSTANCE_INJTKN, scanSliceViewRenderFn, takeOnePipe } from "../util"; -import { API_SERVICE_SET_VIEWER_HANDLE_TOKEN, IUserLandmark, TSetViewerHandle } from "src/atlasViewer/atlasViewer.apiService.service"; +import { API_SERVICE_SET_VIEWER_HANDLE_TOKEN, TSetViewerHandle } from "src/atlasViewer/atlasViewer.apiService.service"; import { MouseHoverDirective } from "src/mouseoverModule"; interface INgLayerInterface { @@ -80,7 +80,7 @@ export class NehubaGlueCmp implements IViewer, OnChanges, OnDestroy{ public perspectiveViewLoading$: Observable<string|null> public hoveredPanelIndices$: Observable<number> private viewPanelWeakMap = new WeakMap<HTMLElement, number>() - private viewPanels: [HTMLElement, HTMLElement, HTMLElement, HTMLElement] = [null, null, null, null] + public viewPanels: [HTMLElement, HTMLElement, HTMLElement, HTMLElement] = [null, null, null, null] private findPanelIndex = (panel: HTMLElement) => this.viewPanelWeakMap.get(panel) public nanometersToOffsetPixelsFn: Array<(...arg) => any> = [] diff --git a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html index 45b20af1f..5c612b295 100644 --- a/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html +++ b/src/viewerModule/nehuba/nehubaViewerGlue/nehubaViewerGlue.template.html @@ -1,8 +1,18 @@ -<div class="d-block" - iav-nehuba-viewer-container - iav-mouse-hover - (iavNehubaViewerContainerViewerLoading)="handleViewerLoadedEvent($event)"> +<div class="d-block w-100 h-100" + (touchmove)="$event.preventDefault()" + iav-viewer-touch-interface + [iav-viewer-touch-interface-v-panels]="viewPanels" + [iav-viewer-touch-interface-vp-to-data]="iavContainer?.viewportToDatas" + [iav-viewer-touch-interface-ngviewer]="iavContainer?.nehubaViewerInstance?.nehubaViewer?.ngviewer" + [iav-viewer-touch-interface-nehuba-config]="selectedTemplate?.nehubaConfig"> + + <div class="d-block" + iav-nehuba-viewer-container + #iavContainer="iavNehubaViewerContainer" + iav-mouse-hover + (iavNehubaViewerContainerViewerLoading)="handleViewerLoadedEvent($event)"> + </div> </div> <current-layout *ngIf="viewerLoaded$ | async" class="position-absolute w-100 h-100 d-block pe-none top-0 left-0"> -- GitLab