diff --git a/docs/releases/v2.1.0.md b/docs/releases/v2.1.0.md new file mode 100644 index 0000000000000000000000000000000000000000..d3f114ce393da92b5ab3a3cd5f05d7979ced638c --- /dev/null +++ b/docs/releases/v2.1.0.md @@ -0,0 +1,4 @@ +# v2.1.0 + +New features: +- connectivity browsing for JuBrain atlas \ No newline at end of file diff --git a/mkdocs.yml b/mkdocs.yml index 92dd61c41987393e0908dd26212e44b5cc56b050..f6632d64cb1302a6510ab06d12f3b2c9973d4b08 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -24,7 +24,8 @@ pages: - Keyboard shortcuts: 'advanced/keyboard.md' - URL parsing: 'advanced/url.md' - Release notes: - - v2.0.2 (latest): 'releases/v2.0.2.md' + - v2.1.0: 'releases/v2.1.0.md' + - v2.0.2: 'releases/v2.0.2.md' - v2.0.1: 'releases/v2.0.1.md' - v2.0.0: 'releases/v2.0.0.md' - v0.3.0-beta: 'releases/v0.3.0-beta.md' diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts index 5fb6bb3e0e9631f309769780ef9cb7ce307129d1..cc502dab803672861858f435569f112ac4e4cf2d 100644 --- a/src/atlasViewer/atlasViewer.component.ts +++ b/src/atlasViewer/atlasViewer.component.ts @@ -12,8 +12,7 @@ import { Store, select, ActionsSubject } from "@ngrx/store"; import { isDefined, safeFilter, - SHOW_SIDE_PANEL_CONNECTIVITY, - EXPAND_SIDE_PANEL_CURRENT_VIEW, IavRootStoreInterface + IavRootStoreInterface } from "../services/stateStore.service"; import {Observable, Subscription, combineLatest, interval, merge, of} from "rxjs"; import { diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html index a542ca229d490ba2311f16ebd3d115a4e3d1aad5..7c483ae0ea6237611503867dd3cc00f04f9e52a9 100644 --- a/src/atlasViewer/atlasViewer.template.html +++ b/src/atlasViewer/atlasViewer.template.html @@ -141,11 +141,12 @@ <ng-container *ngIf="(onhoverSegmentsForFixed$ | async) as onHoverSegments"> <ng-container *ngFor="let onHoverRegion of onHoverSegments; let first = first"> + <!-- ToDo it should change - we should get information about connectivity existence from API--> <region-menu class="pe-all" [region]="onHoverRegion" [isSelected]="selectedRegions$ | async | includes : onHoverRegion : compareFn" - [hasConnectivity]="selectedParcellation && selectedParcellation.name.includes('JuBrain Cytoarchitectonic Atlas')" + [hasConnectivity]="selectedParcellation && selectedParcellation.hasAdditionalViewMode && selectedParcellation.hasAdditionalViewMode.includes('connectivity')" > </region-menu> diff --git a/src/res/ext/MNI152.json b/src/res/ext/MNI152.json index 202a4b61ec03a960b382762fd5498b4d41887908..3ce8bc85cc9c1bd30b2f6465c5cf2cb870390f18 100644 --- a/src/res/ext/MNI152.json +++ b/src/res/ext/MNI152.json @@ -10,6 +10,9 @@ "name": "JuBrain Cytoarchitectonic Atlas", "ngId": "jubrain mni152 v18 left", "auxillaryMeshIndices": [ 65535 ], + "hasAdditionalViewMode": [ + "connectivity" + ], "originDatasets":[{ "kgSchema": "minds/core/dataset/v1.0.0", "kgId": "4ac9f0bc-560d-47e0-8916-7b24da9bb0ce" diff --git a/src/res/ext/colin.json b/src/res/ext/colin.json index 30320fa120475c8464f62a60268d5e97db6c5f8d..9094492116566be46ff2869c02b27d01e40198d9 100644 --- a/src/res/ext/colin.json +++ b/src/res/ext/colin.json @@ -12,6 +12,9 @@ "auxillaryMeshIndices": [ 65535 ], + "hasAdditionalViewMode": [ + "connectivity" + ], "originDatasets": [ { "kgSchema": "minds/core/dataset/v1.0.0", diff --git a/src/services/state/uiState.store.ts b/src/services/state/uiState.store.ts index 06e3025f7204012aa2af8efb3c83d5403c87ff7f..8e962f7bd0d2075eee12e39b8a89bc5feaca19a3 100644 --- a/src/services/state/uiState.store.ts +++ b/src/services/state/uiState.store.ts @@ -16,7 +16,7 @@ export const defaultState: StateInterface = { focusedSidePanel: null, sidePanelIsOpen: true, - sidePanelManualCollapsibleView: '', + sidePanelCurrentViewContent: 'Dataset', sidePanelExploreCurrentViewIsOpen: false, snackbarMessage: null, @@ -86,16 +86,21 @@ export const getStateStore = ({ state = defaultState } = {}) => (prevState:State sidePanelExploreCurrentViewIsOpen: false } - case SHOW_SIDE_PANEL_CONNECTIVITY: + case SHOW_SIDE_PANEL_DATASET_LIST: return { ...prevState, - sidePanelManualCollapsibleView: 'Connectivity' + sidePanelCurrentViewContent: 'Dataset' } + case SHOW_SIDE_PANEL_CONNECTIVITY: + return { + ...prevState, + sidePanelCurrentViewContent: 'Connectivity' + } case HIDE_SIDE_PANEL_CONNECTIVITY: return { ...prevState, - sidePanelManualCollapsibleView: '' + sidePanelCurrentViewContent: 'Dataset' } case AGREE_COOKIE: /** @@ -147,7 +152,7 @@ export interface StateInterface{ segment: any | null }[] sidePanelIsOpen: boolean - sidePanelManualCollapsibleView: 'Connectivity' | '' | null + sidePanelCurrentViewContent: 'Connectivity' | 'Dataset' | null sidePanelExploreCurrentViewIsOpen: boolean mouseOverSegment: any | number @@ -227,6 +232,7 @@ export const MOUSEOVER_USER_LANDMARK = `MOUSEOVER_USER_LANDMARK` export const CLOSE_SIDE_PANEL = `CLOSE_SIDE_PANEL` export const OPEN_SIDE_PANEL = `OPEN_SIDE_PANEL` +export const SHOW_SIDE_PANEL_DATASET_LIST = `SHOW_SIDE_PANEL_DATASET_LIST` export const SHOW_SIDE_PANEL_CONNECTIVITY = `SHOW_SIDE_PANEL_CONNECTIVITY` export const HIDE_SIDE_PANEL_CONNECTIVITY = `HIDE_SIDE_PANEL_CONNECTIVITY` export const COLLAPSE_SIDE_PANEL_CURRENT_VIEW = `COLLAPSE_SIDE_PANEL_CURRENT_VIEW` diff --git a/src/ui/connectivityBrowser/connectivityBrowser.component.ts b/src/ui/connectivityBrowser/connectivityBrowser.component.ts index 13bb7c8cd70e5cb250aba98a41a71b10dbd34903..d75f4c6bab7c06ef83d9d67adbe63938777d4cf0 100644 --- a/src/ui/connectivityBrowser/connectivityBrowser.component.ts +++ b/src/ui/connectivityBrowser/connectivityBrowser.component.ts @@ -6,7 +6,7 @@ import { ViewChild } from "@angular/core"; import {AtlasViewerConstantsServices} from "src/atlasViewer/atlasViewer.constantService.service"; -import {Observable, Subject, Subscription} from "rxjs"; +import {fromEvent, Observable, Subscription} from "rxjs"; import {select, Store} from "@ngrx/store"; import {HIDE_SIDE_PANEL_CONNECTIVITY, isDefined, safeFilter} from "src/services/stateStore.service"; import {distinctUntilChanged, filter, map} from "rxjs/operators"; @@ -25,11 +25,11 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy { private connectivityRegion$: Observable<any> private selectedParcellation$: Observable<any> private subscriptions: Subscription[] = [] - private selectedParcellation: any - public collapseMenu = -1 + public expandMenuIndex = -1 public allRegions = [] public defaultColorMap: Map<string, Map<number, {red: number, green: number, blue: number}>> - private noConnectivityForRegion = false + public noConnectivityForParcellation = false + private areaHemisphere: string math = Math @@ -55,34 +55,39 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy { ngAfterViewInit(): void { this.subscriptions.push( this.selectedParcellation$.subscribe(parcellation => { - this.selectedParcellation = parcellation - if (parcellation && parcellation.name && parcellation.name === 'JuBrain Cytoarchitectonic Atlas') { - this.noConnectivityForRegion = false + if (parcellation && parcellation.hasAdditionalViewMode && parcellation.hasAdditionalViewMode.includes('connectivity')) { + this.noConnectivityForParcellation = false if (parcellation.regions && parcellation.regions.length) { this.allRegions = [] this.getAllRegionsFromParcellation(parcellation.regions) if (this.defaultColorMap) { - this.saveAndDisableExistingColorTemplate() + this.addNewColorMap() } } } else { - this.noConnectivityForRegion = true + this.noConnectivityForParcellation = true } }), this.connectivityRegion$.subscribe(cr => { this.region = cr - this.changeDetectionRef.detectChanges(); + this.areaHemisphere = cr.includes('left hemisphere')? ' - left hemisphere' : ' - right hemisphere' + this.changeDetectionRef.detectChanges() }) ) - this.connectivityComponentElement.nativeElement.addEventListener('connectivityDataReceived', e => { - this.connectedAreas = e.detail - if (this.connectedAreas.length > 0) this.saveAndDisableExistingColorTemplate() - }) + const connectivityData$ = fromEvent(this.connectivityComponentElement.nativeElement, 'connectivityDataReceived', { capture: true }) + const collapsedMenuIndex$ = fromEvent(this.connectivityComponentElement.nativeElement, 'collapsedMenuChanged', { capture: true }) - this.connectivityComponentElement.nativeElement.addEventListener('collapsedMenuChanged', e => { - this.collapseMenu = e.detail - }) + this.subscriptions.push( + connectivityData$.subscribe((e: CustomEvent) => { + this.connectedAreas = e.detail + if (this.connectedAreas.length > 0) this.addNewColorMap() + }), + collapsedMenuIndex$.subscribe((e: CustomEvent) => { + this.expandMenuIndex = e.detail + }), + + ) } ngOnDestroy(): void { @@ -113,14 +118,11 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy { if (r && r.ngId && r.rgb) { this.defaultColorMap.get(r.ngId).set(r.labelIndex, {red: r.rgb[0], green: r.rgb[1], blue: r.rgb[2]}) } - getWindow().interactiveViewer.viewerHandle.applyLayersColourMap(this.defaultColorMap) }) + getWindow().interactiveViewer.viewerHandle.applyLayersColourMap(this.defaultColorMap) } - saveAndDisableExistingColorTemplate() { - - - const hemisphere = this.region.includes('left hemisphere')? ' - left hemisphere' : ' - right hemisphere' + addNewColorMap() { this.defaultColorMap = new Map(getWindow().interactiveViewer.viewerHandle.getLayersSegmentColourMap()) @@ -137,15 +139,14 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy { this.connectedAreas.forEach(area => { const areaAsRegion = this.allRegions - .filter(r => r.name === area.name + hemisphere) + .filter(r => r.name === area.name + this.areaHemisphere) .map(r => r) if (areaAsRegion && areaAsRegion.length && areaAsRegion[0].ngId) // @ts-ignore map.get(areaAsRegion[0].ngId).set(areaAsRegion[0].labelIndex, {red: area.color.r, green: area.color.g, blue: area.color.b}) - - getWindow().interactiveViewer.viewerHandle.applyLayersColourMap(map) }) + getWindow().interactiveViewer.viewerHandle.applyLayersColourMap(map) } getAllRegionsFromParcellation = (regions) => { @@ -162,5 +163,5 @@ export class ConnectivityBrowserComponent implements AfterViewInit, OnDestroy { } function getWindow (): any { - return window; + return window } \ No newline at end of file diff --git a/src/ui/connectivityBrowser/connectivityBrowser.template.html b/src/ui/connectivityBrowser/connectivityBrowser.template.html index 3963b9eac18dac600c919323ca0f3c5a3a7d62af..8f05020c7364390a6b817f6506de3f7360cb409b 100644 --- a/src/ui/connectivityBrowser/connectivityBrowser.template.html +++ b/src/ui/connectivityBrowser/connectivityBrowser.template.html @@ -1,4 +1,4 @@ -<div class="w-100 h-100 overflow-auto d-block d-flex flex-column pb-2" #connectivityComponent *ngIf="!noConnectivityForRegion; else noConnectivity"> +<div class="w-100 h-100 overflow-auto d-block d-flex flex-column pb-2" #connectivityComponent *ngIf="!noConnectivityForParcellation; else noConnectivity"> <!--ToDo set show-description="true" when data will available--> <hbp-connectivity-matrix-row [region]="region" @@ -13,14 +13,14 @@ <div slot="connectedRegionMenu"> - <div class="d-flex flex-column" *ngIf="collapseMenu >= 0"> + <div class="d-flex flex-column" *ngIf="expandMenuIndex >= 0"> <mat-divider></mat-divider> <span class="mt-2 mr-2 ml-2"> - <small>Region: {{connectedAreas[collapseMenu].name}}</small> + <small>Region: {{connectedAreas[expandMenuIndex].name}}</small> <br> - <small>Number of Connection: {{connectedAreas[collapseMenu].numberOfConnections}}</small> + <small>Number of Connection: {{connectedAreas[expandMenuIndex].numberOfConnections}}</small> <br> - <small>Log(123) = {{math.log10(connectedAreas[collapseMenu].numberOfConnections)}}</small> + <small>Log(123) = {{math.log10(connectedAreas[expandMenuIndex].numberOfConnections)}}</small> </span> <div class="d-flex align-items-center justify-content-around"> <small class="d-flex flex-column align-items-center w-100"> @@ -49,7 +49,7 @@ </small> <small class="d-flex flex-column align-items-center w-100"> - <button mat-icon-button class="border" (click)="updateConnevtivityRegion(connectedAreas[collapseMenu].name)"> + <button mat-icon-button class="border" (click)="updateConnevtivityRegion(connectedAreas[expandMenuIndex].name)"> <i class="fab fa-connectdevelop mt-n1"></i> </button> Connectivity diff --git a/src/ui/parcellationRegion/region.base.ts b/src/ui/parcellationRegion/region.base.ts index 427549df3e1a3d8c6750405b90ded5c31061feed..db802685088ca59b985f41ba0eb7423fc2efbcac 100644 --- a/src/ui/parcellationRegion/region.base.ts +++ b/src/ui/parcellationRegion/region.base.ts @@ -2,7 +2,6 @@ import { Store } from "@ngrx/store"; import {EventEmitter, Input, Output} from "@angular/core"; import { VIEWERSTATE_CONTROLLER_ACTION_TYPES } from "../viewerStateController/viewerState.base"; import { - CLOSE_SIDE_PANEL, EXPAND_SIDE_PANEL_CURRENT_VIEW, IavRootStoreInterface, OPEN_SIDE_PANEL, SHOW_SIDE_PANEL_CONNECTIVITY @@ -42,7 +41,8 @@ export class RegionBase{ }) } - pushConnectivityRegion(regionName) { + showConnectivity(regionName) { + //ToDo trigger side panel opening with effect this.store$.dispatch({type: OPEN_SIDE_PANEL}) this.store$.dispatch({type: EXPAND_SIDE_PANEL_CURRENT_VIEW}) this.store$.dispatch({type: SHOW_SIDE_PANEL_CONNECTIVITY}) diff --git a/src/ui/parcellationRegion/regionMenu/regionMenu.template.html b/src/ui/parcellationRegion/regionMenu/regionMenu.template.html index 0782175873a8a2712efe70680a15aa2d74382bfa..965a0af09638ac098a63e39109c4e90d801406d3 100644 --- a/src/ui/parcellationRegion/regionMenu/regionMenu.template.html +++ b/src/ui/parcellationRegion/regionMenu/regionMenu.template.html @@ -20,7 +20,7 @@ Navigate </span> </button> - <button *ngIf="hasConnectivity" mat-button (click)="pushConnectivityRegion(region.name)"> + <button *ngIf="hasConnectivity" mat-button (click)="showConnectivity(region.name)"> <i class="fab fa-connectdevelop"></i> <span> Connectivity diff --git a/src/ui/searchSideNav/searchSideNav.component.ts b/src/ui/searchSideNav/searchSideNav.component.ts index 4bca8384e7fb43d9ec0e5c7f624e41c984bd63a4..949da2a546f735ac2951d4ad26d1965bb57c710d 100644 --- a/src/ui/searchSideNav/searchSideNav.component.ts +++ b/src/ui/searchSideNav/searchSideNav.component.ts @@ -1,8 +1,8 @@ -import { Component, Output, EventEmitter, OnInit, OnDestroy, ViewChild, TemplateRef } from "@angular/core"; +import { Component, Output, EventEmitter, OnDestroy, ViewChild, TemplateRef } from "@angular/core"; import { MatDialogRef, MatDialog, MatSnackBar } from "@angular/material"; import { NgLayerInterface } from "src/atlasViewer/atlasViewer.component"; import { LayerBrowser } from "../layerbrowser/layerbrowser.component"; -import {Observable, Subject, Subscription} from "rxjs"; +import {Observable, Subscription} from "rxjs"; import { Store, select } from "@ngrx/store"; import { map, startWith, scan, filter, mapTo } from "rxjs/operators"; import { trackRegionBy } from '../viewerStateController/regionHierachy/regionHierarchy.component' @@ -11,7 +11,6 @@ import { CLOSE_SIDE_PANEL, COLLAPSE_SIDE_PANEL_CURRENT_VIEW, EXPAND_SIDE_PANEL_CURRENT_VIEW, - OPEN_SIDE_PANEL } from "src/services/state/uiState.store"; import { SELECT_REGIONS, IavRootStoreInterface } from "src/services/stateStore.service"; @@ -35,8 +34,8 @@ export class SearchSideNav implements OnDestroy { public autoOpenSideNavDataset$: Observable<any> - sidePanelExploreCurrentViewIsOpen$: Observable<any> - sidePanelManualCollapsibleView$: Observable<any> + public sidePanelExploreCurrentViewIsOpen$: Observable<any> + public sidePanelCurrentViewContent: Observable<any> constructor( public dialog: MatDialog, @@ -59,9 +58,9 @@ export class SearchSideNav implements OnDestroy { select("sidePanelExploreCurrentViewIsOpen") ) - this.sidePanelManualCollapsibleView$ = this.store$.pipe( + this.sidePanelCurrentViewContent = this.store$.pipe( select('uiState'), - select("sidePanelManualCollapsibleView") + select("sidePanelCurrentViewContent") ) } diff --git a/src/ui/searchSideNav/searchSideNav.style.css b/src/ui/searchSideNav/searchSideNav.style.css index 373ba5c0daa9043482912ff058a7e05df980a96d..4abec449498d3a8586f333d9003d001a100ec6f4 100644 --- a/src/ui/searchSideNav/searchSideNav.style.css +++ b/src/ui/searchSideNav/searchSideNav.style.css @@ -17,3 +17,7 @@ margin-left:-1.5rem; width: calc(100% + 3rem); } + +connectivity-browser { + max-height: calc(100% - 220px); +} \ No newline at end of file diff --git a/src/ui/searchSideNav/searchSideNav.template.html b/src/ui/searchSideNav/searchSideNav.template.html index 44272b3dbb1c79d5ab5a52ff8d25ded57d0dc264..8331fba31b1645fcc3f8bb2a3935509165db40a2 100644 --- a/src/ui/searchSideNav/searchSideNav.template.html +++ b/src/ui/searchSideNav/searchSideNav.template.html @@ -23,12 +23,12 @@ </div> </viewer-state-controller> - <ng-container> - <connectivity-browser class="pe-all flex-grow-5 flex-shrink-1" style="max-height: calc(100% - 220px)" - *ngIf="(sidePanelExploreCurrentViewIsOpen$ | async) && (sidePanelManualCollapsibleView$ | async)"> + <ng-container *ngIf="(sidePanelExploreCurrentViewIsOpen$ | async)" [ngSwitch]="(sidePanelCurrentViewContent | async)"> + <connectivity-browser class="pe-all flex-grow-5 flex-shrink-1" + *ngSwitchCase = "'Connectivity'"> </connectivity-browser> - <data-browser *ngIf="(sidePanelExploreCurrentViewIsOpen$ | async) && !(sidePanelManualCollapsibleView$ | async)" + <data-browser *ngSwitchCase = "'Dataset'" class="pe-all flex-grow-5 flex-shrink-1" [template]="viewerStateController.templateSelected$ | async" [parcellation]="viewerStateController.parcellationSelected$ | async" diff --git a/src/util/directives/captureClickListener.directive.ts b/src/util/directives/captureClickListener.directive.ts index 2d943c2200e6ca60f2c3c5e14c6fb74e1f012a64..3931bc88187bef63764d5754d688d60a1bdcff4a 100644 --- a/src/util/directives/captureClickListener.directive.ts +++ b/src/util/directives/captureClickListener.directive.ts @@ -1,43 +1,42 @@ -import {Directive, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output} from "@angular/core"; -import {fromEvent, Observable, Observer, Subscription} from "rxjs"; -import {switchMapTo, takeUntil} from "rxjs/operators"; +import { Directive, ElementRef, EventEmitter, OnDestroy, OnInit, Output } from "@angular/core"; +import { Subscription, fromEvent } from "rxjs"; +import { switchMapTo, takeUntil } from "rxjs/operators"; @Directive({ - selector: '[iav-captureClickListenerDirective]' + selector: '[iav-captureClickListenerDirective]' }) export class CaptureClickListenerDirective implements OnInit, OnDestroy { - private subscriptions: Subscription[] = [] - @Output('iav-captureClickListenerDirective-onClick') mapClicked: EventEmitter<any> = new EventEmitter() - @Output('iav-captureClickListenerDirective-onMousedown') mouseDownEmitter: EventEmitter<any> = new EventEmitter() - - - constructor(private el: ElementRef){} - - ngOnInit(): void { - const mouseDownObs$ = fromEvent(this.el.nativeElement, 'mousedown', { capture: true }) - const mouseMoveObs$ = fromEvent(this.el.nativeElement, 'mousemove', { capture: true }) - const mouseUpObs$ = fromEvent(this.el.nativeElement, 'mouseup', { capture: true }) - - this.subscriptions.push( - mouseDownObs$.subscribe(event => { - this.mouseDownEmitter.emit(event) - }), - mouseDownObs$.pipe( - switchMapTo( - mouseUpObs$.pipe( - takeUntil(mouseMoveObs$) - ) - ) - ).subscribe(event => { - this.mapClicked.emit(event) - }) + private subscriptions: Subscription[] = [] + @Output('iav-captureClickListenerDirective-onClick') mapClicked: EventEmitter<any> = new EventEmitter() + @Output('iav-captureClickListenerDirective-onMousedown') mouseDownEmitter: EventEmitter<any> = new EventEmitter() + + constructor(private el: ElementRef) { } + + ngOnInit() { + const mouseDownObs$ = fromEvent(this.el.nativeElement, 'mousedown', { capture: true }) + const mouseMoveObs$ = fromEvent(this.el.nativeElement, 'mousemove', { capture: true }) + const mouseUpObs$ = fromEvent(this.el.nativeElement, 'mouseup', { capture: true }) + + this.subscriptions.push( + mouseDownObs$.subscribe(event => { + this.mouseDownEmitter.emit(event) + }), + mouseDownObs$.pipe( + switchMapTo( + mouseUpObs$.pipe( + takeUntil(mouseMoveObs$) + ) ) - } - - ngOnDestroy(): void { - this.subscriptions.forEach(s=> s.unsubscribe()) - } + ).subscribe(event => { + this.mapClicked.emit(event) + }) + ) + } + + ngOnDestroy() { + this.subscriptions.forEach(s => s.unsubscribe()) + } } \ No newline at end of file