Skip to content
Snippets Groups Projects
Commit 771c1d08 authored by Xiao Gui's avatar Xiao Gui
Browse files

feat: expmt display plotly neuron on message evt

parent b8521bd9
No related branches found
No related tags found
No related merge requests found
/* eslint-disable @typescript-eslint/no-empty-function */
import {Injectable, NgZone, Optional, Inject, OnDestroy, InjectionToken} from "@angular/core";
import { MatSnackBar } from "@angular/material/snack-bar";
import { select, Store } from "@ngrx/store";
import { Observable, Subject, Subscription, from, race, of, } from "rxjs";
import { distinctUntilChanged, map, filter, startWith, switchMap, catchError, mapTo, take } from "rxjs/operators";
......@@ -35,12 +36,21 @@ interface IGetUserSelectRegionPr{
export const CANCELLABLE_DIALOG = 'CANCELLABLE_DIALOG'
export const GET_TOAST_HANDLER_TOKEN = 'GET_TOAST_HANDLER_TOKEN'
export interface ILoadMesh {
type: 'VTK',
id: string,
url: string
}
export const LOAD_MESH_TOKEN = new InjectionToken<(loadMeshParam:ILoadMesh)=>void>('LOAD_MESH_TOKEN')
@Injectable({
providedIn : 'root',
providedIn : 'root'
})
export class AtlasViewerAPIServices implements OnDestroy{
public loadMesh$ = new Subject<ILoadMesh>()
private onDestoryCb: Function[] = []
private loadedTemplates$: Observable<any>
private selectParcellation$: Observable<any>
......@@ -146,6 +156,7 @@ export class AtlasViewerAPIServices implements OnDestroy{
constructor(
private store: Store<IavRootStoreInterface>,
private dialogService: DialogService,
private snackbar: MatSnackBar,
private zone: NgZone,
private pluginService: PluginServices,
@Optional() @Inject(CANCELLABLE_DIALOG) openCancellableDialog: (message: string, options: any) => () => void,
......@@ -367,6 +378,20 @@ export class AtlasViewerAPIServices implements OnDestroy{
this.interactiveViewer.metadata.regionsLabelIndexMap = getLabelIndexMap(parcellation.regions)
this.interactiveViewer.metadata.layersRegionLabelIndexMap = getMultiNgIdsRegionsLabelIndexMap(parcellation)
})
this.s.push(
this.loadMesh$.subscribe(({ url, id, type }) => {
if (!this.interactiveViewer.viewerHandle) {
this.snackbar.open('No atlas loaded! Loading mesh failed!', 'Dismiss')
}
this.interactiveViewer.viewerHandle?.loadLayer({
[id]: {
type: 'mesh',
source: `vtk://${url}`
}
})
})
)
}
ngOnDestroy(){
......
import { Injectable } from "@angular/core";
import { fromEvent } from "rxjs";
import { filter, take } from "rxjs/operators";
/* telling webpack to pack the worker file */
import '../util/worker.js'
......@@ -8,10 +10,32 @@ import '../util/worker.js'
*/
export const worker = new Worker('worker.js')
interface IWorkerMessage {
method: string
param: any
}
@Injectable({
providedIn: 'root',
})
export class AtlasWorkerService {
public worker = worker
async sendMessage(data: IWorkerMessage){
const newUuid = crypto.getRandomValues(new Uint32Array(1))[0].toString(16)
this.worker.postMessage({
id: newUuid,
...data
})
const message = await fromEvent(this.worker, 'message').pipe(
filter((message: MessageEvent) => message.data.id && message.data.id === newUuid),
take(1)
).toPromise()
const { data: returnData } = message as MessageEvent
const { id, ...rest } = returnData
return rest
}
}
import { HttpClient } from '@angular/common/http'
import { ComponentFactory, ComponentFactoryResolver, Injectable, ViewContainerRef, Inject } from "@angular/core";
import { ComponentFactory, ComponentFactoryResolver, Injectable, ViewContainerRef, Inject, InjectionToken } from "@angular/core";
import { PLUGINSTORE_ACTION_TYPES } from "src/services/state/pluginState.store";
import { IavRootStoreInterface, isDefined } from 'src/services/stateStore.service'
import { PluginUnit } from "./pluginUnit.component";
import { select, Store } from "@ngrx/store";
import { BehaviorSubject, merge, Observable, of, zip } from "rxjs";
import { BehaviorSubject, merge, Observable, of, Subject, zip } from "rxjs";
import { filter, map, shareReplay, switchMap, catchError } from "rxjs/operators";
import { LoggingService } from 'src/logging';
import { PluginHandler } from 'src/util/pluginHandler';
......
import { DragDropModule } from '@angular/cdk/drag-drop'
import { CommonModule } from "@angular/common";
import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from "@angular/core";
import { CUSTOM_ELEMENTS_SCHEMA, InjectionToken, NgModule } from "@angular/core";
import { FormsModule } from "@angular/forms";
import { StoreModule, ActionReducer } from "@ngrx/store";
import { AngularMaterialModule } from 'src/ui/sharedModules/angularMaterial.module'
......@@ -14,7 +14,7 @@ import { GetNamesPipe } from "./util/pipes/getNames.pipe";
import { HttpClientModule } from "@angular/common/http";
import { EffectsModule } from "@ngrx/effects";
import { AtlasViewerAPIServices, CANCELLABLE_DIALOG, GET_TOAST_HANDLER_TOKEN, API_SERVICE_SET_VIEWER_HANDLE_TOKEN, setViewerHandleFactory } from "./atlasViewer/atlasViewer.apiService.service";
import { AtlasViewerAPIServices, CANCELLABLE_DIALOG, GET_TOAST_HANDLER_TOKEN, API_SERVICE_SET_VIEWER_HANDLE_TOKEN, setViewerHandleFactory, LOAD_MESH_TOKEN, ILoadMesh } from "./atlasViewer/atlasViewer.apiService.service";
import { AtlasWorkerService } from "./atlasViewer/atlasViewer.workerService.service";
import { ModalUnit } from "./atlasViewer/modalUnit/modalUnit.component";
import { TransformOnhoverSegmentPipe } from "./atlasViewer/onhoverSegment.pipe";
......@@ -242,6 +242,15 @@ export function debug(reducer: ActionReducer<any>): ActionReducer<any> {
deps: [
ClickInterceptorService
]
},
{
provide: LOAD_MESH_TOKEN,
useFactory: (apiService: AtlasViewerAPIServices) => {
return (loadMeshParam: ILoadMesh) => apiService.loadMesh$.next(loadMeshParam)
},
deps: [
AtlasViewerAPIServices
]
}
],
bootstrap : [
......
import { NgModule, Optional } from "@angular/core";
import { Inject, NgModule, Optional } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { MatSnackBar } from "@angular/material/snack-bar";
import { AtlasViewerAPIServices } from "src/atlasViewer/atlasViewer.apiService.service";
import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service";
import { LOAD_MESH_TOKEN, ILoadMesh } from "src/atlasViewer/atlasViewer.apiService.service";
import { ComponentsModule } from "src/components";
import { ConfirmDialogComponent } from "src/components/confirmDialog/confirmDialog.component";
import { AngularMaterialModule } from "src/ui/sharedModules/angularMaterial.module";
......@@ -21,7 +24,10 @@ export class MesssagingModule{
constructor(
private dialog: MatDialog,
@Optional() private apiService: AtlasViewerAPIServices
private snackbar: MatSnackBar,
private worker: AtlasWorkerService,
@Optional() private apiService: AtlasViewerAPIServices,
@Optional() @Inject(LOAD_MESH_TOKEN) private loadMesh: (loadMeshParam: ILoadMesh) => void
){
window.addEventListener('message', async ({ data, origin, source }) => {
......@@ -83,7 +89,6 @@ export class MesssagingModule{
}
async processMessage({ method, param }){
console.log({ method, param })
if (method === 'dummyMethod') {
return 'OK'
......@@ -99,6 +104,27 @@ export class MesssagingModule{
return 'OK'
}
if (method === '_tmp:plotly') {
const isLoadingSnack = this.snackbar.open(`Loading plotly mesh ...`)
const resp = await this.worker.sendMessage({
method: `PROCESS_PLOTLY`,
param
})
isLoadingSnack?.dismiss()
const meshId = 'bobby'
if (this.loadMesh) {
const { objectUrl } = resp.result || {}
this.loadMesh({
type: 'VTK',
id: meshId,
url: objectUrl
})
} else {
this.snackbar.open(`Error: loadMesh method not injected.`)
}
return 'OK'
}
throw ({ code: 404, message: 'Method not found' })
}
......
......@@ -5,6 +5,14 @@ const validTypes = [
'PROPAGATE_PARC_REGION_ATTR'
]
const VALID_METHOD = {
PROCESS_PLOTLY: `PROCESS_PLOTLY`
}
const VALID_METHODS = [
VALID_METHOD.PROCESS_PLOTLY
]
const validOutType = [
'ASSEMBLED_LANDMARKS_VTK',
'ASSEMBLED_USERLANDMARKS_VTK',
......@@ -284,7 +292,55 @@ const processParcRegionAttr = (payload) => {
})
}
let plotyVtkUrl
onmessage = (message) => {
if (message.data.method && VALID_METHODS.indexOf(message.data.method) >= 0) {
const { id } = message.data
if (message.data.method === VALID_METHOD.PROCESS_PLOTLY) {
/**
* units in mm --> convert to nm
*/
const plotyMultiple=1e6
try {
const { data: plotlyData } = message.data.param
const { x, y, z } = plotlyData.traces[0]
const lm = []
for (const idx in x) {
if (typeof x !== 'undefined' && x !== null) {
lm.push([x[idx]*plotyMultiple, y[idx]*plotyMultiple, z[idx]*plotyMultiple])
}
}
if (plotyVtkUrl) URL.revokeObjectURL(plotyVtkUrl)
const vtkString = parseLmToVtk(lm, 1e-1)
plotyVtkUrl = URL.createObjectURL(
new Blob([ encoder.encode(vtkString) ], { type: 'application/octet-stream' })
)
postMessage({
id,
result: {
objectUrl: plotyVtkUrl
}
})
} catch (e) {
postMessage({
id,
error: {
code: 401,
message: `malformed plotly param: ${e.toString()}`
}
})
}
}
postMessage({
id,
error: {
code: 404,
message: `worker method not found`
}
})
return
}
if(validTypes.findIndex(type => type === message.data.type) >= 0){
switch(message.data.type){
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment