diff --git a/src/ui/databrowserModule/databrowser.service.ts b/src/ui/databrowserModule/databrowser.service.ts
index 65be98caebc16638f21d51d78a1f54469cd716a7..24b811e80dc8983d10183d068677123e2a8c3473 100644
--- a/src/ui/databrowserModule/databrowser.service.ts
+++ b/src/ui/databrowserModule/databrowser.service.ts
@@ -4,8 +4,9 @@ import { ViewerConfiguration } from "src/services/state/viewerConfig.store";
import { SELECT_REGIONS, extractLabelIdx, CHANGE_NAVIGATION, DataEntry, File, safeFilter, isDefined, getLabelIndexMap, FETCHED_DATAENTRIES, SELECT_PARCELLATION, ADD_NG_LAYER, NgViewerStateInterface, REMOVE_NG_LAYER } from "src/services/stateStore.service";
import { WidgetServices } from "src/atlasViewer/widgetUnit/widgetService.service";
import { map, distinctUntilChanged, filter, debounceTime } from "rxjs/operators";
-import { Subscription, combineLatest, Observable, BehaviorSubject } from "rxjs";
+import { Subscription, combineLatest, Observable, BehaviorSubject, fromEvent } from "rxjs";
import { AtlasViewerConstantsServices } from "src/atlasViewer/atlasViewer.constantService.service";
+import { AtlasWorkerService } from "src/atlasViewer/atlasViewer.workerService.service";
export function temporaryFilterDataentryName(name: string):string{
return /autoradiography/.test(name)
@@ -27,6 +28,9 @@ export class DatabrowserService implements OnDestroy{
public selectedRegions$: Observable<any[]>
public selectedRegions: any[] = []
+ public rebuiltSelectedRegions: any[] = []
+ public rebuiltSomeSelectedRegions: any[] = []
+
public regionsLabelIndexMap: Map<number, any> = new Map()
public fetchingFlag: boolean = false
@@ -42,7 +46,8 @@ export class DatabrowserService implements OnDestroy{
constructor(
private constantService: AtlasViewerConstantsServices,
private store: Store<ViewerConfiguration>,
- private widgetService: WidgetServices
+ private widgetService: WidgetServices,
+ private workerService: AtlasWorkerService
){
this.subscriptions.push(
@@ -86,7 +91,15 @@ export class DatabrowserService implements OnDestroy{
)
this.subscriptions.push(
- this.selectedRegions$.subscribe(r => this.selectedRegions = r)
+ this.selectedRegions$.subscribe(r => {
+ this.selectedRegions = r
+ console.log(r)
+ this.workerService.worker.postMessage({
+ type: 'BUILD_REGION_SELECTION_TREE',
+ selectedRegions: r,
+ regions: this.selectedParcellation.regions
+ })
+ })
)
this.fetchDataObservable$ = combineLatest(
@@ -110,6 +123,21 @@ export class DatabrowserService implements OnDestroy{
debounceTime(16)
).subscribe((param : [string, string, null] ) => this.fetchData(param[0], param[1]))
)
+
+ this.subscriptions.push(
+ fromEvent(this.workerService.worker, 'message').pipe(
+ filter((message:MessageEvent) => message && message.data && message.data.type === 'RETURN_REBUILT_REGION_SELECTION_TREE'),
+ map(message => message.data),
+ ).subscribe((payload:any) => {
+ /**
+ * rebuiltSelectedRegion contains super region that are
+ * selected as a result of all of its children that are selectted
+ */
+ const { rebuiltSelectedRegions, rebuiltSomeSelectedRegions } = payload
+ this.rebuiltSomeSelectedRegions = rebuiltSomeSelectedRegions
+ this.rebuiltSelectedRegions = rebuiltSelectedRegions
+ })
+ )
}
ngOnDestroy(){
@@ -117,12 +145,25 @@ export class DatabrowserService implements OnDestroy{
}
public updateRegionSelection(regions: any[]) {
+ const filteredRegion = regions.filter(r => r.labelIndex !== null && typeof r.labelIndex !== 'undefined')
this.store.dispatch({
type: SELECT_REGIONS,
- selectRegions: regions
+ selectRegions: filteredRegion
})
}
+ public deselectRegion(region) {
+ const regionsToDelect = []
+ const recursiveFlatten = (region:any) => {
+ regionsToDelect.push(region)
+ if (region.children && region.children.map)
+ region.children.map(recursiveFlatten)
+ }
+ recursiveFlatten(region)
+ const selectedRegions = this.selectedRegions.filter(r => !regionsToDelect.some(deR => deR.name === r.name))
+ this.updateRegionSelection(selectedRegions)
+ }
+
public changeParcellation({ current, previous }){
if (previous && current && current.name === previous.name)
return
@@ -134,13 +175,13 @@ export class DatabrowserService implements OnDestroy{
public singleClickRegion(region) {
const selectedSet = new Set(extractLabelIdx(region))
- const intersection = new Set([...this.selectedRegions.map(r => r.labelIndex)].filter(v => selectedSet.has(v)))
- this.store.dispatch({
- type: SELECT_REGIONS,
- selectRegions: intersection.size > 0
- ? this.selectedRegions.filter(v => !intersection.has(v.labelIndex))
- : this.selectedRegions.concat([...selectedSet].map(idx => this.regionsLabelIndexMap.get(idx)))
- })
+ const filteredSelectedRegion = this.selectedRegions.filter(r => r.labelIndex)
+ const intersection = new Set([...filteredSelectedRegion.map(r => r.labelIndex)].filter(v => selectedSet.has(v)))
+ this.updateRegionSelection(
+ intersection.size > 0
+ ? filteredSelectedRegion.filter(v => !intersection.has(v.labelIndex))
+ : filteredSelectedRegion.concat([...selectedSet].map(idx => this.regionsLabelIndexMap.get(idx)))
+ )
}
public doubleClickRegion(region) {
diff --git a/src/ui/databrowserModule/databrowser/databrowser.component.ts b/src/ui/databrowserModule/databrowser/databrowser.component.ts
index 07890a3b0221645facf01409ebddd9c25b36ad2f..182a0cea7e9e06115ff764424b94808e9133231b 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.component.ts
+++ b/src/ui/databrowserModule/databrowser/databrowser.component.ts
@@ -3,6 +3,7 @@ import { DataEntry } from "src/services/stateStore.service";
import { Subscription, merge } from "rxjs";
import { DatabrowserService } from "../databrowser.service";
import { ModalityPicker } from "../modalityPicker/modalityPicker.component";
+import { skip } from "rxjs/operators";
@Component({
selector : 'data-browser',
@@ -23,6 +24,10 @@ export class DataBrowser implements OnDestroy,OnInit{
return this.dbService.selectedRegions
}
+ get rebuiltSomeSelectedRegions(){
+ return this.dbService.rebuiltSomeSelectedRegions
+ }
+
get selectedParcellation(){
return this.dbService.selectedParcellation
}
@@ -65,7 +70,7 @@ export class DataBrowser implements OnDestroy,OnInit{
ngOnInit(){
this.subscriptions.push(
merge(
- this.dbService.selectedRegions$,
+ // this.dbService.selectedRegions$,
this.dbService.fetchDataObservable$
).subscribe(() => {
this.resetCurrentPage()
@@ -96,14 +101,11 @@ export class DataBrowser implements OnDestroy,OnInit{
public showParcellationList: boolean = false
+ /**
+ * when user clicks x on region selector
+ */
deselectRegion(region:any){
- /**
- * when user clicks x on region selector
- */
-
- this.dbService.updateRegionSelection(
- this.selectedRegions.filter(r => r.name !== region.name)
- )
+ this.dbService.deselectRegion(region)
}
uncheckModality(modality:string){
diff --git a/src/ui/databrowserModule/databrowser/databrowser.template.html b/src/ui/databrowserModule/databrowser/databrowser.template.html
index 4653194a66a2cb74139b1cfe4d2aaf2376a1752a..825ebced1fb43775b8ad60a7ac8910cc41d1585d 100644
--- a/src/ui/databrowserModule/databrowser/databrowser.template.html
+++ b/src/ui/databrowserModule/databrowser/databrowser.template.html
@@ -91,6 +91,7 @@
<ng-template #showData>
<!-- datawrapper -->
<div
+ *ngIf="dbService.fetchedDataEntries$ | async | filterDataEntriesByMethods : modalityFilter | filterDataEntriesByRegion : rebuiltSomeSelectedRegions as filteredDataEntry"
[ngStyle]="filePreviewName ? {'transform': 'translateX(-50%)'} : {}"
class="dataEntryWrapper">
@@ -100,8 +101,8 @@
<i *ngIf="dbService.fetchedDataEntries$ | async">
{{ (dbService.fetchedDataEntries$ | async).length }} total results.
<span
- *ngIf="selectedRegions.length + modalityFilter.length > 0 ">
- {{ (dbService.fetchedDataEntries$ | async | filterDataEntriesByMethods : modalityFilter | filterDataEntriesByRegion : selectedRegions).length }}
+ *ngIf="rebuiltSomeSelectedRegions.length + modalityFilter.length > 0 ">
+ {{ filteredDataEntry.length }}
filtered results.
<a
href="#"
@@ -117,7 +118,7 @@
<div *ngIf="dbService.fetchedDataEntries$ | async">
<dataset-viewer
class="mt-1"
- *ngFor="let dataset of dbService.fetchedDataEntries$ | async | filterDataEntriesByMethods : modalityFilter | filterDataEntriesByRegion : selectedRegions | searchResultPagination : currentPage : hitsPerPage"
+ *ngFor="let dataset of filteredDataEntry | searchResultPagination : currentPage : hitsPerPage"
(showPreviewDataset)="onShowPreviewDataset($event)"
[dataset]="dataset">
</dataset-viewer>
@@ -127,7 +128,7 @@
*ngIf="dbService.fetchedDataEntries$ | async"
(paginationChange)="currentPage = $event"
[hitsPerPage]="hitsPerPage"
- [total]="(dbService.fetchedDataEntries$ | async | filterDataEntriesByMethods : modalityFilter | filterDataEntriesByRegion : selectedRegions).length"
+ [total]="filteredDataEntry.length"
[currentPage]="currentPage">
</pagination-component>
</div>
diff --git a/src/ui/databrowserModule/fileviewer/fileviewer.component.ts b/src/ui/databrowserModule/fileviewer/fileviewer.component.ts
index a044db495e675dfcfc22a264c06c9e0109b365e2..1048721014ffc5d81ff849ec2ccb635c2611e6ee 100644
--- a/src/ui/databrowserModule/fileviewer/fileviewer.component.ts
+++ b/src/ui/databrowserModule/fileviewer/fileviewer.component.ts
@@ -53,8 +53,6 @@ export class FileViewer implements OnChanges,OnDestroy,OnInit{
switchMap(()=>from(new Promise((rs,rj)=>{
if(!this.childChart)
return rj('chart not defined after 500ms')
-
- debugger
this.childChart.canvas.nativeElement.toBlob((blob)=>{
blob ? rs(blob) : rj('blob is undefined')
diff --git a/src/ui/databrowserModule/util/filterDataEntriesByMethods.pipe.ts b/src/ui/databrowserModule/util/filterDataEntriesByMethods.pipe.ts
index 3e010621c216d8ec9846f8273b127beedc40e5c0..b6ffded850a9f1765b736142c2eb7a1071c6b44e 100644
--- a/src/ui/databrowserModule/util/filterDataEntriesByMethods.pipe.ts
+++ b/src/ui/databrowserModule/util/filterDataEntriesByMethods.pipe.ts
@@ -8,7 +8,7 @@ import { temporaryFilterDataentryName } from '../databrowser.service'
export class FilterDataEntriesbyMethods implements PipeTransform{
public transform(dataEntries:DataEntry[],showDataMethods:string[]):DataEntry[]{
- return showDataMethods.length > 0
+ return dataEntries && showDataMethods && showDataMethods.length > 0
? dataEntries.filter(dataEntry => {
return dataEntry.activity.some(a => a.methods.some(m => showDataMethods.findIndex(dm => dm === temporaryFilterDataentryName(m)) >= 0))
})
diff --git a/src/ui/databrowserModule/util/filterDataEntriesByRegion.pipe.ts b/src/ui/databrowserModule/util/filterDataEntriesByRegion.pipe.ts
index 1924a87ccae557fbf348092dad369e1c7e67ce68..9c6208dcf613643f7618dcb3379a12a49de85c1c 100644
--- a/src/ui/databrowserModule/util/filterDataEntriesByRegion.pipe.ts
+++ b/src/ui/databrowserModule/util/filterDataEntriesByRegion.pipe.ts
@@ -7,7 +7,7 @@ import { DataEntry } from "src/services/stateStore.service";
export class FilterDataEntriesByRegion implements PipeTransform{
public transform(dataentries: DataEntry[], selectedRegions: any[]) {
- return selectedRegions.length > 0
+ return dataentries && selectedRegions && selectedRegions.length > 0
? dataentries.filter(de =>
de.parcellationRegion.some(pr => {
@@ -15,7 +15,7 @@ export class FilterDataEntriesByRegion implements PipeTransform{
* TODO: temporary hack, some dataset region name is not exactly the same as region
*/
/* https://stackoverflow.com/a/9310752/6059235 */
- const regex = new RegExp(pr.name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'))
+ const regex = new RegExp(pr.name.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'), 'i')
return selectedRegions.some(sr => regex.test(sr.name))
/**
* more correct, but probably should use UUID in the future
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index b9215eadfef0737d0e0ccf48594e784f212350ae..0cb0bf48b152b3642fddc7aaee99185b500bdfd7 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -756,6 +756,10 @@ export class NehubaContainer implements OnInit, OnDestroy{
filter(results => results[1] === null),
map(results => results[0])
).subscribe((region:any) => {
+ /**
+ * TODO
+ * region may have labelIndex as well as children
+ */
this.selectedRegionIndexSet.has(region.labelIndex) ?
this.store.dispatch({
type : SELECT_REGIONS,
diff --git a/src/util/pipes/groupDataEntriesByRegion.pipe.ts b/src/util/pipes/groupDataEntriesByRegion.pipe.ts
index 6778b49808d0483a0a357ae417d5cbf89ae794ae..f4c326b4c253340fa04c819af0b637b85c974a60 100644
--- a/src/util/pipes/groupDataEntriesByRegion.pipe.ts
+++ b/src/util/pipes/groupDataEntriesByRegion.pipe.ts
@@ -5,8 +5,7 @@ import { DataEntry } from "../../services/stateStore.service";
name : 'groupDatasetByRegion'
})
export class GroupDatasetByRegion implements PipeTransform{
- public transform(datasets:DataEntry[], regions:any[]): {region:any|null,searchResults:DataEntry[]}[]
- {
+ public transform(datasets:DataEntry[], regions:any[]): {region:any|null,searchResults:DataEntry[]}[]{
return datasets.reduce((acc,curr)=>{
return (curr.parcellationRegion && curr.parcellationRegion.length > 0)
diff --git a/src/util/worker.js b/src/util/worker.js
index 2d804bf5f8388c5b715655f97f74374bd5b6272d..ba6b1627b9adf00e861f08ba494594118bc0dc2b 100644
--- a/src/util/worker.js
+++ b/src/util/worker.js
@@ -1,5 +1,5 @@
-const validTypes = ['CHECK_MESHES', 'GET_LANDMARKS_VTK', 'GET_USERLANDMARKS_VTK']
-const validOutType = ['CHECKED_MESH', 'ASSEMBLED_LANDMARKS_VTK', 'ASSEMBLED_USERLANDMARKS_VTK']
+const validTypes = ['CHECK_MESHES', 'GET_LANDMARKS_VTK', 'GET_USERLANDMARKS_VTK', 'BUILD_REGION_SELECTION_TREE']
+const validOutType = ['CHECKED_MESH', 'ASSEMBLED_LANDMARKS_VTK', 'ASSEMBLED_USERLANDMARKS_VTK', 'RETURN_REBUILT_REGION_SELECTION_TREE']
const checkMeshes = (action) => {
@@ -219,9 +219,42 @@ const getuserLandmarksVtk = (action) => {
})
}
+const rebuildSelectedRegion = (payload) => {
+ const { selectedRegions, regions } = payload
+
+ /**
+ * active tree branch
+ * branch is active if ALL children are active
+ */
+ const activeTreeBranch = []
+ const isRegionActive = (region) => selectedRegions.some(r => r.name === region.name)
+ || region.children && region.children.length > 0 && region.children.every(isRegionActive)
+
+ /**
+ * some active tree branch
+ * branch is active if SOME children are active
+ */
+ const someActiveTreeBranch = []
+ const isSomeRegionActive = (region) => selectedRegions.some(r => r.name === region.name)
+ || region.children && region.children.length > 0 && region.children.some(isSomeRegionActive)
+
+ const handleRegion = (r) => {
+ isRegionActive(r) ? activeTreeBranch.push(r) : {}
+ isSomeRegionActive(r) ? someActiveTreeBranch.push(r) : {}
+ if (r.children && r.children.length > 0)
+ r.children.forEach(handleRegion)
+ }
+ regions.forEach(handleRegion)
+ postMessage({
+ type: 'RETURN_REBUILT_REGION_SELECTION_TREE',
+ rebuiltSelectedRegions: activeTreeBranch,
+ rebuiltSomeSelectedRegions: someActiveTreeBranch
+ })
+}
+
onmessage = (message) => {
- if(validTypes.findIndex(type => type === message.data.type)>=0){
+ if(validTypes.findIndex(type => type === message.data.type) >= 0){
switch(message.data.type){
case 'CHECK_MESHES':
checkMeshes(message.data)
@@ -232,6 +265,9 @@ onmessage = (message) => {
case 'GET_USERLANDMARKS_VTK':
getuserLandmarksVtk(message.data)
return
+ case 'BUILD_REGION_SELECTION_TREE':
+ rebuildSelectedRegion(message.data)
+ return
default:
console.warn('unhandled worker action', message)
}