diff --git a/package-lock.json b/package-lock.json index ecb53104c7d5b6939da22d90b41344f8a82c2473..8e7f6b6a39ea268baf93a705910d5bae30c429ea 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "@ngrx/effects": "^14.3.2", "@ngrx/store": "^14.3.2", "acorn": "^8.4.1", - "export-nehuba": "^0.1.0-dev.7", + "export-nehuba": "^0.1.0-dev.8", "file-loader": "^6.2.0", "jszip": "^3.6.0", "postcss": "^8.3.6", @@ -26966,9 +26966,9 @@ "dev": true }, "node_modules/export-nehuba": { - "version": "0.1.0-dev.7", - "resolved": "https://registry.npmjs.org/export-nehuba/-/export-nehuba-0.1.0-dev.7.tgz", - "integrity": "sha512-hBDeOWo/OoThgfqa9RtRpYlPj0/5RwgBsoMjHKYMRqgsscoYglfPYaMSG57mANEIii4hxnsFiUUXOQTn2B2P+w==", + "version": "0.1.0-dev.8", + "resolved": "https://registry.npmjs.org/export-nehuba/-/export-nehuba-0.1.0-dev.8.tgz", + "integrity": "sha512-nSiGMclXztCG5N9tNL9xf1Q8Eq2WN2FwtjJpXEtUxsIj/rzVWdU0EkEHjv6APDNTbDA9kgU2Nc61HLqcWWdIgQ==", "dependencies": { "pako": "^1.0.6" } diff --git a/package.json b/package.json index 70a41160d17071ee9886ea4490c35ad23d394980..e0c290ded11056934fb23cf9ec04454531840cf8 100644 --- a/package.json +++ b/package.json @@ -66,7 +66,7 @@ "@ngrx/effects": "^14.3.2", "@ngrx/store": "^14.3.2", "acorn": "^8.4.1", - "export-nehuba": "^0.1.0-dev.7", + "export-nehuba": "^0.1.0-dev.8", "file-loader": "^6.2.0", "jszip": "^3.6.0", "postcss": "^8.3.6", diff --git a/src/atlasComponents/annotations/annotation.service.ts b/src/atlasComponents/annotations/annotation.service.ts index 3969bc420cdea13c69fef90bbc765de4b047e0de..f0a63f7aa298c0cad46efcd96a1dfbe452f1098b 100644 --- a/src/atlasComponents/annotations/annotation.service.ts +++ b/src/atlasComponents/annotations/annotation.service.ts @@ -167,9 +167,6 @@ export class AnnotationLayer { } private parseNgSpecType(spec: AnnotationSpec): _AnnotationSpec{ - const voxelSize = this.viewer.navigationState.voxelSize.toJSON() - const sanitizePoint = (p: [number, number, number]) => p.map((v, idx) => v / voxelSize[idx]) as [number, number, number] - const needSanitizePosition = voxelSize[0] !== 1 || voxelSize[1] !== 1 || voxelSize[2] !== 1 const overwrite: Partial<_AnnotationSpec> = {} switch (spec.type) { case "point": { @@ -187,15 +184,6 @@ export class AnnotationLayer { default: throw new Error(`overwrite type lookup failed for ${(spec as any).type}`) } - /** - * The unit of annotation(s) depends on voxel size. If it is 1,1,1 then it would be in um, but often it is not. - * If not sanitized, the annotation can be miles off. - */ - if (needSanitizePosition) { - for (const key of ['point', 'pointA', 'pointB'] ) { - if (!!spec[key]) overwrite[key] = sanitizePoint(spec[key]) - } - } return { ...spec, ...overwrite, diff --git a/src/messagingGlue.ts b/src/messagingGlue.ts index ae415e68cff96abaaf964e6606a2a93df8cbc782..994bf30d8aab393eccfa769dc1ac17f1c5fcf8ce 100644 --- a/src/messagingGlue.ts +++ b/src/messagingGlue.ts @@ -86,7 +86,8 @@ export class MessagingGlue implements IWindowMessaging, OnDestroy { "1" ], transform: transform, - clType: 'customlayer/nglayer' as const + clType: 'customlayer/nglayer' as const, + type: 'segmentation', } this.store.dispatch( diff --git a/src/util/periodic.service.ts b/src/util/periodic.service.ts new file mode 100644 index 0000000000000000000000000000000000000000..e3e280cbc541f9a891dc6d7fd36f54dbb5ef385d --- /dev/null +++ b/src/util/periodic.service.ts @@ -0,0 +1,57 @@ +import { Injectable } from "@angular/core"; +import { Subject, combineLatest, interval, merge } from "rxjs"; +import { filter, map, scan } from "rxjs/operators"; +import { getUuid } from "./fn"; + +type Queue = { + callback: () => boolean + uuid: string +} + +@Injectable({ + providedIn: 'root' +}) +export class PeriodicSvc{ + #queue$ = new Subject<Queue>() + #dequeue$ = new Subject<Queue>() + #scannedQueue$ = merge<{ queue?: Queue, dequeue?: Queue }>( + this.#queue$.pipe( + map(queue => ({ queue })), + ), + this.#dequeue$.pipe( + map(dequeue => ({ dequeue })) + ) + ).pipe( + scan((acc, curr) => { + const { queue, dequeue } = curr + if (queue) { + return [...acc, queue] + } + if (dequeue) { + return acc.filter(q => q.uuid !== dequeue.uuid) + } + console.warn(`neither queue nor dequeue were defined!`) + return acc + }, [] as Queue[]) + ) + + addToQueue(callback: () => boolean){ + this.#queue$.next({ callback, uuid: getUuid() }) + } + constructor(){ + combineLatest([ + this.#scannedQueue$, + interval(160) + ]).pipe( + map(([queues, _]) => queues), + filter(queues => queues.length > 0), + ).subscribe(queues => { + for (const queue of queues) { + const { callback } = queue + if (callback()) { + this.#dequeue$.next(queue) + } + } + }) + } +} diff --git a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts index 073893847ad53cd310d9252333f7124a4031147d..1bdcedc1685bc6605bb95f56f9e881daebadf6f0 100644 --- a/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts +++ b/src/viewerModule/nehuba/nehubaViewer/nehubaViewer.component.ts @@ -13,6 +13,7 @@ import { IColorMap, SET_COLORMAP_OBS, SET_LAYER_VISIBILITY } from "../layerCtrl. */ import { INgLayerCtrl, NG_LAYER_CONTROL, SET_SEGMENT_VISIBILITY, TNgLayerCtrl } from "../layerCtrl.service/layerCtrl.util"; import { NgCoordinateSpace, Unit } from "../types"; +import { PeriodicSvc } from "src/util/periodic.service"; function translateUnit(unit: Unit) { if (unit === "m") { @@ -118,6 +119,7 @@ export class NehubaViewerUnit implements OnDestroy { constructor( public elementRef: ElementRef, private log: LoggingService, + private periodicSvc: PeriodicSvc, @Inject(IMPORT_NEHUBA_INJECT_TOKEN) getImportNehubaPr: () => Promise<any>, @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) private nehubaViewer$: Subject<NehubaViewerUnit>, @Optional() @Inject(SET_MESHES_TO_LOAD) private injSetMeshesToLoad$: Observable<IMeshesToLoad>, @@ -475,6 +477,27 @@ export class NehubaViewerUnit implements OnDestroy { /* if the layer exists, it will not be loaded */ !viewer.layerManager.getLayerByName(key)) .map(key => { + /** + * new implementation of neuroglancer treats swc as a mesh layer of segmentation layer + * But it cannot *directly* be accessed by nehuba's setMeshesToLoad, since it filters by + * UserSegmentationLayer. + * + * The below monkey patch sets the mesh to load, allow the SWC to be shown + */ + const isSwc = layerObj[key]['source'].includes("swc://") + const hasSegment = (layerObj[key]["segments"] || []).length > 0 + if (isSwc && hasSegment) { + this.periodicSvc.addToQueue( + () => { + const layer = viewer.layerManager.getLayerByName(key) + if (!(layer?.layer)) { + return false + } + layer.layer.displayState.visibleSegments.setMeshesToLoad([1]) + return true + } + ) + } viewer.layerManager.addManagedLayer( viewer.layerSpecification.getLayer(key, layerObj[key])) diff --git a/src/viewerModule/nehuba/userLayers/service.ts b/src/viewerModule/nehuba/userLayers/service.ts index 0bc5bb32e6dbf1a727144c32006856f8156e3911..41d16e71bc3e20aa74f717d11ec8a598d13b3c42 100644 --- a/src/viewerModule/nehuba/userLayers/service.ts +++ b/src/viewerModule/nehuba/userLayers/service.ts @@ -77,6 +77,7 @@ export class UserLayerService implements OnDestroy { options: { segments: ["1"], transform: xform, + type: "segmentation" }, } } diff --git a/third_party/vanilla.html b/third_party/vanilla.html index 38206ec40b244a8b3011c6850dc46aa41f047b2f..be223e1e38ab861e649e4c4666e894d0a48c6f8c 100644 --- a/third_party/vanilla.html +++ b/third_party/vanilla.html @@ -8,6 +8,7 @@ <script src="main.bundle.js"></script> <link rel="stylesheet" href="vanilla_styles.css"> + <link rel="stylesheet" href="main.css"> </head> <body> <div id="neuroglancer-container"></div>