diff --git a/docs/releases/v2.12.5.md b/docs/releases/v2.12.5.md index 99593eb2a15a269a0dee8d845eceb735659b7c8b..d7714ac02ddb6386a42822bebaed27ea0e05c761 100644 --- a/docs/releases/v2.12.5.md +++ b/docs/releases/v2.12.5.md @@ -4,3 +4,5 @@ - enable connectivity for Julich Brain v3 - added version inspector in UI +- (experimental) add keyframe support for NG viewer +- allow experimental flag to be toggled via `setExperimentalFlag` global method diff --git a/src/main.module.ts b/src/main.module.ts index 735f7f66dea3d897c4c71f9186a20e7ab2cde9f4..dca320a003b36c2b5ca08acaecc810c5375a63fc 100644 --- a/src/main.module.ts +++ b/src/main.module.ts @@ -41,6 +41,7 @@ import { atlasSelection, RootStoreModule, getStoreEffects, + userPreference, } from "./state" import { DARKTHEME } from './util/injectionTokens'; import { map } from 'rxjs/operators'; @@ -173,12 +174,17 @@ import { ViewerCommonEffects } from './viewerModule'; }, { provide: APP_INITIALIZER, - useFactory: (authSvc: AuthService) => { + useFactory: (authSvc: AuthService, store: Store) => { + window['setExperimentalFlag'] = (flag: boolean) => { + store.dispatch(userPreference.actions.setShowExperimental({ + flag + })) + } authSvc.authReloadState() return () => Promise.resolve() }, multi: true, - deps: [ AuthService ] + deps: [ AuthService, Store ] } ], bootstrap: [ diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts index dac942b8e0c95f4ab43ff91940546e333f0dbb54..9ff4c75cc8234c254e143e1a1812519dba9a74ff 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts @@ -2,7 +2,7 @@ import { Component, ElementRef, EventEmitter, OnDestroy, Output, Inject, Optiona import { Subscription, BehaviorSubject, Observable, Subject, of, interval, combineLatest } from 'rxjs' import { debounceTime, filter, scan, switchMap, take, distinctUntilChanged, debounce, map } from "rxjs/operators"; import { LoggingService } from "src/logging"; -import { bufferUntil, getExportNehuba, switchMapWaitFor } from "src/util/fn"; +import { bufferUntil, getExportNehuba, getUuid, switchMapWaitFor } from "src/util/fn"; import { deserializeSegment, NEHUBA_INSTANCE_INJTKN } from "../util"; import { arrayOrderedEql, rgbToHex } from 'common/util' import { IMeshesToLoad, SET_MESHES_TO_LOAD, PERSPECTIVE_ZOOM_FUDGE_FACTOR } from "../constants"; @@ -14,6 +14,7 @@ import { IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl. import { INgLayerCtrl, NG_LAYER_CONTROL, SET_SEGMENT_VISIBILITY, TNgLayerCtrl, Z_TRAVERSAL_MULTIPLIER } from "../layerCtrl.service/layerCtrl.util"; import { NgCoordinateSpace, Unit } from "../types"; import { PeriodicSvc } from "src/util/periodic.service"; +import { ViewerInternalStateSvc, AUTO_ROTATE } from "src/viewerModule/viewerInternalState.service"; function translateUnit(unit: Unit) { if (unit === "m") { @@ -130,6 +131,7 @@ export class NehubaViewerUnit implements OnDestroy { @Optional() @Inject(SET_SEGMENT_VISIBILITY) private segVis$: Observable<string[]>, @Optional() @Inject(NG_LAYER_CONTROL) private layerCtrl$: Observable<TNgLayerCtrl<keyof INgLayerCtrl>>, @Optional() @Inject(Z_TRAVERSAL_MULTIPLIER) multiplier$: Observable<number>, + @Optional() intViewerStateSvc: ViewerInternalStateSvc, ) { if (multiplier$) { this.ondestroySubscriptions.push( @@ -139,6 +141,54 @@ export class NehubaViewerUnit implements OnDestroy { this.multplier[0] = 1 } + if (intViewerStateSvc) { + let raqRef: number + const { + done, + next, + } = intViewerStateSvc.registerEmitter({ + "@type": "TViewerInternalStateEmitter", + viewerType: "nehuba", + applyState: arg => { + + if (arg.viewerType === AUTO_ROTATE) { + if (raqRef) { + cancelAnimationFrame(raqRef) + } + const autoPlayFlag = (arg.payload as any).play + const reverseFlag = (arg.payload as any).reverse + const autoplaySpeed = (arg.payload as any).speed + + if (!autoPlayFlag) { + return + } + const deg = (reverseFlag ? 1 : -1) * autoplaySpeed * 1e-3 + const animate = () => { + raqRef = requestAnimationFrame(() => { + animate() + }) + const perspectivePose = this.nehubaViewer?.ngviewer?.perspectiveNavigationState?.pose + if (!perspectivePose) { + return + } + perspectivePose.rotateAbsolute([0, 0, 1], deg, [0, 0, 0]) + } + + animate() + return + } + } + }) + + this.onDestroyCb.push(() => done()) + next({ + "@id": getUuid(), + '@type': "TViewerInternalStateEmitterEvent", + viewerType: "nehuba", + payload: {} + }) + } + if (this.nehubaViewer$) { this.nehubaViewer$.next(this) }