diff --git a/src/atlasViewer/atlasViewer.apiService.service.spec.ts b/src/atlasViewer/atlasViewer.apiService.service.spec.ts index e49cdacd44bb66b9690c1ac802a4e4c7fc275a40..846b29bd7c57d4ae34735873fa9029fb3ac2619d 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.spec.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.spec.ts @@ -76,6 +76,44 @@ describe('atlasViewer.apiService.service.ts', () => { }) }) + describe('> getUserToSelectRoi', () => { + it('> calling getUserToSelectRoi without spec throws error', () => { + const service = TestBed.inject(AtlasViewerAPIServices) + expect(() => { + service.interactiveViewer.uiHandle.getUserToSelectRoi('hello world') + }).toThrow() + }) + + it('> calling getUserToSelectRoi without spec.type throws', () => { + const service = TestBed.inject(AtlasViewerAPIServices) + expect(() => { + service.interactiveViewer.uiHandle.getUserToSelectRoi('hello world', { foo: 'bar' } as any) + }).toThrow() + }) + + it('> calling getUserToSelectRoi populates getUserToSelectRegion with malformed spec.type is fine', () => { + const service = TestBed.inject(AtlasViewerAPIServices) + expect(() => { + service.interactiveViewer.uiHandle.getUserToSelectRoi('hello world', { type: 'foobar' }) + }).not.toThrow() + }) + it('> calling getUserToSelectRoi populates getUserToSelectRegion', () => { + + const service = TestBed.inject(AtlasViewerAPIServices) + + const pr = service.interactiveViewer.uiHandle.getUserToSelectRoi('hello world', { type: 'POINT' }) + + expect(service.getUserToSelectRegion.length).toEqual(1) + const { promise, message, spec, rs, rj } = service.getUserToSelectRegion[0] + expect(promise).toEqual(pr) + expect(message).toEqual('hello world') + expect(spec).toEqual({ type: 'POINT' }) + + expect(rs).not.toBeFalsy() + expect(rj).not.toBeFalsy() + }) + }) + describe('cancelPromise', () => { it('calling cancelPromise removes pr from getUsertoSelectRegion', done => { @@ -243,9 +281,10 @@ describe('atlasViewer.apiService.service.ts', () => { describe('overrideNehubaClickFactory', () => { const OVERRIDE_NEHUBA_TOKEN = 'OVERRIDE_NEHUBA_TOKEN' - const MOCK_GET_MOUSEOVER_SEGMENTS_TOKEN = 'MOCK_GET_MOUSEOVER_SEGMENTS_TOKEN' + const MOCK_GET_STATE_SNAPSHOT_TOKEN = 'MOCK_GET_STATE_SNAPSHOT_TOKEN' let mockGetMouseOverSegments = [] + let mousePositionReal = [1,2,3] afterEach(() => { mockGetMouseOverSegments = [] @@ -264,13 +303,22 @@ describe('atlasViewer.apiService.service.ts', () => { useFactory: overrideNehubaClickFactory, deps: [ AtlasViewerAPIServices, - MOCK_GET_MOUSEOVER_SEGMENTS_TOKEN, + MOCK_GET_STATE_SNAPSHOT_TOKEN, ] }, { - provide: MOCK_GET_MOUSEOVER_SEGMENTS_TOKEN, + provide: MOCK_GET_STATE_SNAPSHOT_TOKEN, useValue: () => { - return mockGetMouseOverSegments + return { + state: { + uiState: { + mouseOverSegments: mockGetMouseOverSegments + } + }, + other: { + mousePositionReal + } + } } }, { @@ -288,142 +336,316 @@ describe('atlasViewer.apiService.service.ts', () => { expect(fn).not.toBeNull() }) - it('by default, next fn will be called', () => { - const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void - const nextSpy = jasmine.createSpy('next') - fn(nextSpy) - expect(nextSpy).toHaveBeenCalled() - }) + describe('> if getUserToSelectRegion.length === 0', () => { - it('if both apiService.getUserToSelectRegion.length > 0 and mouseoverSegment.length >0, then next will not be called, but rs will be', () => { - const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void - const apiService = TestBed.inject(AtlasViewerAPIServices) - - const rsSpy = jasmine.createSpy('rs') - const rjSpy = jasmine.createSpy('rj') - apiService.getUserToSelectRegion = [ - { - message: 'test', - promise: null, - rs: rsSpy, - rj: rjSpy, - } - ] - - const mockSegment = { - layer: { - name: 'apple' - }, - segment: { - name: 'bananas' - } - } - mockGetMouseOverSegments = [ mockSegment ] - - const nextSpy = jasmine.createSpy('next') - fn(nextSpy) - - expect(nextSpy).not.toHaveBeenCalled() - expect(rsSpy).toHaveBeenCalledWith(mockSegment) - }) + it('by default, next fn will be called', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + expect(nextSpy).toHaveBeenCalled() + }) - it('if apiService.getUserToSelectRegion.length === 0, and mouseoversegment.length > 0 calls next', () => { - const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void - - const mockSegment = { - layer: { - name: 'apple' - }, - segment: { - name: 'bananas' - } - } - mockGetMouseOverSegments = [ mockSegment ] - - const nextSpy = jasmine.createSpy('next') - fn(nextSpy) - - expect(nextSpy).toHaveBeenCalled() - }) - - it('if apiService.getUserToSelectRegion.length > 0, but mouseoversegment.length ===0, will not call next, will not rs, will not call rj', () => { - const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void - const apiService = TestBed.inject(AtlasViewerAPIServices) - - const rsSpy = jasmine.createSpy('rs') - const rjSpy = jasmine.createSpy('rj') - apiService.getUserToSelectRegion = [ - { - message: 'test', - promise: null, - rs: rsSpy, - rj: rjSpy, + it('if apiService.getUserToSelectRegion.length === 0, and mouseoversegment.length > 0 calls next', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + + const mockSegment = { + layer: { + name: 'apple' + }, + segment: { + name: 'bananas' + } } - ] - - const nextSpy = jasmine.createSpy('next') - fn(nextSpy) - - expect(rsSpy).not.toHaveBeenCalled() - expect(nextSpy).toHaveBeenCalled() - expect(rjSpy).not.toHaveBeenCalled() + mockGetMouseOverSegments = [ mockSegment ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(nextSpy).toHaveBeenCalled() + }) }) - it('if muliple getUserToSelectRegion handler exists, it resolves in a FIFO manner', () => { - const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void - const apiService = TestBed.inject(AtlasViewerAPIServices) - - const rsSpy1 = jasmine.createSpy('rs1') - const rjSpy1 = jasmine.createSpy('rj1') - - const rsSpy2 = jasmine.createSpy('rs2') - const rjSpy2 = jasmine.createSpy('rj2') - apiService.getUserToSelectRegion = [ - { - message: 'test1', - promise: null, - rs: rsSpy1, - rj: rjSpy1, - }, - { - message: 'test2', - promise: null, - rs: rsSpy2, - rj: rjSpy2, + describe('> if getUserToSelectRegion.length > 0', () => { + it('if both apiService.getUserToSelectRegion.length > 0 and mouseoverSegment.length >0, then next will not be called, but rs will be', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy = jasmine.createSpy('rs') + const rjSpy = jasmine.createSpy('rj') + apiService.getUserToSelectRegion = [ + { + message: 'test', + promise: null, + rs: rsSpy, + rj: rjSpy, + } + ] + + const mockSegment = { + layer: { + name: 'apple' + }, + segment: { + name: 'bananas' + } } - ] - - const mockSegment = { - layer: { - name: 'apple' - }, - segment: { - name: 'bananas' + mockGetMouseOverSegments = [ mockSegment ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(nextSpy).not.toHaveBeenCalled() + expect(rsSpy).toHaveBeenCalledWith(mockSegment) + }) + it('if multiple getUserToSelectRegion handler exists, it resolves in a LIFO manner', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy1 = jasmine.createSpy('rs1') + const rjSpy1 = jasmine.createSpy('rj1') + + const rsSpy2 = jasmine.createSpy('rs2') + const rjSpy2 = jasmine.createSpy('rj2') + apiService.getUserToSelectRegion = [ + { + message: 'test1', + promise: null, + rs: rsSpy1, + rj: rjSpy1, + }, + { + message: 'test2', + promise: null, + rs: rsSpy2, + rj: rjSpy2, + } + ] + + const mockSegment = { + layer: { + name: 'apple' + }, + segment: { + name: 'bananas' + } } - } - - mockGetMouseOverSegments = [ mockSegment ] + + mockGetMouseOverSegments = [ mockSegment ] + + const nextSpy1 = jasmine.createSpy('next1') + fn(nextSpy1) + + expect(rsSpy2).toHaveBeenCalledWith(mockSegment) + expect(rjSpy2).not.toHaveBeenCalled() + + expect(nextSpy1).not.toHaveBeenCalled() + expect(rsSpy1).not.toHaveBeenCalled() + expect(rjSpy1).not.toHaveBeenCalled() + + const nextSpy2 = jasmine.createSpy('next2') + fn(nextSpy2) + + expect(nextSpy2).not.toHaveBeenCalled() + expect(rsSpy1).toHaveBeenCalledWith(mockSegment) + expect(rjSpy1).not.toHaveBeenCalled() + + const nextSpy3 = jasmine.createSpy('next3') + fn(nextSpy3) + + expect(nextSpy3).toHaveBeenCalled() + }) - const nextSpy1 = jasmine.createSpy('next1') - fn(nextSpy1) + describe('> if spec is not set (defaults to parcellation region mode)', () => { - expect(rsSpy2).toHaveBeenCalledWith(mockSegment) - expect(rjSpy2).not.toHaveBeenCalled() + it('if apiService.getUserToSelectRegion.length > 0, but mouseoversegment.length ===0, will not call next, will not rs, will not call rj', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy = jasmine.createSpy('rs') + const rjSpy = jasmine.createSpy('rj') + apiService.getUserToSelectRegion = [ + { + message: 'test', + promise: null, + rs: rsSpy, + rj: rjSpy, + } + ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(rsSpy).not.toHaveBeenCalled() + expect(nextSpy).toHaveBeenCalled() + expect(rjSpy).not.toHaveBeenCalled() + }) + }) - expect(nextSpy1).not.toHaveBeenCalled() - expect(rsSpy1).not.toHaveBeenCalled() - expect(rjSpy1).not.toHaveBeenCalled() + describe('> if spec is set', () => { + describe('> if spec is set to PARCELLATION_REGION', () => { - const nextSpy2 = jasmine.createSpy('next2') - fn(nextSpy2) + it('> mouseoversegment.length === 0, will not call next, will not rs, will not call rj', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy = jasmine.createSpy('rs') + const rjSpy = jasmine.createSpy('rj') + apiService.getUserToSelectRegion = [ + { + message: 'test', + promise: null, + spec: { + type: 'PARCELLATION_REGION' + }, + rs: rsSpy, + rj: rjSpy, + } + ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(rsSpy).not.toHaveBeenCalled() + expect(nextSpy).toHaveBeenCalled() + expect(rjSpy).not.toHaveBeenCalled() + }) + + it('> mouseoversegment.length > 0, will not call next, will call rs', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const mockSegment = { + layer: { + name: 'apple' + }, + segment: { + name: 'bananas' + } + } + mockGetMouseOverSegments = [ mockSegment ] - expect(nextSpy2).not.toHaveBeenCalled() - expect(rsSpy1).toHaveBeenCalledWith(mockSegment) - expect(rjSpy1).not.toHaveBeenCalled() + const rsSpy = jasmine.createSpy('rs') + const rjSpy = jasmine.createSpy('rj') + apiService.getUserToSelectRegion = [ + { + message: 'test', + promise: null, + spec: { + type: 'PARCELLATION_REGION' + }, + rs: rsSpy, + rj: rjSpy, + } + ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(rsSpy).toHaveBeenCalled() + expect(nextSpy).not.toHaveBeenCalled() + expect(rjSpy).not.toHaveBeenCalled() + }) + }) - const nextSpy3 = jasmine.createSpy('next3') - fn(nextSpy3) + describe('> if spec is set to POINT', () => { + it('> rs is called if mouseoversegment.length === 0', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy = jasmine.createSpy('rs') + const rjSpy = jasmine.createSpy('rj') + apiService.getUserToSelectRegion = [ + { + message: 'test', + promise: null, + spec: { + type: 'POINT' + }, + rs: rsSpy, + rj: rjSpy, + } + ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(rsSpy).toHaveBeenCalled() + expect(nextSpy).not.toHaveBeenCalled() + expect(rjSpy).not.toHaveBeenCalled() + }) + it('> rs is called with correct arg if mouseoversegment.length > 0', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy = jasmine.createSpy('rs') + const rjSpy = jasmine.createSpy('rj') + apiService.getUserToSelectRegion = [ + { + message: 'test', + promise: null, + spec: { + type: 'POINT' + }, + rs: rsSpy, + rj: rjSpy, + } + ] + + const nextSpy = jasmine.createSpy('next') + fn(nextSpy) + + expect(rsSpy).toHaveBeenCalledWith({ + type: 'POINT', + payload: mousePositionReal + }) + expect(nextSpy).not.toHaveBeenCalled() + expect(rjSpy).not.toHaveBeenCalled() + }) + }) - expect(nextSpy3).toHaveBeenCalled() + describe('> if multiple getUserToSelectRegion exist', () => { + it('> only the last Promise will be evaluated', () => { + const fn = TestBed.inject(OVERRIDE_NEHUBA_TOKEN as any) as (next: () => void) => void + const apiService = TestBed.inject(AtlasViewerAPIServices) + + const rsSpy1 = jasmine.createSpy('rs1') + const rjSpy1 = jasmine.createSpy('rj1') + + const rsSpy2 = jasmine.createSpy('rs2') + const rjSpy2 = jasmine.createSpy('rj2') + apiService.getUserToSelectRegion = [ + { + message: 'test1', + promise: null, + spec: { + type: 'POINT' + }, + rs: rsSpy1, + rj: rjSpy1, + }, + { + message: 'test2', + promise: null, + spec: { + type: 'PARCELLATION_REGION' + }, + rs: rsSpy2, + rj: rjSpy2, + } + ] + + const nextSpy1 = jasmine.createSpy('next1') + fn(nextSpy1) + + expect(rsSpy2).not.toHaveBeenCalled() + expect(rjSpy2).not.toHaveBeenCalled() + + expect(nextSpy1).toHaveBeenCalled() + expect(rsSpy1).not.toHaveBeenCalled() + expect(rjSpy1).not.toHaveBeenCalled() + + }) + }) + }) }) }) }) diff --git a/src/atlasViewer/atlasViewer.apiService.service.ts b/src/atlasViewer/atlasViewer.apiService.service.ts index 8aa0c991a4d648a1d990b73eb8021f2dddb5aeb7..60640949036f453d1cabb41e94515b0a68f02729 100644 --- a/src/atlasViewer/atlasViewer.apiService.service.ts +++ b/src/atlasViewer/atlasViewer.apiService.service.ts @@ -24,6 +24,7 @@ interface IRejectUserInput{ interface IGetUserSelectRegionPr{ message: string promise: Promise<any> + spec?: ICustomRegionSpec rs: (region: any) => void rj: (reject: IRejectUserInput) => void } @@ -60,15 +61,20 @@ export class AtlasViewerAPIServices implements OnDestroy{ public getUserToSelectRegion: IGetUserSelectRegionPr[] = [] public getUserToSelectRegionUI$: Subject<IGetUserSelectRegionPr[]> = new Subject() - public getUserRegionSelectHandler: () => IGetUserSelectRegionPr = () => { + public getNextUserRegionSelectHandler: () => IGetUserSelectRegionPr = () => { if (this.getUserToSelectRegion.length > 0) { - const handler = this.getUserToSelectRegion.pop() - this.getUserToSelectRegionUI$.next([...this.getUserToSelectRegion]) - return handler + return this.getUserToSelectRegion[this.getUserToSelectRegion.length - 1] } else return null } + public popUserRegionSelectHandler = () => { + if (this.getUserToSelectRegion.length > 0) { + this.getUserToSelectRegion.pop() + this.getUserToSelectRegionUI$.next([...this.getUserToSelectRegion]) + } + } + private s: Subscription[] = [] constructor( @@ -217,8 +223,32 @@ export class AtlasViewerAPIServices implements OnDestroy{ getUserConfirmation: config => this.dialogService.getUserConfirm(config), getUserToSelectARegion: message => { + console.warn(`interactiveViewer.uiHandle.getUserToSelectARegion is becoming deprecated. Use getUserToSelectRoi instead`) + const obj = { + message, + promise: null, + rs: null, + rj: null + } + const pr = new Promise((rs, rj) => { + obj.rs = rs + obj.rj = rj + }) + + obj.promise = pr + + this.getUserToSelectRegion.push(obj) + this.getUserToSelectRegionUI$.next([...this.getUserToSelectRegion]) + this.zone.run(() => { + + }) + return pr + }, + getUserToSelectRoi: (message: string, spec: ICustomRegionSpec) => { + if (!spec || !spec.type) throw new Error(`spec.type must be defined for getUserToSelectRoi`) const obj = { message, + spec, promise: null, rs: null, rj: null @@ -331,7 +361,8 @@ export interface IInteractiveViewerInterface { getUserInput: (config: IGetUserInputConfig) => Promise<string> getUserConfirmation: (config: IGetUserConfirmation) => Promise<any> getUserToSelectARegion: (selectingMessage: any) => Promise<any> - cancelPromise: (pr) => void + getUserToSelectRoi: (selectingMessage: string, spec?: ICustomRegionSpec) => Promise<any> + cancelPromise: (pr: Promise<any>) => void } pluginControl: { @@ -355,16 +386,63 @@ export interface IUserLandmark { name: string position: [number, number, number] id: string /* probably use the it to track and remove user landmarks */ - highlight: boolean + color: [ number, number, number ] +} + +export enum EnumCustomRegion{ + POINT = 'POINT', + PARCELLATION_REGION = 'PARCELLATION_REGION', } -export const overrideNehubaClickFactory = (apiService: AtlasViewerAPIServices, getMouseoverSegments: () => any [] ) => { +export interface ICustomRegionSpec{ + type: string // type of EnumCustomRegion +} + +export const overrideNehubaClickFactory = (apiService: AtlasViewerAPIServices, getState: () => any ) => { return (next: () => void) => { - const moSegments = getMouseoverSegments() - if (!!moSegments && Array.isArray(moSegments) && moSegments.length > 0) { - const { rs } = apiService.getUserRegionSelectHandler() || {} - if (!!rs) { - return rs(moSegments[0]) + const { state, other } = getState() + const moSegments = state?.uiState?.mouseOverSegments + const { mousePositionReal } = other || {} + const { rs, spec } = apiService.getNextUserRegionSelectHandler() || {} + if (!!rs) { + + /** + * getROI api + */ + if (spec) { + + /** + * if spec of overwrite click is for a point + */ + if (spec.type === EnumCustomRegion.POINT) { + apiService.popUserRegionSelectHandler() + return rs({ + type: spec.type, + payload: mousePositionReal + }) + } + + /** + * if spec of overwrite click is for a point + */ + if (spec.type === EnumCustomRegion.PARCELLATION_REGION) { + if (!!moSegments && Array.isArray(moSegments) && moSegments.length > 0) { + apiService.popUserRegionSelectHandler() + return rs({ + type: spec.type, + payload: moSegments + }) + } + } + } else { + /** + * selectARegion API + * TODO deprecate + */ + if (!!moSegments && Array.isArray(moSegments) && moSegments.length > 0) { + apiService.popUserRegionSelectHandler() + return rs(moSegments[0]) + } } } next() diff --git a/src/main.module.ts b/src/main.module.ts index be401e8923810618d16b6bae7e6a5413e241b61d..51e875ff0926cbfba5f0d487c1b93b4786a11773 100644 --- a/src/main.module.ts +++ b/src/main.module.ts @@ -1,6 +1,6 @@ import { DragDropModule } from '@angular/cdk/drag-drop' import { CommonModule } from "@angular/common"; -import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core"; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule, InjectionToken } from "@angular/core"; import { FormsModule } from "@angular/forms"; import { StoreModule, Store, ActionReducer } from "@ngrx/store"; import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.module' @@ -38,7 +38,7 @@ import { UtilModule } from "src/util"; import { SpotLightModule } from 'src/spotlight/spot-light.module' import { TryMeComponent } from "./ui/tryme/tryme.component"; import { MouseHoverDirective, MouseOverIconPipe, MouseOverTextPipe } from "./atlasViewer/mouseOver.directive"; -import { UiStateUseEffect, getMouseoverSegmentsFactory, GET_MOUSEOVER_SEGMENTS_TOKEN } from "src/services/state/uiState.store"; +import { UiStateUseEffect } from "src/services/state/uiState.store"; import { AtlasViewerHistoryUseEffect } from "./atlasViewer/atlasViewer.history.service"; import { PluginServiceUseEffect } from './services/effect/pluginUseEffect'; import { TemplateCoordinatesTransformation } from "src/services/templateCoordinatesTransformation.service"; @@ -56,6 +56,7 @@ import 'src/res/css/version.css' import 'src/theme.scss' import { DatasetPreviewGlue, datasetPreviewMetaReducer, IDatasetPreviewGlue, GlueEffects } from './glue'; import { viewerStateHelperReducer, viewerStateFleshOutDetail, viewerStateMetaReducers, ViewerStateHelperEffect } from './services/state/viewerState.store.helper'; +import { take } from 'rxjs/operators'; export function debug(reducer: ActionReducer<any>): ActionReducer<any> { return function(state, action) { @@ -65,7 +66,8 @@ export function debug(reducer: ActionReducer<any>): ActionReducer<any> { return reducer(state, action); }; } - + +export const GET_STATE_SNAPSHOT_TOKEN = new InjectionToken('GET_STATE_SNAPSHOT_TOKEN') @NgModule({ imports : [ @@ -155,12 +157,30 @@ export function debug(reducer: ActionReducer<any>): ActionReducer<any> { useFactory: overrideNehubaClickFactory, deps: [ AtlasViewerAPIServices, - GET_MOUSEOVER_SEGMENTS_TOKEN + GET_STATE_SNAPSHOT_TOKEN ] }, { - provide: GET_MOUSEOVER_SEGMENTS_TOKEN, - useFactory: getMouseoverSegmentsFactory, + provide: GET_STATE_SNAPSHOT_TOKEN, + useFactory: (store: Store<any>) => { + return () => { + const other: any = {} + let state + // rather than commiting mousePositionReal in state via action, do a single subscription instead. + // otherwise, the state gets updated way too often + if (window && (window as any).nehubaViewer) { + (window as any).nehubaViewer.mousePosition.inRealSpace + .take(1) + .subscribe(floatArr => { + other.mousePositionReal = floatArr && Array.from(floatArr).map((val: number) => val / 1e6) + }) + } + store.pipe( + take(1) + ).subscribe(v => state = v) + return { state, other } + } + }, deps: [ Store ] }, { diff --git a/src/plugin_examples/plugin_api.md b/src/plugin_examples/plugin_api.md index f2860cdee059fda4503534d222a99f41b6146112..425daa034f1679b47c29ddeadcc6e53e9d5d7389 100644 --- a/src/plugin_examples/plugin_api.md +++ b/src/plugin_examples/plugin_api.md @@ -166,18 +166,45 @@ window.interactiveViewer } ``` - *getUserToSelectARegion(message)* returns a `Promise` + + **To be deprecated** + + _input_ + + | input | type | desc | + | --- | --- | --- | + | message | `string` | human readable message displayed to the user | + | spec.type | `'POINT'` `'PARCELLATION_REGION'` **default** | type of region to be returned. | + + _returns_ + + `Promise`, resolves to return array of region clicked, rejects with error object `{ userInitiated: boolean }` + + Requests user to select a region of interest. Resolving to the region selected by the user. Rejects if either user cancels by pressing `Esc` or `Cancel`, or by developer calling `cancelPromise` + + - *getUserToSelectRoi(message, spec)* returns a `Promise` _input_ | input | type | desc | | --- | --- | --- | | message | `string` | human readable message displayed to the user | + | spec.type | `POINT` `PARCELLATION_REGION` | type of ROI to be returned. | _returns_ - `Promise`, resolves to return `RegionSelectedByUser`, rejects with error object `{ userInitiated: boolean }` + `Promise` + + **resolves**: return `{ type, payload }`. `type` is the same as `spec.type`, and `payload` differs depend on the type requested: + + | type | payload | example | + | --- | --- | --- | + | `POINT` | array of number in mm | `[12.2, 10.1, -0.3]` | + | `PARCELLATION_REGOIN` | non empty array of region selected | `[{ "layer": { "name" : " viewer specific layer name " }, "segment": {} }]` | + + **rejects**: with error object `{ userInitiated: boolean }` - Requests user to select a parcellation region, displaying the message. Resolving to the region selected by the user. Rejects if either user cancels by pressing `Esc` or `Cancel`, or by developer calling `cancelPromise` + Requests user to select a region of interest. If the `spec.type` input is missing, it is assumed to be `'PARCELLATION_REGION'`. Resolving to the region selected by the user. Rejects if either user cancels by pressing `Esc` or `Cancel`, or by developer calling `cancelPromise` - *cancelPromise(promise)* returns `void` diff --git a/src/services/state/uiState.store.spec.ts b/src/services/state/uiState.store.spec.ts index 3ee389e6ade78280cd3ac84fbc0991180dc924a2..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 --- a/src/services/state/uiState.store.spec.ts +++ b/src/services/state/uiState.store.spec.ts @@ -1,65 +0,0 @@ -import { TestBed, async } from "@angular/core/testing" -import { Component, Inject } from "@angular/core" -import { getMouseoverSegmentsFactory } from "./uiState.store" -import { Store } from "@ngrx/store" -import { provideMockStore } from "@ngrx/store/testing" -import { defaultRootState } from "../stateStore.service" - -const INJECTION_TOKEN = `INJECTION_TOKEN` - -@Component({ - template: '' -}) -class TestCmp{ - constructor( - @Inject(INJECTION_TOKEN) public getMouseoverSegments: Function - ){ - - } -} - -const dummySegment = { - layer: { - name: 'apple' - }, - segment: { - hello: 'world' - } -} - -describe('getMouseoverSegmentsFactory', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ - TestCmp - ], - providers: [ - { - provide: INJECTION_TOKEN, - useFactory: getMouseoverSegmentsFactory, - deps: [ Store ] - }, - provideMockStore({ - initialState: { - ...defaultRootState, - uiState: { - ...defaultRootState.uiState, - mouseOverSegments: [ dummySegment ] - } - } - }) - ] - }).compileComponents() - })) - - it('should compile component', () => { - const fixture = TestBed.createComponent(TestCmp) - expect(fixture).toBeTruthy() - }) - - it('function should return dummy segment', () => { - const fixutre = TestBed.createComponent(TestCmp) - const result = fixutre.componentInstance.getMouseoverSegments() - expect(result).toEqual([dummySegment]) - }) -}) \ No newline at end of file diff --git a/src/services/state/uiState.store.ts b/src/services/state/uiState.store.ts index 68ea3630fcc45e031addf8ce6dae518de5fc4603..a3969dd32db093e163891ac794ce2f4c0efa5041 100644 --- a/src/services/state/uiState.store.ts +++ b/src/services/state/uiState.store.ts @@ -192,20 +192,6 @@ export interface ActionInterface extends Action { payload: any } -export const GET_MOUSEOVER_SEGMENTS_TOKEN = `GET_MOUSEOVER_SEGMENTS_TOKEN` - -export const getMouseoverSegmentsFactory = (store: Store<IavRootStoreInterface>) => { - return () => { - let moSegments - store.pipe( - select('uiState'), - select('mouseOverSegments'), - take(1) - ).subscribe(v => moSegments = v) - return moSegments - } -} - @Injectable({ providedIn: 'root', })