diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..8acbc9780e8547d6bec7148ddbfcd05a02797ca8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +src/atlasComponents/sapi/schema.ts linguist-generated=true diff --git a/src/assets/images/atlas-selection/firbe-long.png b/src/assets/images/atlas-selection/fibre-long.png similarity index 100% rename from src/assets/images/atlas-selection/firbe-long.png rename to src/assets/images/atlas-selection/fibre-long.png diff --git a/src/assets/images/atlas-selection/firbe-short.png b/src/assets/images/atlas-selection/fibre-short.png similarity index 100% rename from src/assets/images/atlas-selection/firbe-short.png rename to src/assets/images/atlas-selection/fibre-short.png diff --git a/src/atlasComponents/parcellation/index.ts b/src/atlasComponents/parcellation/index.ts index f49438e683dafb818113eb571433a364854eb24b..4af8252e223c89fce580454087e7038563e1fab4 100644 --- a/src/atlasComponents/parcellation/index.ts +++ b/src/atlasComponents/parcellation/index.ts @@ -1,4 +1,3 @@ -export { GetParcPreviewUrlPipe } from "./getParcPreviewUrl.pipe"; export { FilterNameBySearch } from "./regionHierachy/filterNameBySearch.pipe"; export { AtlasCmpParcellationModule } from "./module"; export { RegionHierarchy } from "./regionHierachy/regionHierarchy.component"; diff --git a/src/atlasComponents/parcellation/module.ts b/src/atlasComponents/parcellation/module.ts index c3e101c3a1d4bf3b2a6384723d79414e59a76429..7763c155a14babdc53f3d81c2c8466410066d5e0 100644 --- a/src/atlasComponents/parcellation/module.ts +++ b/src/atlasComponents/parcellation/module.ts @@ -8,7 +8,6 @@ import { FilterNameBySearch } from "./regionHierachy/filterNameBySearch.pipe"; import { UtilModule } from "src/util"; import { FormsModule, ReactiveFormsModule } from "@angular/forms"; import { ComponentsModule } from "src/components"; -import { GetParcPreviewUrlPipe } from "./getParcPreviewUrl.pipe"; @NgModule({ imports: [ @@ -25,13 +24,11 @@ import { GetParcPreviewUrlPipe } from "./getParcPreviewUrl.pipe"; RegionTextSearchAutocomplete, FilterNameBySearch, - GetParcPreviewUrlPipe, ], exports: [ RegionHierarchy, RegionTextSearchAutocomplete, FilterNameBySearch, - GetParcPreviewUrlPipe, ] }) export class AtlasCmpParcellationModule{} \ No newline at end of file diff --git a/src/atlasComponents/parcellation/regionSearch/regionSearch.template.html b/src/atlasComponents/parcellation/regionSearch/regionSearch.template.html index fb8ff3060e6c737ed7df4aa9f33ca21d54a36faf..a5db58d620bc343cfbda66bd3118313bde451db3 100644 --- a/src/atlasComponents/parcellation/regionSearch/regionSearch.template.html +++ b/src/atlasComponents/parcellation/regionSearch/regionSearch.template.html @@ -37,8 +37,8 @@ [value]="region.labelIndexId"> <simple-region - [region-base-region]="region" - [isSelected]="regionsSelected$ | async | includes : region : compareFn"> + [region-base-region]="region"> + <!-- [isSelected]="regionsSelected$ | async | includes : region : compareFn"> --> </simple-region> </mat-option> diff --git a/src/atlasComponents/parcellationRegion/index.ts b/src/atlasComponents/parcellationRegion/index.ts index cced6b8edf56fd9c723124704267e3f5fd11e722..d5869daaa5aa889247c5a07ed8217605bb8a4fa6 100644 --- a/src/atlasComponents/parcellationRegion/index.ts +++ b/src/atlasComponents/parcellationRegion/index.ts @@ -3,6 +3,5 @@ export { } from "./module" export { RegionDirective } from "./region.directive"; -export { RegionMenuComponent } from "./regionMenu/regionMenu.component"; export { SimpleRegionComponent } from "./regionSimple/regionSimple.component"; export { RenderViewOriginDatasetLabelPipe } from "./region.base"; \ No newline at end of file diff --git a/src/atlasComponents/parcellationRegion/module.ts b/src/atlasComponents/parcellationRegion/module.ts index 8c995808ea52f2b2fa72d9e1272b221387d04200..20f1f4fb3d006cf3a4ae06572111fc8641dce748 100644 --- a/src/atlasComponents/parcellationRegion/module.ts +++ b/src/atlasComponents/parcellationRegion/module.ts @@ -5,14 +5,12 @@ import { AngularMaterialModule } from "src/sharedModules"; import { UtilModule } from "src/util"; import { RenderViewOriginDatasetLabelPipe } from "./region.base"; import { RegionDirective } from "./region.directive"; -import { RegionMenuComponent } from "./regionMenu/regionMenu.component"; import { SimpleRegionComponent } from "./regionSimple/regionSimple.component"; import { RegionAccordionTooltipTextPipe } from "./regionAccordionTooltipText.pipe"; import { AtlasCmptConnModule } from "../connectivity"; import { HttpClientModule } from "@angular/common/http"; import { RegionInOtherTmplPipe } from "./regionInOtherTmpl.pipe"; import { SiibraExplorerTemplateModule } from "../template"; -import { RegionalFeaturesModule } from "./regionalFeatures/module"; @NgModule({ imports: [ @@ -24,10 +22,8 @@ import { RegionalFeaturesModule } from "./regionalFeatures/module"; HttpClientModule, SiibraExplorerTemplateModule, - RegionalFeaturesModule, ], declarations: [ - RegionMenuComponent, SimpleRegionComponent, RegionDirective, @@ -36,7 +32,6 @@ import { RegionalFeaturesModule } from "./regionalFeatures/module"; RegionInOtherTmplPipe, ], exports: [ - RegionMenuComponent, SimpleRegionComponent, RegionDirective, diff --git a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.spec.ts b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.spec.ts deleted file mode 100644 index 2c9d299636b1aab010b6af672210079c28611d87..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.spec.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { TestBed, async } from "@angular/core/testing" -import { RegionMenuComponent } from "./regionMenu.component" -import { AngularMaterialModule } from "src/sharedModules" -import { UtilModule } from "src/util/util.module" -import { CommonModule } from "@angular/common" -import { provideMockStore } from "@ngrx/store/testing" -import { Component, Directive, Input } from "@angular/core" -import { NoopAnimationsModule } from "@angular/platform-browser/animations" -import { ComponentsModule } from "src/components" -import { ParcellationRegionModule } from "../module" -import { BS_ENDPOINT } from "src/util/constants" - -const mt0 = { - name: 'mt0' -} - -const mt1 = { - name: 'mt1' -} - -const mr0 = { - name: 'mr0' -} - -const mr1 = { - name: 'mr1' -} - -const mp0 = { - name: 'mp0' -} - -const mp1 = { - name: 'mp1' -} - -const mrm0 = { - template: mt0, - parcellation: mp0, - region: mr0 -} - -const mrm1 = { - template: mt1, - parcellation: mp1, - region: mr1 -} - -const hemisphereMrms = [ { - ...mrm0, - hemisphere: 'left hemisphere' -}, { - ...mrm1, - hemisphere: 'left hemisphere' -} ] - -const nohemisphereHrms = [mrm0, mrm1] - -@Component({ - selector: 'kg-regional-features-list', - template: '' -}) - -class DummyKgRegionalFeatureList{} - -@Directive({ - selector: '[kg-regional-features-list-directive]', - exportAs: 'kgRegionalFeaturesListDirective' -}) - -class DummySingleDatasetDirective{ - @Input() - region: string - -} - -describe('> regionMenu.component.ts', () => { - describe('> RegionMenuComponent', () => { - beforeEach(async(() => { - - TestBed.configureTestingModule({ - imports: [ - UtilModule, - AngularMaterialModule, - CommonModule, - NoopAnimationsModule, - ComponentsModule, - ParcellationRegionModule, - ], - declarations: [ - /** - * Used by regionMenu.template.html to show region preview - */ - DummySingleDatasetDirective, - DummyKgRegionalFeatureList, - ], - providers: [ - provideMockStore({ initialState: {} }), - { - provide: BS_ENDPOINT, - useValue: 'http://example.dev/1_0' - } - ] - }).compileComponents() - - })) - - it('> init just fine', () => { - const fixture = TestBed.createComponent(RegionMenuComponent) - expect(fixture).toBeTruthy() - }) - }) -}) \ No newline at end of file diff --git a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts deleted file mode 100644 index b587c100ff00445ac0489c5bb0a8ee1561a28bf5..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.component.ts +++ /dev/null @@ -1,95 +0,0 @@ -import { Component, EventEmitter, OnDestroy, Output } from "@angular/core"; -import { Store } from "@ngrx/store"; -import { merge, Observable, Subject, Subscription } from "rxjs"; -import { RegionBase } from '../region.base' -import { CONST, ARIA_LABELS } from 'common/constants' -import { ComponentStore } from "src/viewerModule/componentStore"; -import { distinctUntilChanged, mapTo } from "rxjs/operators"; -import { SapiRegionalFeatureModel } from "src/atlasComponents/sapi"; - -@Component({ - selector: 'region-menu', - templateUrl: './regionMenu.template.html', - styleUrls: ['./regionMenu.style.css'], - providers: [ ComponentStore ] -}) -export class RegionMenuComponent extends RegionBase implements OnDestroy { - - @Output('region-menu-feat-clicked') - featureClicked = new EventEmitter<SapiRegionalFeatureModel>() - - public CONST = CONST - public ARIA_LABELS = ARIA_LABELS - private subscriptions: Subscription[] = [] - - public activePanelTitles$: Observable<string[]> - private activePanelTitles: string[] = [] - - public intentToChgTmpl$ = new Subject() - public lockOtherTmpl$ = merge( - this.selectedTemplate$.pipe( - mapTo(false) - ), - this.intentToChgTmpl$.pipe( - mapTo(true) - ) - ).pipe( - distinctUntilChanged() - ) - - constructor( - store$: Store<any>, - private viewerCmpLocalUiStore: ComponentStore<{ activePanelsTitle: string[] }>, - ) { - super(store$) - this.viewerCmpLocalUiStore.setState({ - activePanelsTitle: [] - }) - - this.activePanelTitles$ = this.viewerCmpLocalUiStore.select( - state => state.activePanelsTitle - ) as Observable<string[]> - - this.subscriptions.push( - this.activePanelTitles$.subscribe( - (activePanelTitles: string[]) => this.activePanelTitles = activePanelTitles - ) - ) - } - - ngOnDestroy(): void { - this.subscriptions.forEach(s => s.unsubscribe()) - } - - handleExpansionPanelClosedEv(title: string){ - this.viewerCmpLocalUiStore.setState({ - activePanelsTitle: this.activePanelTitles.filter(n => n !== title) - }) - } - handleExpansionPanelAfterExpandEv(title: string){ - if (this.activePanelTitles.includes(title)) return - this.viewerCmpLocalUiStore.setState({ - activePanelsTitle: [ - ...this.activePanelTitles, - title - ] - }) - } - - public busyFlag = false - private busyMap = new Map<string, boolean>() - handleBusySignal(namespace: string, flag: boolean) { - this.busyMap.set(namespace, flag) - for (const [_key, val] of this.busyMap.entries()) { - if (val) { - this.busyFlag = true - return - } - } - this.busyFlag = false - } - - handleRegionalFeatureClicked(feat: SapiRegionalFeatureModel){ - this.featureClicked.emit(feat) - } -} diff --git a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.style.css b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.style.css deleted file mode 100644 index 386e688cd8e1adc6489f109fbadf71148c4d5ccc..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.style.css +++ /dev/null @@ -1,54 +0,0 @@ -mat-icon -{ - transform: scale(0.75); -} - -.action-list -{ - margin-left: -16px; - margin-right: -16px; -} - -.action-list mat-icon -{ - padding-left: 0px; -} - -.region-name -{ - display: inherit; - font-size: 95%; - line-height: normal; -} - -:host-context([darktheme="true"]) .loading-overlay -{ - background-color: rgba(10, 10, 10, 0.8); -} - -.loading-overlay -{ - background-color: rgba(250, 250, 250, 0.8); -} - -.loading-overlay -{ - position: absolute; - width: 100%; - height: 100%; - top: 0; - left: 0; - font-size: 200%; - - display: grid; - grid-template-columns: auto; - grid-template-rows: 1fr auto 1fr; - grid-template-columns: 1fr auto 1fr; - grid-template-areas: "." "vertical-center" "."; -} - -.loading-overlay > .spinner -{ - grid-column: 2; - grid-row: 2; -} diff --git a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html b/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html deleted file mode 100644 index 8e542df8c9dac0d874da0c8ec6d6bffff8b733fa..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionMenu/regionMenu.template.html +++ /dev/null @@ -1,191 +0,0 @@ -<ng-template [ngIf]="region"> - -<mat-card class="mat-elevation-z4"> - <!-- rgbDarkmode must be checked for strict equality to true/false - as if rgb is undefined, rgbDarkmode will be null/undefined - which is falsy --> - <div class="sidenav-cover-header-container" - [ngClass]="{'darktheme': rgbDarkmode === true, 'lighttheme': rgbDarkmode === false}" - [style.backgroundColor]="rgbString"> - <mat-card-title> - <div class="position-relative region-name iv-custom-comp text"> - {{ region.name }} - </div> - </mat-card-title> - - <!-- subtitle on what it is --> - <mat-card-subtitle class="d-inline-flex align-items-center flex-wrap"> - <mat-icon fontSet="fas" fontIcon="fa-brain"></mat-icon> - <span> - Brain region - </span> - - <!-- origin datas format --> - - <mat-divider vertical="true" class="ml-2 h-2rem"></mat-divider> - - <!-- position --> - <button mat-icon-button *ngIf="position" - (click)="navigateToRegion()" - [matTooltip]="ARIA_LABELS.GO_TO_REGION_CENTROID + ': ' + (position | nmToMm | numbers | addUnitAndJoin : 'mm')"> - <mat-icon fontSet="fas" fontIcon="fa-map-marked-alt"> - </mat-icon> - </button> - - <!-- explore doi --> - <a *ngFor="let doi of dois" - [href]="doi | doiParserPipe" - [matTooltip]="ARIA_LABELS.EXPLORE_DATASET_IN_KG" - target="_blank" - mat-icon-button> - <i class="fas fa-external-link-alt"></i> - </a> - - </mat-card-subtitle> - - </div> -</mat-card> - -<mat-accordion class="d-block mt-2"> - - <!-- description --> - <!-- TODO how are we going to get desc for PEV? --> - <!-- <ng-template [ngIf]="(originDatainfos || []).length > 0"> - <ng-container *ngFor="let originData of originDatainfos"> - <ng-template #descTmpl> - <markdown-dom [markdown]="originData.description" - class="text-muted text-sm"> - </markdown-dom> - </ng-template> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: 'Description', - iconClass: 'fas fa-info', - iavNgIf: true, - content: descTmpl - }"> - - </ng-container> - </ng-container> - </ng-template> --> - - - <!-- Explore in other template --> - TODO reimplmenent explore in other templates - perhaps extract the tile into a separate ui component (?) - - - <!-- kg regional features list --> - <ng-template #kgRegionalFeatureList> - <regional-features-list - class="fs-80 max-50-vh d-block of-y-scroll of-x-hidden" - [regional-features-list-region]="region$ | async" - [regional-features-list-atlas]="atlas" - [regional-features-list-template]="template" - [regional-features-list-parcellation]="parcellation" - (regional-features-list-feat-clicked)="handleRegionalFeatureClicked($event)" - > - </regional-features-list> - </ng-template> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: CONST.REGIONAL_FEATURES, - iconClass: 'fas fa-database', - content: kgRegionalFeatureList, - desc: '', - iconTooltip: 'Regional Features', - iavNgIf: true - }"> - </ng-container> - - <!-- Connectivity --> - - <ng-template #connectivityContentTmpl let-expansionPanel="expansionPanel"> - <mat-card-content class="flex-grow-1 flex-shrink-1 w-100"> - <connectivity-browser class="pe-all flex-shrink-1" - [region]="region" - (setOpenState)="expansionPanel.expanded = $event" - [accordionExpanded]="expansionPanel.expanded" - (connectivityNumberReceived)="hasConnectivityDirective.connectivityNumber = $event"> - </connectivity-browser> - </mat-card-content> - </ng-template> - - <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { - title: 'Connectivity', - desc: hasConnectivityDirective.connectivityNumber, - iconClass: 'fas fa-braille', - iconTooltip: hasConnectivityDirective.connectivityNumber | regionAccordionTooltipTextPipe : 'connectivity', - iavNgIf: hasConnectivityDirective.hasConnectivity, - content: connectivityContentTmpl - }"> - </ng-container> - - <div has-connectivity - [region]="[region]" - #hasConnectivityDirective="hasConnectivityDirective"> - </div> -</mat-accordion> - -<div *ngIf="busyFlag" class="mt-2 d-flex justify-content-center"> - <spinner-cmp></spinner-cmp> -</div> - -<!-- expansion tmpl --> -<ng-template #ngMatAccordionTmpl - let-title="title" - let-desc="desc" - let-iconClass="iconClass" - let-iconTooltip="iconTooltip" - let-iavNgIf="iavNgIf" - let-content="content"> - <mat-expansion-panel - [expanded]="activePanelTitles$ | async | includes : title" - [attr.data-opened]="expansionPanel.expanded" - [attr.data-mat-expansion-title]="title" - (closed)="handleExpansionPanelClosedEv(title)" - (afterExpand)="handleExpansionPanelAfterExpandEv(title)" - hideToggle - *ngIf="iavNgIf" - #expansionPanel="matExpansionPanel"> - - <mat-expansion-panel-header> - - <!-- title --> - <mat-panel-title> - {{ title }} - </mat-panel-title> - - <!-- desc + icon --> - <mat-panel-description class="d-flex align-items-center justify-content-end" - [matTooltip]="iconTooltip"> - <span class="mr-3">{{ desc }}</span> - <span class="accordion-icon d-inline-flex justify-content-center"> - <i [class]="iconClass"></i> - </span> - </mat-panel-description> - - </mat-expansion-panel-header> - - <!-- content --> - <ng-template matExpansionPanelContent> - <ng-container *ngTemplateOutlet="content; context: { - expansionPanel: expansionPanel - }"> - </ng-container> - </ng-template> - </mat-expansion-panel> -</ng-template> -</ng-template> - - -<ng-template [ngIf]="!region"> - <mat-card class="mat-elevation-z4"> - <h1 class="mat-h1 sidenav-cover-header-container"> - <spinner-cmp class="d-inline-block"></spinner-cmp> - <span class="text-muted"> - Loading region - </span> - </h1> - </mat-card> -</ng-template> \ No newline at end of file diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/constants.ts b/src/atlasComponents/parcellationRegion/regionalFeatures/constants.ts deleted file mode 100644 index 6350c2d32979fc1b6b32be05e2ebe84a3b25175a..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/constants.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { InjectionToken } from "@angular/core"; -import { Observable } from "rxjs"; -import { SapiAtlasModel, SapiParcellationModel, SapiRegionModel, SapiSpaceModel } from "src/atlasComponents/sapi"; diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/index.ts b/src/atlasComponents/parcellationRegion/regionalFeatures/index.ts deleted file mode 100644 index 19f18aba07313c4cd59daadb03e0944253c09e7e..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { - RegionalFeaturesModule -} from "./module" diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/module.ts b/src/atlasComponents/parcellationRegion/regionalFeatures/module.ts deleted file mode 100644 index 01e894e5b3c641b1141b0795362649cee42009f1..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { AngularMaterialModule } from "src/sharedModules"; -import { RegionalFeatureBadgeColourPipe } from "./regionalFeatureBadgeColor.pipe"; -import { RegionalFeatureBadgeColourName } from "./regionalFeatureBadgeName.pipe"; -import { RegionalFeaturesList } from "./regionalFeaturesList/regionalFeaturesList.component"; - -@NgModule({ - imports: [ - CommonModule, - AngularMaterialModule, - ], - declarations: [ - RegionalFeaturesList, - RegionalFeatureBadgeColourPipe, - RegionalFeatureBadgeColourName, - ], - exports: [ - RegionalFeaturesList - ] -}) -export class RegionalFeaturesModule{} diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeatureBadgeColor.pipe.ts b/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeatureBadgeColor.pipe.ts deleted file mode 100644 index be36dfd938018e47d4f1747cf1bffa026b8ba637..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeatureBadgeColor.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; -import { SapiRegionalFeatureModel } from "src/atlasComponents/sapi"; - -@Pipe({ - name: 'regionalFeatureBadgeColour', - pure: true -}) - -export class RegionalFeatureBadgeColourPipe implements PipeTransform{ - public transform(regionalFeature: SapiRegionalFeatureModel) { - if (regionalFeature.type === "siibra/receptor") { - return "accent" - } - return "default" - } -} diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeatureBadgeName.pipe.ts b/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeatureBadgeName.pipe.ts deleted file mode 100644 index 0a0d956b8de09cdd68318381473dcde45c165d26..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeatureBadgeName.pipe.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; -import { SapiRegionalFeatureModel } from "src/atlasComponents/sapi"; - -@Pipe({ - name: 'regionalFeatureBadgeName', - pure: true -}) - -export class RegionalFeatureBadgeColourName implements PipeTransform{ - public transform(regionalFeature: SapiRegionalFeatureModel) { - if (regionalFeature.type === "siibra/receptor") { - return "receptor density" - } - return null - } -} diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList.stories.ts b/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList.stories.ts deleted file mode 100644 index dc1762efbe8262da979adb4a6f73716fcb39430e..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList.stories.ts +++ /dev/null @@ -1,116 +0,0 @@ -import { Meta, moduleMetadata, Story } from '@storybook/angular'; -import { SAPI, SapiAtlasModel, SapiParcellationModel, SapiRegionModel, SapiSpaceModel } from "src/atlasComponents/sapi" -import { RegionalFeaturesModule } from '.'; -import { CommonModule } from '@angular/common'; -import { Component, Input, Output, EventEmitter, HostBinding } from '@angular/core'; -import { HttpClientModule } from '@angular/common/http'; -import { AngularMaterialModule } from 'src/sharedModules'; -import { getHumanAtlas, getMni152, getJba29, getHoc1Left } from 'src/atlasComponents/sapi/stories.base'; - -@Component({ - // selector is **mandatory**!! - selector: 'wrapper-cls', - template: ` - <mat-card> - <regional-features-list - [regional-features-list-atlas]="atlas" - [regional-features-list-template]="space" - [regional-features-list-parcellation]="parc" - [regional-features-list-region]="region" - (regional-features-list-feat-clicked)="clickTriggered.emit($event)" - > - </regional-features-list> - </mat-card> - `, - styles: [ - ` - :host - { - display: block; - } - ` - ], -}) - -class WrapperCls{ - atlas: SapiAtlasModel - space: SapiSpaceModel - parc: SapiParcellationModel - region: SapiRegionModel - - constructor(){ - } - - @Output() - clickTriggered = new EventEmitter() - - @HostBinding('style.max-width') - @Input() - maxWidth: string = null -} - -//👇 This default export determines where your story goes in the story list -export default { - /* 👇 The title prop is optional. - * See https://storybook.js.org/docs/angular/configure/overview#configure-story-loading - * to learn how to generate automatic titles - */ - - component: WrapperCls, - decorators: [ - moduleMetadata({ - imports: [ - CommonModule, - RegionalFeaturesModule, - HttpClientModule, - AngularMaterialModule, - ], - providers: [ - SAPI, - ] - }) - ] -} as Meta; - -//👇 We create a “template†of how args map to rendering -const Template: Story<WrapperCls> = (args: WrapperCls, { loaded }) => { - const { atlas, parc, space, region } = loaded - return ({ - props: { - ...args, - atlas, parc, space, region - } - }) -} - -Template.loaders = [ - async () => { - const atlas = await getHumanAtlas() - const parc = await getJba29() - const region = await getHoc1Left() - const space = await getMni152() - return { - atlas, parc, space, region - } - } -] - - -export const NormalView = Template.bind({}); -NormalView.loaders = [ - ...Template.loaders -] -// NormalView.args = { -// //👇 The args you need here will depend on your component -// }; - -// half width view not working -// related probably: https://github.com/storybookjs/storybook/issues/13264 -export const HalfWidth = Template.bind({}); -HalfWidth.loaders = [ - ...Template.loaders -] -HalfWidth.args = { - //👇 The args you need here will depend on your component - maxWidth: "20rem" -}; diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.template.html b/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.template.html deleted file mode 100644 index 3e508d17817dfbb641e58225df857abc2edf063d..0000000000000000000000000000000000000000 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.template.html +++ /dev/null @@ -1,20 +0,0 @@ -<ng-template ngFor let-first="first" let-feature [ngForOf]="listOfFeatures$ | async"> - - <mat-divider *ngIf="!first"> - </mat-divider> - - <div mat-ripple class="sxplr-pt-4 cursor-default" (click)="showFeature(feature)"> - <mat-chip-list [ngSwitch]="feature.type" class="scale-80 transform-origin-left-center"> - <mat-chip *ngSwitchCase="'siibra/receptor'" - [color]="feature | regionalFeatureBadgeColour" - selected> - {{ feature | regionalFeatureBadgeName }} - </mat-chip> - </mat-chip-list> - - <div> - {{ feature.metadata.fullName }} - </div> - - </div> -</ng-template> diff --git a/src/atlasComponents/sapi/index.ts b/src/atlasComponents/sapi/index.ts index 07d0d433db71ed44d77b91ca90ba29a22d33613f..b1bbb7c2313d3c88f505f59b4a4947bbb620c99d 100644 --- a/src/atlasComponents/sapi/index.ts +++ b/src/atlasComponents/sapi/index.ts @@ -11,6 +11,7 @@ export { SapiRegionalFeatureModel, SapiSpatialFeatureModel, SapiFeatureModel, + SapiParcellationFeatureModel, } from "./type" export { SAPI } from "./sapi.service" diff --git a/src/atlasComponents/sapi/sapi.service.ts b/src/atlasComponents/sapi/sapi.service.ts index 07fb77d1567562de156b73b4081ada8d86897b5e..2db21f415d1d171732adb4f631adcee4934ca4e9 100644 --- a/src/atlasComponents/sapi/sapi.service.ts +++ b/src/atlasComponents/sapi/sapi.service.ts @@ -18,7 +18,7 @@ type RegistryType = SAPIAtlas | SAPISpace | SAPIParcellation @Injectable() export class SAPI{ - static bsEndpoint = `https://siibra-api-dev.apps-dev.hbp.eu/v1_0` + static bsEndpoint = `http://localhost:5000/v1_0` // `https://siibra-api-dev.apps-dev.hbp.eu/v1_0` public bsEndpoint = SAPI.bsEndpoint diff --git a/src/atlasComponents/sapi/schema.ts b/src/atlasComponents/sapi/schema.ts index 9fb39e5fff86f2e4451f957c11d2affcbdb64d9a..1b807d7d385c884f61551e6d8f2a50c7f8519ea3 100644 --- a/src/atlasComponents/sapi/schema.ts +++ b/src/atlasComponents/sapi/schema.ts @@ -195,6 +195,11 @@ export interface components { ConnectivityMatrixDataModel: { /** @Id */ "@id": string; + /** + * Type + * @constant + */ + type?: "siibra/connectivity"; /** Name */ name: string; /** Parcellations */ @@ -545,6 +550,8 @@ export interface components { "@type"?: "minds/core/parcellationatlas/v1.0.0"; /** Name */ name: string; + /** Modality */ + modality?: string; /** Datasets */ datasets: components["schemas"]["DatasetJsonModel"][]; /** Brainatlasversions */ @@ -1292,6 +1299,7 @@ export interface operations { }; query: { space_id?: string; + find?: string; }; }; responses: { diff --git a/src/atlasComponents/sapi/stories.base.ts b/src/atlasComponents/sapi/stories.base.ts index 1ef57fbe75af6f199dfb15c40b32f5e76e51547a..e3cd6f322117fed8ff26ec9c88227fee77b28ae7 100644 --- a/src/atlasComponents/sapi/stories.base.ts +++ b/src/atlasComponents/sapi/stories.base.ts @@ -37,19 +37,23 @@ export const provideDarkTheme = [{ deps: [ DOCUMENT ] }] -const atlasId = { - human: 'juelich/iav/atlas/v1.0.0/1' +export const atlasId = { + human: 'juelich/iav/atlas/v1.0.0/1', + rat: "minds/core/parcellationatlas/v1.0.0/522b368e-49a3-49fa-88d3-0870a307974a", + mouse: "juelich/iav/atlas/v1.0.0/2", + monkey: "juelich/iav/atlas/v1.0.0/monkey" } -const spaceId = { +export const spaceId = { human: { mni152: 'minds/core/referencespace/v1.0.0/dafcffc5-4826-4bf1-8ff6-46b8a31ff8e2' } } -const parcId = { +export const parcId = { human: { - jba29: "minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-290" + jba29: "minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579-290", + longBundle: "juelich/iav/atlas/v1.0.0/5" } } @@ -81,8 +85,11 @@ export async function getJba29(): Promise<SapiParcellationModel> { return await getParc(atlasId.human, parcId.human.jba29) } -export async function getHoc1Left(): Promise<SapiRegionModel> { - return await (await fetch(`${SAPI.bsEndpoint}/atlases/${atlasId.human}/parcellations/${parcId.human.jba29}/regions/hoc1%20left`)).json() +export async function getHoc1Left(spaceId=null): Promise<SapiRegionModel> { + if (!spaceId) { + return await (await fetch(`${SAPI.bsEndpoint}/atlases/${atlasId.human}/parcellations/${parcId.human.jba29}/regions/hoc1%20left`)).json() + } + return await (await fetch(`${SAPI.bsEndpoint}/atlases/${atlasId.human}/parcellations/${parcId.human.jba29}/regions/hoc1%20left?space_id=${encodeURIComponent(spaceId)}`)).json() } export async function getHoc1Features(): Promise<SapiRegionalFeatureModel[]> { diff --git a/src/atlasComponents/sapi/type.ts b/src/atlasComponents/sapi/type.ts index 231d82deab2bd18587e443464a1d5ced7ee11e8d..42a8047ae94cc443b006989ec202b80b2e97f01c 100644 --- a/src/atlasComponents/sapi/type.ts +++ b/src/atlasComponents/sapi/type.ts @@ -1,6 +1,5 @@ import { OperatorFunction } from "rxjs" import { map } from "rxjs/operators" -import { IVolumeTypeDetail } from "src/util/siibraApiConstants/types" import { components } from "./schema" export type IdName = { @@ -9,15 +8,6 @@ export type IdName = { } type Point = [number, number, number] -type Volume = { - id: string - name: string - url: string - volume_type: "neuroglancer/precomputed" - detail: { - "neuroglancer/precomputed": IVolumeTypeDetail["neuroglancer/precomputed"] - } -} export type BoundingBoxConcept = [Point, Point] @@ -53,7 +43,7 @@ export type SapiRegionalFeatureModel = components["schemas"]["BaseDatasetJsonMod export type SapiParcellationFeatureMatrixModel = components["schemas"]["ConnectivityMatrixDataModel"] export type SapiParcellationFeatureModel = SapiParcellationFeatureMatrixModel | SapiSerializationErrorModel -export type SapiFeatureModel = (SapiRegionalFeatureModel | SapiSpatialFeatureModel | SapiParcellationFeatureModel) & { type: string } +export type SapiFeatureModel = SapiRegionalFeatureModel | SapiSpatialFeatureModel | SapiParcellationFeatureModel export function guardPipe< InputType, diff --git a/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.component.ts b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec13b306430d23ee1574bf4935345b80870aa9dc --- /dev/null +++ b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.component.ts @@ -0,0 +1,40 @@ +import { Component } from "@angular/core"; +import { Store, select } from "@ngrx/store"; +import { Observable } from "rxjs"; +import { ARIA_LABELS } from 'common/constants' +import { atlasSelection } from "src/state" +import { SAPI, SapiAtlasModel } from "src/atlasComponents/sapi"; + +@Component({ + selector: 'sxplr-sapiviews-core-atlas-dropdown-selector', + templateUrl: './dropdownAtlasSelector.template.html', + styleUrls: [ + './dropdownAtlasSelector.style.css' + ] +}) + +export class SapiViewsCoreAtlasAtlasDropdownSelector{ + + public fetchedAtlases$: Observable<SapiAtlasModel[]> = this.sapi.atlases$ + public selectedAtlas$: Observable<SapiAtlasModel> = this.store$.pipe( + select(atlasSelection.selectors.selectedAtlas) + ) + + public SELECT_ATLAS_ARIA_LABEL = ARIA_LABELS.SELECT_ATLAS + + constructor( + private store$: Store<any>, + private sapi: SAPI, + ){ + this.selectedAtlas$.subscribe(val => console.log('sel atlas changed', val)) + } + + handleChangeAtlas({ value }) { + this.store$.dispatch( + atlasSelection.actions.selectATPById({ + atlasId: value + }) + ) + } +} + diff --git a/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.stories.ts b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..027fa024eb8bf497fa6600558b59098bab837d54 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.stories.ts @@ -0,0 +1,49 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI } from "src/atlasComponents/sapi" +import { provideDarkTheme } from "src/atlasComponents/sapi/stories.base" +import { SapiViewsCoreAtlasAtlasDropdownSelector } from "./dropdownAtlasSelector.component" +import { SapiViewsCoreAtlasModule } from "../module" +import { atlasSelection } from "src/state" +import { StoreModule } from "@ngrx/store" + +export default { + component: SapiViewsCoreAtlasAtlasDropdownSelector, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreAtlasModule, + + StoreModule.forRoot({ + [atlasSelection.nameSpace]: atlasSelection.reducer + }), + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [] + }) + ], +} as Meta + +const Template: Story<SapiViewsCoreAtlasAtlasDropdownSelector> = (args: SapiViewsCoreAtlasAtlasDropdownSelector, { parameters }) => { + /** + * TODO can't seem to hook in handlechangeAtlas action + * always results in maximum call stack reached + * perhaps related: https://github.com/storybookjs/storybook/issues/13238 + */ + return ({ + props: { + }, + }) +} + + +export const Default = Template.bind({}) +Default.args = { + +} \ No newline at end of file diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.style.css b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.style.css similarity index 100% rename from src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.style.css rename to src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.style.css diff --git a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.template.html b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.template.html similarity index 87% rename from src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.template.html rename to src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.template.html index 4b5ddc4b0309e62ff937c8e6e5ffefeadfc55a6a..f3922fea6c44412fc83137f6c3ed71db7efd26e7 100644 --- a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.template.html +++ b/src/atlasComponents/sapiViews/core/atlas/dropdownAtlasSelector/dropdownAtlasSelector.template.html @@ -4,7 +4,7 @@ </mat-label> <mat-select [aria-label]="SELECT_ATLAS_ARIA_LABEL" - [value]="selectedAtlas$ | async | getProperty" + [value]="(selectedAtlas$ | async)?.['@id']" (selectionChange)="handleChangeAtlas($event)"> <mat-option *ngFor="let atlas of (fetchedAtlases$ | async)" diff --git a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.style.css b/src/atlasComponents/sapiViews/core/atlas/index.ts similarity index 100% rename from src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.style.css rename to src/atlasComponents/sapiViews/core/atlas/index.ts diff --git a/src/atlasComponents/sapiViews/core/atlas/module.ts b/src/atlasComponents/sapiViews/core/atlas/module.ts new file mode 100644 index 0000000000000000000000000000000000000000..770a8e9e1e91354fe5edb9d4b1376e2ee25e2c86 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/atlas/module.ts @@ -0,0 +1,30 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { SpinnerModule } from "src/components/spinner"; +import { AngularMaterialModule } from "src/sharedModules"; +import { QuickTourModule } from "src/ui/quickTour"; +import { SapiViewsCoreParcellationModule } from "../parcellation"; +import { SapiViewsCoreSpaceModule } from "../space"; +import { SapiViewsCoreAtlasAtlasDropdownSelector } from "./dropdownAtlasSelector/dropdownAtlasSelector.component"; +import { SapiViewsCoreAtlasAtlasTmplParcSelector } from "./tmplParcSelector/tmplParcSelector.component"; + +@NgModule({ + imports: [ + CommonModule, + AngularMaterialModule, + SapiViewsCoreSpaceModule, + SapiViewsCoreParcellationModule, + QuickTourModule, + SpinnerModule, + ], + declarations: [ + SapiViewsCoreAtlasAtlasDropdownSelector, + SapiViewsCoreAtlasAtlasTmplParcSelector, + ], + exports: [ + SapiViewsCoreAtlasAtlasDropdownSelector, + SapiViewsCoreAtlasAtlasTmplParcSelector, + ] +}) + +export class SapiViewsCoreAtlasModule{} \ No newline at end of file diff --git a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.component.ts similarity index 64% rename from src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts rename to src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.component.ts index 927d62cb3d5fed7d12a1d3a5361aa0fd280a9883..d3cbe274f4ba2194ebfacfc40837eed3c4eca20e 100644 --- a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.ts +++ b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.component.ts @@ -1,25 +1,23 @@ -import { Component, ViewChildren, QueryList, HostBinding, ViewChild, ElementRef, OnDestroy } from "@angular/core"; -import { select, Store } from "@ngrx/store"; -import { distinctUntilChanged, map, withLatestFrom, shareReplay, mapTo } from "rxjs/operators"; -import { merge, Observable, Subject, Subscription } from "rxjs"; -import { MatMenuTrigger } from "@angular/material/menu"; -import { ARIA_LABELS, CONST, QUICKTOUR_DESC } from 'common/constants' -import { IQuickTourData } from "src/ui/quickTour/constrants"; import { animate, state, style, transition, trigger } from "@angular/animations"; -import { IHasId, OVERWRITE_SHOW_DATASET_DIALOG_TOKEN } from "src/util/interfaces"; -import { CurrentTmplSupportsParcPipe } from "../pipes/currTmplSupportsParc.pipe"; -import { - actions, - fromRootStore -} from "src/state/atlasSelection" +import { Component, ElementRef, HostBinding, Input, QueryList, ViewChild, ViewChildren } from "@angular/core"; +import { select, Store } from "@ngrx/store"; +import { merge, Subject, Subscription } from "rxjs"; +import { distinctUntilChanged, map, mapTo, shareReplay, tap, withLatestFrom } from "rxjs/operators"; import { SAPI } from "src/atlasComponents/sapi"; import { atlasSelection } from "src/state"; +import { fromRootStore } from "src/state/atlasSelection"; +import { IQuickTourData } from "src/ui/quickTour"; +import { ARIA_LABELS, CONST, QUICKTOUR_DESC } from 'common/constants' +import { MatMenuTrigger } from "@angular/material/menu"; +import { SapiParcellationModel, SapiSpaceModel } from "src/atlasComponents/sapi/type"; @Component({ - selector: 'atlas-layer-selector', - templateUrl: './atlasLayerSelector.template.html', - styleUrls: ['./atlasLayerSelector.style.css'], - exportAs: 'atlasLayerSelector', + selector: `sxplr-sapiviews-core-atlas-tmplparcselector`, + templateUrl: './tmplParcSelector.template.html', + styleUrls: [ + `./tmplParcSelector.style.css` + ], + exportAs: 'sxplrSapiViewsCoreAtlasTmplparcselector', animations: [ trigger('toggleAtlasLayerSelector', [ state('false', style({ @@ -40,14 +38,9 @@ import { atlasSelection } from "src/state"; ]) ]) ], - providers:[ - { - provide: OVERWRITE_SHOW_DATASET_DIALOG_TOKEN, - useValue: null - } - ] }) -export class AtlasLayerSelector implements OnDestroy { + +export class SapiViewsCoreAtlasAtlasTmplParcSelector { public ARIA_LABELS = ARIA_LABELS public CONST = CONST @@ -58,13 +51,7 @@ export class AtlasLayerSelector implements OnDestroy { @ViewChild('selectorPanelTmpl', { read: ElementRef }) selectorPanelTemplateRef: ElementRef - public selectedAtlas$: Observable<any> = this.store$.pipe( - select(atlasSelection.selectors.selectedAtlas), - distinctUntilChanged(), - shareReplay(1) - ) - - public atlasLayersLatest$ = this.store$.pipe( + public availableParcellations$ = this.store$.pipe( fromRootStore.allAvailParcs(this.sapi), shareReplay(1), ) @@ -80,6 +67,11 @@ export class AtlasLayerSelector implements OnDestroy { return fullInfoTemplates.find(t => t['@id'] === selectedTmpl['@id']) }) ) + + public selectedParcellation$ = this.store$.pipe( + select(atlasSelection.selectors.selectedParcellation), + ) + private showOverlayIntent$ = new Subject() public showLoadingOverlay$ = merge( this.showOverlayIntent$.pipe( @@ -92,10 +84,6 @@ export class AtlasLayerSelector implements OnDestroy { distinctUntilChanged(), ) - public selectedParcellation$ = this.store$.pipe( - select(atlasSelection.selectors.selectedParcellation), - ) - private subscriptions: Subscription[] = [] @HostBinding('attr.data-opened') @@ -106,11 +94,10 @@ export class AtlasLayerSelector implements OnDestroy { description: QUICKTOUR_DESC.LAYER_SELECTOR, } - constructor( - private store$: Store<any>, - private sapi: SAPI, - ) {} + constructor(private store$: Store, private sapi: SAPI){ + + } ngOnDestroy() { while(this.subscriptions.length) this.subscriptions.pop().unsubscribe() } @@ -120,21 +107,21 @@ export class AtlasLayerSelector implements OnDestroy { this.selectorExpanded = !this.selectorExpanded } - selectTemplatewithId(templateId: string) { + selectTemplate(tmpl: SapiSpaceModel) { this.showOverlayIntent$.next(true) + this.store$.dispatch( - actions.selectATPById({ - templateId + atlasSelection.actions.selectTemplate({ + template: tmpl }) ) } - private currTmplSupportParcPipe = new CurrentTmplSupportsParcPipe() - - selectParcellationWithId(id: string) { + selectParcellation(parc: SapiParcellationModel) { + this.store$.dispatch( - actions.selectATPById({ - parcellationId: id + atlasSelection.actions.selectParcellation({ + parcellation: parc }) ) } @@ -144,11 +131,11 @@ export class AtlasLayerSelector implements OnDestroy { } - trackbyAtId(t: IHasId){ + trackbyAtId(t){ return t['@id'] } trackKeyVal(obj: {key: string, value: any}) { return obj.key } -} +} \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.stories.ts b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..8a4d924ea369098ce72d59f822029a3e71d408fd --- /dev/null +++ b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.stories.ts @@ -0,0 +1,87 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { provideMockStore } from "@ngrx/store/testing" +import { action } from "@storybook/addon-actions" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI, SapiSpaceModel } from "src/atlasComponents/sapi" +import { atlasId, spaceId, getAtlas, getSpace, provideDarkTheme, getHumanAtlas } from "src/atlasComponents/sapi/stories.base" +import { AngularMaterialModule } from "src/sharedModules" +import { atlasSelection } from "src/state" +import { SapiViewsCoreAtlasModule } from "../module" +import { SapiViewsCoreAtlasAtlasTmplParcSelector } from "./tmplParcSelector.component" + +const actionsData = { + selectTemplate: action('selectTemplate'), + selectParcellation: action('selectParcellation') +} + +export default { + component: SapiViewsCoreAtlasAtlasTmplParcSelector, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreAtlasModule, + AngularMaterialModule, + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [ + ] + }) + ], +} as Meta + +const Template: Story<SapiViewsCoreAtlasAtlasTmplParcSelector> = (args: SapiViewsCoreAtlasAtlasTmplParcSelector, { loaded }) => { + const { + atlas + } = loaded + + return ({ + props: { + selectTemplate: actionsData.selectTemplate, + selectParcellation: actionsData.selectParcellation + }, + moduleMetadata: { + providers: [ + provideMockStore({ + initialState: { + [atlasSelection.nameSpace]: { + ...atlasSelection.defaultState, + selectedAtlas: atlas + } + } + }) + ] + } + }) +} +Template.loaders = [ + +] + +const asyncLoader = async () => { + const atlas = await getHumanAtlas() + return { + atlas + } +} + +export const Default = Template.bind({}) +Default.args = { + selected: spaceId.human.mni152 +} +Default.loaders = [ + + async () => { + const { + atlas + } = await asyncLoader() + return { + atlas + } + } +] diff --git a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.style.css b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.style.css similarity index 70% rename from src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.style.css rename to src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.style.css index 425a45a5e252f904956712930e5996740733d60f..0d8c1e19955bbe9ffdf8218f48641f68a4b44be8 100644 --- a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.style.css +++ b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.style.css @@ -1,15 +1,9 @@ .selector-container { - overflow-y:scroll; - max-height: 80vh; - width: 21rem; - bottom: 4rem; - z-index: 5; -} - -:host-context([darktheme="true"]) .loading-overlay -{ - background-color: rgba(10, 10, 10, 0.8); + overflow-y:scroll; + max-height: 80vh; + width: 21rem; + bottom: 4rem; } .loading-overlay diff --git a/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.template.html b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.template.html new file mode 100644 index 0000000000000000000000000000000000000000..f98de1d0bc0efe9b2d9018bfd89d3aff5d8db568 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/atlas/tmplParcSelector/tmplParcSelector.template.html @@ -0,0 +1,80 @@ +<!-- selector panel when expanded --> + +<mat-card class="selector-container m-2 position-absolute" + [ngClass]="{'pe-all': selectorExpanded}" + [@toggleAtlasLayerSelector]="selectorExpanded" + (@toggleAtlasLayerSelector.done)="atlasSelectorTour?.attachTo(selectorExpanded ? selectorPanelTemplateRef : null)" + #selectorPanelTmpl> + <mat-card-content> + + <!-- templates --> + <mat-card-subtitle> + {{ CONST.ATLAS_SELECTOR_LABEL_SPACES }} + </mat-card-subtitle> + + <!-- template grid and tiles --> + <mat-grid-list cols="3" + rowHeight="2:3" + gutterSize="16"> + + <mat-grid-tile *ngFor="let template of availableTemplates$ | async; trackBy: trackbyAtId" + [attr.aria-checked]="(selectedTemplate$ | async)?.['@id'] === template['@id']"> + <sxplr-sapiviews-core-space-tile + [sxplr-sapiviews-core-space-tile-space]="template" + [sxplr-sapiviews-core-space-tile-selected]="(selectedTemplate$ | async)?.['@id'] === template['@id']" + (click)="selectTemplate(template)"> + </sxplr-sapiviews-core-space-tile> + </mat-grid-tile> + </mat-grid-list> + + <mat-divider></mat-divider> + + <!-- parcellations --> + <mat-card-subtitle class="mt-2"> + {{ CONST.ATLAS_SELECTOR_LABEL_PARC_MAPS }} + </mat-card-subtitle> + + <mat-grid-list cols="3" + rowHeight="2:3" + gutterSize="16"> + + <mat-grid-tile *ngFor="let parc of availableParcellations$ | async | filterUnsupportedParc | filterGroupedParcs"> + <sxplr-sapiviews-core-parcellation-tile + [sxplr-sapiviews-core-parcellation-tile-parcellation]="parc" + (sxplr-sapiviews-core-parcellation-tile-onclick-parc)="selectParcellation($event)"> + + </sxplr-sapiviews-core-parcellation-tile> + </mat-grid-tile> + + <mat-grid-tile *ngFor="let group of availableParcellations$ | async | filterUnsupportedParc | filterGroupedParcs : true | filterUnsupportedParc"> + <sxplr-sapiviews-core-parcellation-tile + [sxplr-sapiviews-core-parcellation-tile-parcellation]="group" + (sxplr-sapiviews-core-parcellation-tile-onclick-parc)="selectParcellation($event)"> + + </sxplr-sapiviews-core-parcellation-tile> + </mat-grid-tile> + </mat-grid-list> +</mat-card-content> + +<div [hidden]="!(showLoadingOverlay$ | async)" + class="loading-overlay"> + <spinner-cmp class="spinner"></spinner-cmp> +</div> +</mat-card> + +<!-- place holder when not expanded --> +<div class="position-relative m-2 cursor-pointer scale-up-bl pe-all sxplr-d-inline-block" + quick-tour + [quick-tour-description]="quickTourData.description" + [quick-tour-order]="quickTourData.order" + #atlasSelectorTour="quickTour"> + <!-- TODO check when do we disable atlas selector --> + <button color="primary" + *ngIf="true" + matTooltip="Select layer" + mat-mini-fab + [attr.aria-label]="ARIA_LABELS.TOGGLE_ATLAS_LAYER_SELECTOR" + (click)="toggleSelector()"> + <i class="fas fa-layer-group"></i> + </button> +</div> diff --git a/src/atlasComponents/sapiViews/core/datasets/module.ts b/src/atlasComponents/sapiViews/core/datasets/module.ts index c25b3a58eedf49fb938febdd1f95b4bed430d798..b295da6bc25f1a9fdc98031a42810ba907013320 100644 --- a/src/atlasComponents/sapiViews/core/datasets/module.ts +++ b/src/atlasComponents/sapiViews/core/datasets/module.ts @@ -2,18 +2,18 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; import { MarkdownModule } from "src/components/markdown"; import { AngularMaterialModule } from "src/sharedModules"; +import { SapiViewsUtilModule } from "../../util/module"; import { DatasetView } from "./dataset/dataset.component"; -import { ParseDoiPipe } from "./parseDoi.pipe"; @NgModule({ imports: [ CommonModule, AngularMaterialModule, MarkdownModule, + SapiViewsUtilModule ], declarations: [ DatasetView, - ParseDoiPipe, ], exports: [ DatasetView diff --git a/src/atlasComponents/sapiViews/core/module.ts b/src/atlasComponents/sapiViews/core/module.ts index 6c377585d84bfe7f00b5cb2371a0b4fc8313a24e..3540a8cad111340aa311af447910d60fc26c521b 100644 --- a/src/atlasComponents/sapiViews/core/module.ts +++ b/src/atlasComponents/sapiViews/core/module.ts @@ -1,14 +1,26 @@ import { CommonModule } from "@angular/common"; import { NgModule } from "@angular/core"; +import { SapiViewsCoreAtlasModule } from "./atlas/module"; import { SapiViewsCoreDatasetModule } from "./datasets"; +import { SapiViewsCoreParcellationModule } from "./parcellation/module"; +import { SapiViewsCoreRegionModule } from "./region"; +import { SapiViewsCoreSpaceModule } from "./space"; @NgModule({ imports: [ CommonModule, SapiViewsCoreDatasetModule, + SapiViewsCoreRegionModule, + SapiViewsCoreAtlasModule, + SapiViewsCoreSpaceModule, + SapiViewsCoreParcellationModule, ], exports: [ - SapiViewsCoreDatasetModule + SapiViewsCoreDatasetModule, + SapiViewsCoreRegionModule, + SapiViewsCoreAtlasModule, + SapiViewsCoreSpaceModule, + SapiViewsCoreParcellationModule, ] }) diff --git a/src/atlasComponents/sapiViews/core/parcellation/filterGroupedParcellations.pipe.ts b/src/atlasComponents/sapiViews/core/parcellation/filterGroupedParcellations.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..62910eab45e5529ee22f137afa92e4978d42cfe4 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/filterGroupedParcellations.pipe.ts @@ -0,0 +1,31 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { SapiParcellationModel } from "src/atlasComponents/sapi"; +import { GroupedParcellation } from "./groupedParcellation"; + +@Pipe({ + name: `filterGroupedParcs`, + pure: true +}) + +export class FilterGroupedParcellationPipe implements PipeTransform{ + public transform(parcs: SapiParcellationModel[], getGroupsFlag: boolean=false): (SapiParcellationModel|GroupedParcellation)[] { + if (!getGroupsFlag) { + return parcs.filter(p => !p.modality) + } + const map: Record<string, SapiParcellationModel[]> = {} + for (const parc of parcs.filter(p => !!p.modality)) { + if (!map[parc.modality]) { + map[parc.modality] = [] + } + map[parc.modality].push(parc) + } + + const returnGrps: GroupedParcellation[] = [] + for (const key in map) { + returnGrps.push( + new GroupedParcellation(key, map[key]) + ) + } + return returnGrps + } +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/filterUnsupportedParc.pipe.ts b/src/atlasComponents/sapiViews/core/parcellation/filterUnsupportedParc.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..188a83b0a71ad0a21ba1e1840cea50dabc158af3 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/filterUnsupportedParc.pipe.ts @@ -0,0 +1,30 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { SapiParcellationModel } from "src/atlasComponents/sapi/type"; +import { GroupedParcellation } from "./groupedParcellation"; + +type Filterables = SapiParcellationModel | GroupedParcellation + +const unsupportedIds = [ + "https://doi.org/10.1016/j.jneumeth.2020.108983/mni152", + "https://identifiers.org/neurovault.image:23262" +] + +const hideGroup = [ + "cytoarchitecture" +] + +@Pipe({ + name: `filterUnsupportedParc`, + pure: true +}) + +export class FilterUnsupportedParcPipe implements PipeTransform{ + public transform<T extends Filterables>(parcs: T[]): T[] { + return parcs.filter(p => { + if (p instanceof GroupedParcellation) { + return hideGroup.indexOf(p.name) < 0 + } + return unsupportedIds.indexOf(p["@id"]) < 0 + }) + } +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/groupedParcellation.ts b/src/atlasComponents/sapiViews/core/parcellation/groupedParcellation.ts new file mode 100644 index 0000000000000000000000000000000000000000..c66d6e9818a3884cb0c48fc58de56bee4373e113 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/groupedParcellation.ts @@ -0,0 +1,10 @@ +import { SapiParcellationModel } from "src/atlasComponents/sapi" + +export class GroupedParcellation{ + name: string + parcellations: SapiParcellationModel[] + constructor(name: string, parcellations: SapiParcellationModel[]){ + this.name = name + this.parcellations = parcellations + } +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/index.ts b/src/atlasComponents/sapiViews/core/parcellation/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..801b1f3e381a6a806c94cd6458e3187a620755c1 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/index.ts @@ -0,0 +1,11 @@ +export { + SapiViewsCoreParcellationModule +} from "./module" + +export { + FilterGroupedParcellationPipe +} from "./filterGroupedParcellations.pipe" + +export { + FilterUnsupportedParcPipe +} from "./filterUnsupportedParc.pipe" \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/parcellation/module.ts b/src/atlasComponents/sapiViews/core/parcellation/module.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ef93bef579d86ada8f14739b3a5571ab7882b0e --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/module.ts @@ -0,0 +1,29 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { ComponentsModule } from "src/components"; +import { AngularMaterialModule } from "src/sharedModules"; +import { FilterGroupedParcellationPipe } from "./filterGroupedParcellations.pipe"; +import { FilterUnsupportedParcPipe } from "./filterUnsupportedParc.pipe"; +import { PreviewParcellationUrlPipe } from "./previewParcellationUrl.pipe"; +import { SapiViewsCoreParcellationParcellationTile } from "./tile/parcellation.tile.component"; + +@NgModule({ + imports: [ + CommonModule, + ComponentsModule, + AngularMaterialModule, + ], + declarations: [ + SapiViewsCoreParcellationParcellationTile, + PreviewParcellationUrlPipe, + FilterGroupedParcellationPipe, + FilterUnsupportedParcPipe, + ], + exports: [ + SapiViewsCoreParcellationParcellationTile, + FilterGroupedParcellationPipe, + FilterUnsupportedParcPipe, + ] +}) + +export class SapiViewsCoreParcellationModule{} \ No newline at end of file diff --git a/src/atlasComponents/parcellation/getParcPreviewUrl.pipe.ts b/src/atlasComponents/sapiViews/core/parcellation/previewParcellationUrl.pipe.ts similarity index 67% rename from src/atlasComponents/parcellation/getParcPreviewUrl.pipe.ts rename to src/atlasComponents/sapiViews/core/parcellation/previewParcellationUrl.pipe.ts index 3f70d60e90bdb1645d44f74edbe86ce7b6aec463..66a23202eeec67fa87b9d94ede25e6ad93283e4d 100644 --- a/src/atlasComponents/parcellation/getParcPreviewUrl.pipe.ts +++ b/src/atlasComponents/sapiViews/core/parcellation/previewParcellationUrl.pipe.ts @@ -1,12 +1,14 @@ -import { Pipe, PipeTransform } from "@angular/core" +import { Pipe, PipeTransform } from "@angular/core"; +import { SapiParcellationModel } from "src/atlasComponents/sapi"; +import { GroupedParcellation } from "./groupedParcellation"; const previewImgMap = new Map([ ['minds/core/parcellationatlas/v1.0.0/94c1125b-b87e-45e4-901c-00daee7f2579', 'cytoarchitectonic-maps.png'], ['juelich/iav/atlas/v1.0.0/3', 'cortical-layers.png'], ['juelich/iav/atlas/v1.0.0/4', 'grey-white-matter.png'], - ['juelich/iav/atlas/v1.0.0/5', 'firbe-long.png'], - ['juelich/iav/atlas/v1.0.0/6', 'firbe-short.png'], + ['juelich/iav/atlas/v1.0.0/5', 'fibre-long.png'], + ['juelich/iav/atlas/v1.0.0/6', 'fibre-short.png'], ['minds/core/parcellationatlas/v1.0.0/d80fbab2-ce7f-4901-a3a2-3c8ef8a3b721', 'difumo-64.png'], ['minds/core/parcellationatlas/v1.0.0/73f41e04-b7ee-4301-a828-4b298ad05ab8', 'difumo-128.png'], ['minds/core/parcellationatlas/v1.0.0/141d510f-0342-4f94-ace7-c97d5f160235', 'difumo-256.png'], @@ -29,21 +31,23 @@ const previewImgMap = new Map([ /** * used for directories */ -const previewNameToPngMap = new Map([ - ['fibre architecture', 'firbe-long.png'], + const previewNameToPngMap = new Map([ + ['fibre architecture', 'fibre-long.png'], ['functional modes', 'difumo-128.png'] ]) @Pipe({ - name: 'getParcPreviewUrl', + name: 'previewParcellationUrl', pure: true }) -export class GetParcPreviewUrlPipe implements PipeTransform{ - public transform(tile: any){ - const filename = tile['@id'] - ? previewImgMap.get(tile['@id']) - : previewNameToPngMap.get(tile['name']) +export class PreviewParcellationUrlPipe implements PipeTransform{ + public transform(tile: SapiParcellationModel | GroupedParcellation): string { + if (tile instanceof GroupedParcellation) { + const filename = previewNameToPngMap.get(tile.name) + return filename && `assets/images/atlas-selection/${filename}` + } + const filename = previewImgMap.get(tile['@id']) return filename && `assets/images/atlas-selection/${filename}` } } diff --git a/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.component.ts b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..e6052cd0ca1eeb0e7011c42b1fa53af6c60bbc71 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.component.ts @@ -0,0 +1,47 @@ +import { Component, EventEmitter, Input, OnChanges, Output, SimpleChanges } from "@angular/core"; +import { SapiParcellationModel } from "src/atlasComponents/sapi"; +import { GroupedParcellation } from "../groupedParcellation"; + +const lightthemeId = [ + 'juelich/iav/atlas/v1.0.0/3', + 'juelich/iav/atlas/v1.0.0/4', +] + +@Component({ + selector: `sxplr-sapiviews-core-parcellation-tile`, + templateUrl: './parcellation.tile.template.html', + styleUrls: [ + `./parcellation.tile.style.css` + ], +}) + +export class SapiViewsCoreParcellationParcellationTile implements OnChanges{ + @Input('sxplr-sapiviews-core-parcellation-tile-parcellation') + parcellation: SapiParcellationModel | GroupedParcellation + + @Input('sxplr-sapiviews-core-parcellation-tile-selected') + selected: boolean = false + + @Output('sxplr-sapiviews-core-parcellation-tile-onclick-parc') + onClickOnParcellation = new EventEmitter<SapiParcellationModel>() + + public gutterSize = "2" + public rowHeight = "6:11" + + public darktheme = false + public pureParc: SapiParcellationModel + public dirParc: GroupedParcellation + + ngOnChanges(): void { + if (this.parcellation instanceof GroupedParcellation) { + this.dirParc = this.parcellation + } else { + this.pureParc = this.parcellation + } + this.darktheme = !!this.dirParc || lightthemeId.indexOf(this.parcellation['@id']) < 0 + } + + clickOnParcellation(parc: SapiParcellationModel){ + this.onClickOnParcellation.emit(parc) + } +} diff --git a/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.stories.ts b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..fc7b39f5018544063d10e2247551ed249b0845f7 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.stories.ts @@ -0,0 +1,136 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { Component, Input, Output, EventEmitter } from "@angular/core" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI, SapiParcellationModel } from "src/atlasComponents/sapi" +import { atlasId, parcId, getAtlas, provideDarkTheme, getParc } from "src/atlasComponents/sapi/stories.base" +import { AngularMaterialModule } from "src/sharedModules" +import { SapiViewsCoreParcellationModule } from "../module" + +@Component({ + selector: `parc-tile-wrapper`, + template: ` + <mat-accordion> + <mat-expansion-panel *ngFor="let item of parcs | keyvalue"> + + <mat-expansion-panel-header> + {{ item.key }} + </mat-expansion-panel-header> + + <ng-template matExpansionPanelContent> + <div class="sxplr-d-inline-flex align-items-start"> + <sxplr-sapiviews-core-parcellation-tile + *ngFor="let parc of item.value" + [sxplr-sapiviews-core-parcellation-tile-parcellation]="parc" + [sxplr-sapiviews-core-parcellation-tile-selected]="parc['@id'] === selected" + class="sxplr-m-2" + (sxplr-sapiviews-core-parcellation-tile-onclick-parc)="parcClicked.emit($event)"> + </sxplr-sapiviews-core-parcellation-tile> + </div> + </ng-template> + + </mat-expansion-panel> + + <mat-expansion-panel> + <mat-expansion-panel-header> + > grouped + </mat-expansion-panel-header> + + <ng-template matExpansionPanelContent> + <ng-container *ngFor="let item of parcs | keyvalue"> + <sxplr-sapiviews-core-parcellation-tile + *ngFor="let parc of (item.value | filterGroupedParcs : true)" + [sxplr-sapiviews-core-parcellation-tile-parcellation]="parc" + class="sxplr-m-2" + (sxplr-sapiviews-core-parcellation-tile-onclick-parc)="parcClicked.emit($event)"> + </sxplr-sapiviews-core-parcellation-tile> + </ng-container> + </ng-template> + </mat-expansion-panel> + </mat-accordion> + `, + styles: [ + `sxplr-sapiviews-core-parcellation-tile { display: inline-block; max-width: 8rem; }` + ] +}) + +class ParcTileWrapper{ + @Input() + parcs: Record<string, SapiParcellationModel[]> = {} + + @Input() + selected: string = parcId.human.longBundle + + @Output() + parcClicked = new EventEmitter() +} + +export default { + component: ParcTileWrapper, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreParcellationModule, + AngularMaterialModule, + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [ + ParcTileWrapper + ] + }) + ], +} as Meta + +const Template: Story<ParcTileWrapper> = (args: ParcTileWrapper, { loaded }) => { + const { + parcs + } = loaded + + return ({ + props: { + ...args, + parcs + } + }) +} +Template.loaders = [ + +] + +const asyncLoader = async () => { + const parcs: Record<string, SapiParcellationModel[]> = {} + for (const species in atlasId) { + const atlasDetail = await getAtlas(atlasId[species]) + parcs[species] = [] + + for (const parc of atlasDetail.parcellations) { + const parcDetail = await getParc(atlasDetail['@id'], parc['@id']) + parcs[species].push(parcDetail) + } + } + + return { + parcs + } +} + +export const Default = Template.bind({}) +Default.args = { + selected: parcId.human.longBundle +} +Default.loaders = [ + + async () => { + const { + parcs + } = await asyncLoader() + return { + parcs + } + } +] diff --git a/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.style.css b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.style.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.template.html b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.template.html new file mode 100644 index 0000000000000000000000000000000000000000..774814d739967b41f277539d795b40aaa569b3e0 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/tile/parcellation.tile.template.html @@ -0,0 +1,54 @@ +<mat-menu hasBackDrop="false" #matMenu="matMenu"> + + <ng-template matMenuContent let-subParcellations="subParcellations"> + <div class="sxplr-ml-2 sxplr-mr-2"> + <mat-grid-list + cols="1" + [rowHeight]="rowHeight" + [gutterSize]="gutterSize"> + + <mat-grid-tile + *ngFor="let parc of subParcellations"> + + <tile-cmp *ngIf="parc" + [tile-text]="parc.name" + [tile-image-src]="parc | previewParcellationUrl" + [tile-selected]="selected" + [tile-image-darktheme]="darktheme" + (click)="clickOnParcellation(parc)"> + + </tile-cmp> + + </mat-grid-tile> + </mat-grid-list> + </div> + </ng-template> +</mat-menu> + +<ng-template [ngIf]="parcellation"> + + <tile-cmp *ngIf="pureParc" + [tile-text]="pureParc.name" + [tile-image-src]="pureParc | previewParcellationUrl" + [tile-selected]="selected" + [tile-image-darktheme]="darktheme" + (click)="clickOnParcellation(pureParc)" + > + + </tile-cmp> + + + <tile-cmp *ngIf="dirParc" + [tile-text]="dirParc.name" + [tile-image-src]="dirParc | previewParcellationUrl" + [tile-selected]="selected" + [tile-image-darktheme]="darktheme" + tile-is-dir="true" + [matMenuTriggerFor]="matMenu" + [matMenuTriggerData]="{ + subParcellations: dirParc.parcellations || [] + }" + > + </tile-cmp> + +</ng-template> \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/parcellation/tile/singleTile.stories.ts b/src/atlasComponents/sapiViews/core/parcellation/tile/singleTile.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..410456e99f31401f91342f43c9190b60898777ec --- /dev/null +++ b/src/atlasComponents/sapiViews/core/parcellation/tile/singleTile.stories.ts @@ -0,0 +1,86 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { Component, Input, Output, EventEmitter } from "@angular/core" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI, SapiParcellationModel } from "src/atlasComponents/sapi" +import { atlasId, parcId, getAtlas, provideDarkTheme, getParc, getHumanAtlas } from "src/atlasComponents/sapi/stories.base" +import { AngularMaterialModule } from "src/sharedModules" +import { FilterGroupedParcellationPipe } from "../filterGroupedParcellations.pipe" +import { GroupedParcellation } from "../groupedParcellation" +import { SapiViewsCoreParcellationModule } from "../module" +import { SapiViewsCoreParcellationParcellationTile } from "./parcellation.tile.component" + +export default { + component: SapiViewsCoreParcellationParcellationTile, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreParcellationModule, + AngularMaterialModule, + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [ + + ] + }) + ], +} as Meta + +const Template: Story<SapiViewsCoreParcellationParcellationTile> = (args: SapiViewsCoreParcellationParcellationTile, { loaded }) => { + const { + groups + } = loaded + + const { + gutterSize, + rowHeight + } = args + return ({ + props: { + gutterSize, + rowHeight, + parcellation: groups[1] + } + }) +} +Template.loaders = [ + +] + +const asyncLoader = async () => { + const parcs: SapiParcellationModel[] = [] + + const atlasDetail = await getHumanAtlas() + + for (const parc of atlasDetail.parcellations) { + const parcDetail = await getParc(atlasDetail['@id'], parc['@id']) + parcs.push(parcDetail) + } + + const pipe = new FilterGroupedParcellationPipe() + const groups = pipe.transform(parcs, true) as GroupedParcellation[] + return { + groups + } +} + +export const Default = Template.bind({}) +Default.args = { + selected: parcId.human.longBundle +} +Default.loaders = [ + + async () => { + const { + groups + } = await asyncLoader() + return { + groups + } + } +] diff --git a/src/atlasComponents/sapiViews/core/region/index.ts b/src/atlasComponents/sapiViews/core/region/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8b76cf0a9a6de3c8d738f9fb145fb97a7faceb61 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/index.ts @@ -0,0 +1 @@ +export { SapiViewsCoreRegionModule } from "./module" \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/region/module.ts b/src/atlasComponents/sapiViews/core/region/module.ts new file mode 100644 index 0000000000000000000000000000000000000000..511a1fcb8c770c56dbd9e64de315c7c09b9d38c4 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/module.ts @@ -0,0 +1,32 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { AngularMaterialModule } from "src/sharedModules"; +import { SapiViewsFeaturesModule } from "../../features"; +import { SapiViewsUtilModule } from "../../util/module"; +import { SapiViewsCoreRegionRegionListItem } from "./region/listItem/region.listItem.component"; +import { SapiViewsCoreRegionRegionBase } from "./region/region.base.directive"; +import { SapiViewsCoreRegionRegionalFeatureDirective } from "./region/region.features.directive"; +import { SapiViewsCoreRegionRegionRich } from "./region/rich/region.rich.component"; + +@NgModule({ + imports: [ + CommonModule, + AngularMaterialModule, + SapiViewsUtilModule, + SapiViewsFeaturesModule + ], + declarations: [ + SapiViewsCoreRegionRegionListItem, + SapiViewsCoreRegionRegionRich, + SapiViewsCoreRegionRegionBase, + SapiViewsCoreRegionRegionalFeatureDirective, + ], + exports: [ + SapiViewsCoreRegionRegionListItem, + SapiViewsCoreRegionRegionRich, + SapiViewsCoreRegionRegionBase, + SapiViewsCoreRegionRegionalFeatureDirective, + ] +}) + +export class SapiViewsCoreRegionModule{} \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.component.ts b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..449b7fa3f4947b07df2c2df7afac1d7e04e4e738 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from "@angular/core"; +import { SapiViewsCoreRegionRegionBase } from "../region.base.directive"; + +@Component({ + selector: 'sxplr-sapiviews-core-region-region-list-item', + templateUrl: './region.listItem.template.html', + styleUrls: [ + `./region.listItem.style.css` + ] +}) + +export class SapiViewsCoreRegionRegionListItem extends SapiViewsCoreRegionRegionBase { + @Input('sxplr-sapiviews-core-region-region-list-item-ripple') + ripple: boolean = false +} \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.stories.ts b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..900bd2e0a0f01a7ec5797aec22c19bb539aee4a7 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.stories.ts @@ -0,0 +1,123 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI } from "src/atlasComponents/sapi" +import { getHoc1Left, getHumanAtlas, getJba29, getMni152, provideDarkTheme } from "src/atlasComponents/sapi/stories.base" +import { SapiViewsCoreRegionModule } from "../../module" +import { SapiViewsCoreRegionRegionListItem } from "./region.listItem.component" + +export default { + component: SapiViewsCoreRegionRegionListItem, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreRegionModule, + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [] + }) + ], +} as Meta + +const Template: Story<SapiViewsCoreRegionRegionListItem> = (args: SapiViewsCoreRegionRegionListItem, { loaded, parameters }) => { + const { + human, + mni152, + jba29, + hoc1left + } = loaded + + const { contentProjection } = parameters + return ({ + props: { + ...args, + atlas: human, + template: mni152, + parcellation: jba29, + region: hoc1left, + ripple: true + }, + template: ` + <sxplr-sapiviews-core-region-region-list-item> + ${contentProjection || ''} + </sxplr-sapiviews-core-region-region-list-item> + ` + }) +} + +const loadRegions = async () => { + + const human = await getHumanAtlas() + const mni152 = await getMni152() + const jba29 = await getJba29() + const hoc1left = await getHoc1Left(mni152["@id"]) + + return { + human, + mni152, + jba29, + hoc1left, + } +} + +export const HumanMni152Jba29Hoc1Left = Template.bind({}) +HumanMni152Jba29Hoc1Left.args = { + +} +HumanMni152Jba29Hoc1Left.loaders = [ + async () => { + const { + human, + mni152, + jba29, + hoc1left, + } = await loadRegions() + return { + human, + mni152, + jba29, + hoc1left, + } + } +] + + +const getPrefixSuffix = (prefix: string, suffix: string) => { + let returnVal = `` + if (prefix) { + returnVal += `<div prefix>${prefix}</div>` + } + if (suffix) { + returnVal += `<div suffix>${suffix}</div>` + } + return returnVal +} + +export const HeaderContentProjectionPrefix = Template.bind({}) +HeaderContentProjectionPrefix.loaders = [ + ...HumanMni152Jba29Hoc1Left.loaders +] +HeaderContentProjectionPrefix.parameters = { + contentProjection: getPrefixSuffix(`<i class="far fa-square"></i>`, null) +} + +export const HeaderContentProjectionSuffix = Template.bind({}) +HeaderContentProjectionSuffix.loaders = [ + ...HumanMni152Jba29Hoc1Left.loaders +] +HeaderContentProjectionSuffix.parameters = { + contentProjection: getPrefixSuffix(null, `<i class="fab fa-chrome"></i>`) +} + +export const HeaderContentProjectionBox = Template.bind({}) +HeaderContentProjectionBox.loaders = [ + ...HumanMni152Jba29Hoc1Left.loaders +] +HeaderContentProjectionBox.parameters = { + contentProjection: getPrefixSuffix(`TEXT`, `<button mat-raised-button>test button</button>`) +} diff --git a/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.style.css b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.style.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.template.html b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.template.html new file mode 100644 index 0000000000000000000000000000000000000000..4c833e9218409ff1ed338d4cc781dc852742fd52 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/listItem/region.listItem.template.html @@ -0,0 +1,7 @@ +<div *ngIf="region" matRipple [matRippleDisabled]="!ripple" class="sxplr-d-inline-flex"> + <ng-content select="[prefix]"></ng-content> + <span class="mat-body"> + {{ region.name }} + </span> + <ng-content select="[suffix]"></ng-content> +</div> \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/region/region/region.base.directive.ts b/src/atlasComponents/sapiViews/core/region/region/region.base.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..a84edee486bcbde88230a3629a5a0738ccc8db6b --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/region.base.directive.ts @@ -0,0 +1,72 @@ +import { Directive, Input } from "@angular/core"; +import { SapiAtlasModel, SapiParcellationModel, SapiRegionModel, SapiSpaceModel } from "src/atlasComponents/sapi"; +import { strToRgb, rgbToHsl, hexToRgb } from 'common/util' + +@Directive({ + selector: `sxplr-sapiviews-core-region` +}) +export class SapiViewsCoreRegionRegionBase { + + @Input('sxplr-sapiviews-core-region-atlas') + atlas: SapiAtlasModel + @Input('sxplr-sapiviews-core-region-template') + template: SapiSpaceModel + @Input('sxplr-sapiviews-core-region-parcellation') + parcellation: SapiParcellationModel + + private _region: SapiRegionModel + @Input('sxplr-sapiviews-core-region-region') + set region(val: SapiRegionModel) { + this._region = val + this.setupRegionDarkmode() + } + get region(){ + return this._region + } + + regionRgbString: string = `rgb(200, 200, 200)` + regionDarkmode = false + // in mm!! + regionPosition: number[] = null + dois: string[] = [] + + protected setupRegionDarkmode(){ + + this.regionRgbString = `rgb(200, 200, 200)` + this.regionDarkmode = false + this.regionPosition = null + this.dois = [] + + if (this.region) { + + /** + * color + */ + let rgb = [255, 200, 200] + if (this.region.hasAnnotation?.displayColor) { + rgb = hexToRgb(this.region?.hasAnnotation?.displayColor) + } else { + rgb = strToRgb(JSON.stringify(this.region)) + } + this.regionRgbString = `rgb(${rgb.join(',')})` + const [_h, _s, l] = rgbToHsl(...rgb) + this.regionDarkmode = l < 0.4 + + /** + * position + */ + this.regionPosition = this.region.hasAnnotation?.bestViewPoint?.coordinates.map(v => v.value) + + /** + * dois + */ + this.dois = (this.region.hasAnnotation?.inspiredBy || []) + .map(insp => insp["@id"] as string) + .filter(id => /^https?:\/\/doi\.org/.test(id)) + } + } + + navigateTo(position: number[]) { + console.log('navigate to region', position) + } +} diff --git a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.component.ts b/src/atlasComponents/sapiViews/core/region/region/region.features.directive.ts similarity index 51% rename from src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.component.ts rename to src/atlasComponents/sapiViews/core/region/region/region.features.directive.ts index fbeba8f3d258e03cdc56d0f75c2f0a1c53001106..c2e1d640fc4069217f533ca859a534c530c30235 100644 --- a/src/atlasComponents/parcellationRegion/regionalFeatures/regionalFeaturesList/regionalFeaturesList.component.ts +++ b/src/atlasComponents/sapiViews/core/region/region/region.features.directive.ts @@ -1,32 +1,15 @@ -import { Component, EventEmitter, Input, OnChanges, Output } from "@angular/core"; +import { Directive, OnChanges, SimpleChanges } from "@angular/core"; import { BehaviorSubject, Observable } from "rxjs"; -import { filter, shareReplay, startWith, switchMap } from "rxjs/operators"; +import { switchMap, filter, startWith, shareReplay } from "rxjs/operators"; import { SAPI, SapiAtlasModel, SapiParcellationModel, SapiRegionalFeatureModel, SapiRegionModel, SapiSpaceModel } from "src/atlasComponents/sapi"; +import { SapiViewsCoreRegionRegionBase } from "./region.base.directive"; -@Component({ - selector: 'regional-features-list', - templateUrl: './regionalFeaturesList.template.html', - styleUrls: [ - './regionalFeaturesList.style.css' - ] +@Directive({ + selector: '[sxplr-sapiviews-core-region-regional-feature]', + exportAs: 'sapiViewsRegionalFeature' }) -export class RegionalFeaturesList implements OnChanges{ - - @Input('regional-features-list-atlas') - atlas: SapiAtlasModel - - @Input('regional-features-list-template') - template: SapiSpaceModel - - @Input('regional-features-list-parcellation') - parcellation: SapiParcellationModel - - @Input('regional-features-list-region') - region: SapiRegionModel - - @Output('regional-features-list-feat-clicked') - featureClicked = new EventEmitter<SapiRegionalFeatureModel>() +export class SapiViewsCoreRegionRegionalFeatureDirective extends SapiViewsCoreRegionRegionBase implements OnChanges{ private ATPR$ = new BehaviorSubject<{ atlas: SapiAtlasModel @@ -35,6 +18,15 @@ export class RegionalFeaturesList implements OnChanges{ region: SapiRegionModel }>(null) + ngOnChanges(sc: SimpleChanges): void { + const { atlas, template, parcellation, region } = this + this.ATPR$.next({ atlas, template, parcellation, region }) + } + + constructor(private sapi: SAPI){ + super() + } + public listOfFeatures$: Observable<SapiRegionalFeatureModel[]> = this.ATPR$.pipe( filter(arg => { if (!arg) return false @@ -45,15 +37,4 @@ export class RegionalFeaturesList implements OnChanges{ startWith([]), shareReplay(1), ) - - ngOnChanges(): void { - const { atlas, template, parcellation, region } = this - this.ATPR$.next({ atlas, template, parcellation, region }) - } - - constructor(private sapi: SAPI){} - - showFeature(feat: SapiRegionalFeatureModel){ - this.featureClicked.emit(feat) - } } diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.component.ts b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..60eb0e4979f2dc64913ca686cd8caee878646331 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.component.ts @@ -0,0 +1,49 @@ +import { Component, EventEmitter, Inject, Output } from "@angular/core"; +import { Observable, Subject } from "rxjs"; +import { DARKTHEME } from "src/util/injectionTokens"; +import { SapiViewsCoreRegionRegionBase } from "../region.base.directive"; +import { ARIA_LABELS, CONST } from 'common/constants' +import { SapiRegionalFeatureModel } from "src/atlasComponents/sapi"; + +@Component({ + selector: 'sxplr-sapiviews-core-region-region-rich', + templateUrl: './region.rich.template.html', + styleUrls: [ + `./region.rich.style.css` + ] +}) + +export class SapiViewsCoreRegionRegionRich extends SapiViewsCoreRegionRegionBase{ + + get ARIA_LABELS() { + return ARIA_LABELS + } + + get CONST() { + return CONST + } + + @Output('sxplr-sapiviews-core-region-region-rich-feature-clicked') + featureClicked = new EventEmitter<SapiRegionalFeatureModel>() + + constructor( + @Inject(DARKTHEME) public darktheme$: Observable<boolean> + ){ + super() + } + + handleRegionalFeatureClicked(feat: SapiRegionalFeatureModel) { + this.featureClicked.emit(feat) + } + + handleExpansionPanelClosedEv(title: string){ + console.log("title", title) + } + + handleExpansionPanelAfterExpandEv(title: string) { + console.log("title", title) + } + + activePanelTitles$: Observable<string[]> = new Subject() + +} diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.stories.ts b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..818f0b227362e5ce9ac3a6035a09bc4e25b2818e --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.stories.ts @@ -0,0 +1,103 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI } from "src/atlasComponents/sapi" +import { getHoc1Left, getHumanAtlas, getJba29, getMni152, provideDarkTheme } from "src/atlasComponents/sapi/stories.base" +import { SapiViewsCoreRegionModule } from "../../module" +import { SapiViewsCoreRegionRegionRich } from "./region.rich.component" +import { action } from '@storybook/addon-actions'; + +const actionsData = { + onNavigateTo: action('onNavigateTo'), + onHandleRegionalFeatureClicked: action('onHandleRegionalFeatureClicked') +} + +export default { + component: SapiViewsCoreRegionRegionRich, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreRegionModule, + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [] + }) + ], +} as Meta + +const Template: Story<SapiViewsCoreRegionRegionRich> = (args: SapiViewsCoreRegionRegionRich, { loaded, parameters }) => { + const { + human, + mni152, + jba29, + hoc1left + } = loaded + + const { contentProjection } = parameters + return ({ + props: { + ...args, + atlas: human, + template: mni152, + parcellation: jba29, + region: hoc1left, + navigateTo: actionsData.onNavigateTo, + handleRegionalFeatureClicked: actionsData.onHandleRegionalFeatureClicked + }, + template: ` + <sxplr-sapiviews-core-region-region-rich> + ${contentProjection || ''} + </sxplr-sapiviews-core-region-region-rich> + ` + }) +} + +const loadRegions = async () => { + + const human = await getHumanAtlas() + const mni152 = await getMni152() + const jba29 = await getJba29() + const hoc1left = await getHoc1Left(mni152["@id"]) + + return { + human, + mni152, + jba29, + hoc1left, + } +} + +export const HumanMni152Jba29Hoc1Left = Template.bind({}) +HumanMni152Jba29Hoc1Left.args = { + +} +HumanMni152Jba29Hoc1Left.loaders = [ + async () => { + const { + human, + mni152, + jba29, + hoc1left, + } = await loadRegions() + return { + human, + mni152, + jba29, + hoc1left, + } + } +] + + +export const HeaderContentProjection = Template.bind({}) +HeaderContentProjection.loaders = [ + ...HumanMni152Jba29Hoc1Left.loaders +] +HeaderContentProjection.parameters = { + contentProjection: `<div header>HEADER CONTENT PROJECTED</div>` +} diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.style.css b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.style.css new file mode 100644 index 0000000000000000000000000000000000000000..a897b1ea9ca28e94e43c28f32593fa18fa3426d9 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.style.css @@ -0,0 +1,12 @@ +.vanishing-border +{ + padding: 16px; + margin: -16px!important; +} + +.feature-list-container +{ + max-height: 16rem; + overflow-x: hidden; + overflow-y: scroll; +} \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html new file mode 100644 index 0000000000000000000000000000000000000000..453707e72d044d826f925a950116752e73782a5e --- /dev/null +++ b/src/atlasComponents/sapiViews/core/region/region/rich/region.rich.template.html @@ -0,0 +1,142 @@ +<ng-template [ngIf]="region"> + +<mat-card class="mat-elevation-z4"> + <div + [style.backgroundColor]="regionRgbString" + class="vanishing-border" + [ngClass]="{ + 'darktheme': regionDarkmode === true, + 'lighttheme': regionDarkmode === false + }"> + + <ng-content [select]="[header]"></ng-content> + + <mat-card-title class="iv-custom-comp text"> + {{ region.name }} + </mat-card-title> + + + <!-- subtitle on what it is --> + <mat-card-subtitle class="d-inline-flex align-items-center flex-wrap"> + <mat-icon fontSet="fas" fontIcon="fa-brain"></mat-icon> + <span> + Brain region + </span> + + <!-- origin datas format --> + + <mat-divider vertical="true" class="sxplr-pl-2 h-2rem"></mat-divider> + + <!-- position --> + <button mat-icon-button *ngIf="regionPosition" + (click)="navigateTo(regionPosition)" + [matTooltip]="ARIA_LABELS.GO_TO_REGION_CENTROID + ': ' + (regionPosition | numbers | addUnitAndJoin : 'mm')"> + <mat-icon fontSet="fas" fontIcon="fa-map-marked-alt"> + </mat-icon> + </button> + + <!-- explore doi --> + <a *ngFor="let doi of dois" + [href]="doi | parseDoi" + [matTooltip]="ARIA_LABELS.EXPLORE_DATASET_IN_KG" + target="_blank" + mat-icon-button> + <i class="fas fa-external-link-alt"></i> + </a> + + </mat-card-subtitle> + + </div> +</mat-card> + + +<!-- kg regional features list --> +<ng-template #kgRegionalFeatureList> + <div sxplr-sapiviews-core-region-regional-feature + [sxplr-sapiviews-core-region-atlas]="atlas" + [sxplr-sapiviews-core-region-template]="template" + [sxplr-sapiviews-core-region-parcellation]="parcellation" + [sxplr-sapiviews-core-region-region]="region" + #rfDir="sapiViewsRegionalFeature" + class="feature-list-container" + > + + <sxplr-sapiviews-features-entry-list-item + *ngFor="let feat of rfDir.listOfFeatures$ | async" + [sxplr-sapiviews-features-entry-list-item-feature]="feat" + (click)="handleRegionalFeatureClicked(feat)"> + </sxplr-sapiviews-features-entry-list-item> + </div> + +</ng-template> + + +<mat-accordion class="d-block mt-2"> + + <ng-container *ngTemplateOutlet="ngMatAccordionTmpl; context: { + title: CONST.REGIONAL_FEATURES, + iconClass: 'fas fa-database', + content: kgRegionalFeatureList, + desc: '', + iconTooltip: 'Regional Features', + iavNgIf: true + }"> + </ng-container> + +</mat-accordion> + +</ng-template> + + +<!-- expansion tmpl --> +<ng-template #ngMatAccordionTmpl + let-title="title" + let-desc="desc" + let-iconClass="iconClass" + let-iconTooltip="iconTooltip" + let-iavNgIf="iavNgIf" + let-content="content"> + + <mat-expansion-panel + [expanded]="activePanelTitles$ | async | includes : title" + [attr.data-opened]="expansionPanel.expanded" + [attr.data-mat-expansion-title]="title" + (closed)="handleExpansionPanelClosedEv(title)" + (afterExpand)="handleExpansionPanelAfterExpandEv(title)" + hideToggle + *ngIf="iavNgIf" + #expansionPanel="matExpansionPanel"> + + <mat-expansion-panel-header> + + <!-- title --> + <mat-panel-title> + {{ title }} + </mat-panel-title> + + <!-- desc + icon --> + <mat-panel-description class="sxplr-d-flex sxplr-align-items-center sxplr-justify-content-end" + [matTooltip]="iconTooltip"> + <span class="mr-3">{{ desc }}</span> + <span class="accordion-icon d-inline-flex justify-content-center"> + <i [class]="iconClass"></i> + </span> + </mat-panel-description> + + </mat-expansion-panel-header> + + <!-- content --> + <ng-template matExpansionPanelContent> + <ng-container *ngTemplateOutlet="content; context: { + expansionPanel: expansionPanel + }"> + </ng-container> + </ng-template> + </mat-expansion-panel> +</ng-template> + +<!-- fall back if region is not provided --> + +<ng-template [ngIf]="!region"> + Region must be provided! +</ng-template> \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/space/index.ts b/src/atlasComponents/sapiViews/core/space/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..46f783b69e03bdae2ef01144ba731e0b264c1c12 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/space/index.ts @@ -0,0 +1 @@ +export { SapiViewsCoreSpaceModule } from "./module" \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/space/module.ts b/src/atlasComponents/sapiViews/core/space/module.ts new file mode 100644 index 0000000000000000000000000000000000000000..a55902c111b8a2de12a53062f23d7d61e31047ab --- /dev/null +++ b/src/atlasComponents/sapiViews/core/space/module.ts @@ -0,0 +1,21 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { ComponentsModule } from "src/components"; +import { PreviewSpaceUrlPipe } from "./previewSpaceUrl.pipe"; +import { SapiViewsCoreSpaceSpaceTile } from "./tile/space.tile.component"; + +@NgModule({ + imports: [ + CommonModule, + ComponentsModule, + ], + declarations: [ + SapiViewsCoreSpaceSpaceTile, + PreviewSpaceUrlPipe, + ], + exports: [ + SapiViewsCoreSpaceSpaceTile, + ] +}) + +export class SapiViewsCoreSpaceModule{} \ No newline at end of file diff --git a/src/atlasComponents/template/getTemplatePreviewUrl.pipe.ts b/src/atlasComponents/sapiViews/core/space/previewSpaceUrl.pipe.ts similarity index 84% rename from src/atlasComponents/template/getTemplatePreviewUrl.pipe.ts rename to src/atlasComponents/sapiViews/core/space/previewSpaceUrl.pipe.ts index c2071c8af1b686baee241c47608695b7a709667d..8bbecdf23e0cf041912d5293c3be12eef5d5f7b6 100644 --- a/src/atlasComponents/template/getTemplatePreviewUrl.pipe.ts +++ b/src/atlasComponents/sapiViews/core/space/previewSpaceUrl.pipe.ts @@ -1,4 +1,5 @@ import { Pipe, PipeTransform } from "@angular/core" +import { SapiSpaceModel } from "src/atlasComponents/sapi" const previewImgMap = new Map([ ['minds/core/referencespace/v1.0.0/a1655b99-82f1-420f-a3c2-fe80fd4c8588', 'bigbrain.png'], @@ -18,12 +19,12 @@ const previewImgMap = new Map([ ]) @Pipe({ - name: 'getTemplatePreviewUrl', + name: 'previewSpaceUrl', pure: true }) -export class GetTemplatePreviewUrlPipe implements PipeTransform{ - public transform(tile: any){ +export class PreviewSpaceUrlPipe implements PipeTransform{ + public transform(tile: SapiSpaceModel){ const filename = previewImgMap.get(tile['@id']) return filename && `assets/images/atlas-selection/${filename}` } diff --git a/src/atlasComponents/sapiViews/core/space/tile/space.tile.component.ts b/src/atlasComponents/sapiViews/core/space/tile/space.tile.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..e9aaab3bebbdce796155a754857d9b0ff67ce090 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/space/tile/space.tile.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from "@angular/core"; +import { SapiSpaceModel } from "src/atlasComponents/sapi"; + +@Component({ + selector: `sxplr-sapiviews-core-space-tile`, + templateUrl: `./space.tile.template.html`, + styleUrls: [ + `./space.tile.style.css` + ] +}) + +export class SapiViewsCoreSpaceSpaceTile { + @Input('sxplr-sapiviews-core-space-tile-space') + space: SapiSpaceModel + + @Input('sxplr-sapiviews-core-space-tile-selected') + selected: boolean = false + +} \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/core/space/tile/space.tile.stories.ts b/src/atlasComponents/sapiViews/core/space/tile/space.tile.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd385d0f599b21101fdc6021714ad78e921d5178 --- /dev/null +++ b/src/atlasComponents/sapiViews/core/space/tile/space.tile.stories.ts @@ -0,0 +1,116 @@ +import { CommonModule } from "@angular/common" +import { HttpClientModule } from "@angular/common/http" +import { Component, Input } from "@angular/core" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SAPI, SapiSpaceModel } from "src/atlasComponents/sapi" +import { atlasId, spaceId, getAtlas, getSpace, provideDarkTheme } from "src/atlasComponents/sapi/stories.base" +import { AngularMaterialModule } from "src/sharedModules" +import { SapiViewsCoreSpaceModule } from "../module" +import { SapiViewsCoreSpaceSpaceTile } from "./space.tile.component" + +@Component({ + selector: `space-tile-wrapper`, + template: ` + <mat-accordion> + <mat-expansion-panel *ngFor="let item of spaces | keyvalue"> + + <mat-expansion-panel-header> + {{ item.key }} + </mat-expansion-panel-header> + + <ng-template matExpansionPanelContent> + <div class="sxplr-d-inline-flex align-items-start"> + <sxplr-sapiviews-core-space-tile + *ngFor="let spc of item.value" + [sxplr-sapiviews-core-space-tile-space]="spc" + [sxplr-sapiviews-core-space-tile-selected]="spc['@id'] === selected" + class="sxplr-m-2"> + </sxplr-sapiviews-core-space-tile> + </div> + </ng-template> + + </mat-expansion-panel> + </mat-accordion> + `, + styles: [ + `sxplr-sapiviews-core-space-tile { display: inline-block; max-width: 8rem; }` + ] +}) + +class SpaceTileWrapper{ + @Input() + spaces: Record<string, SapiSpaceModel[]> = {} + + @Input() + selected: string = spaceId.human.mni152 +} + +export default { + component: SpaceTileWrapper, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + HttpClientModule, + SapiViewsCoreSpaceModule, + AngularMaterialModule, + ], + providers: [ + SAPI, + ...provideDarkTheme, + ], + declarations: [ + SpaceTileWrapper + ] + }) + ], +} as Meta + +const Template: Story<SapiViewsCoreSpaceSpaceTile> = (args: SapiViewsCoreSpaceSpaceTile, { loaded }) => { + const { + spaces + } = loaded + + return ({ + props: { + ...args, + spaces + } + }) +} +Template.loaders = [ + +] + +const asyncLoader = async () => { + const spaces: Record<string, SapiSpaceModel[]> = {} + for (const species in atlasId) { + const atlasDetail = await getAtlas(atlasId[species]) + spaces[species] = [] + + for (const spc of atlasDetail.spaces) { + const spcDetail = await getSpace(atlasDetail['@id'], spc['@id']) + spaces[species].push(spcDetail) + } + } + + return { + spaces + } +} + +export const Default = Template.bind({}) +Default.args = { + selected: spaceId.human.mni152 +} +Default.loaders = [ + + async () => { + const { + spaces + } = await asyncLoader() + return { + spaces + } + } +] diff --git a/src/atlasComponents/sapiViews/core/space/tile/space.tile.style.css b/src/atlasComponents/sapiViews/core/space/tile/space.tile.style.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/src/atlasComponents/sapiViews/core/space/tile/space.tile.template.html b/src/atlasComponents/sapiViews/core/space/tile/space.tile.template.html new file mode 100644 index 0000000000000000000000000000000000000000..74ba27c9a7384a0f470b083f4aa5a1df4489401a --- /dev/null +++ b/src/atlasComponents/sapiViews/core/space/tile/space.tile.template.html @@ -0,0 +1,7 @@ +<tile-cmp + *ngIf="space" + [tile-text]="space.fullName" + [tile-image-src]="space | previewSpaceUrl" + [tile-selected]="selected"> + +</tile-cmp> \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.component.ts b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..a7c5f4a8417acca1858a6112255a229e13efaec8 --- /dev/null +++ b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.component.ts @@ -0,0 +1,29 @@ +import { Component, Input } from "@angular/core"; +import { SapiFeatureModel, SapiRegionalFeatureModel, SapiSpatialFeatureModel, SapiParcellationFeatureModel } from "src/atlasComponents/sapi"; +import { SapiParcellationFeatureMatrixModel } from "src/atlasComponents/sapi/type"; + +@Component({ + selector: `sxplr-sapiviews-features-entry-list-item`, + templateUrl: `./entryListItem.template.html`, + styleUrls: [ + `./entryListItem.style.css` + ] +}) + +export class SapiViewsFeaturesEntryListItem{ + @Input('sxplr-sapiviews-features-entry-list-item-feature') + feature: SapiFeatureModel + + @Input('sxplr-sapiviews-features-entry-list-item-ripple') + ripple = true + + get label(): string{ + if (!this.feature) return null + if (this.feature.type === "siibra/base-dataset" || this.feature.type === "siibra/receptor") { + return (this.feature as (SapiRegionalFeatureModel | SapiSpatialFeatureModel)).metadata.fullName + } + return (this.feature as SapiParcellationFeatureMatrixModel).name + } + constructor(){ + } +} diff --git a/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.style.css b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.style.css new file mode 100644 index 0000000000000000000000000000000000000000..58f6c43f50f172f58c7933747209ca04ea5530a2 --- /dev/null +++ b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.style.css @@ -0,0 +1,5 @@ +:host span +{ + overflow: hidden; + white-space: nowrap; +} diff --git a/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html new file mode 100644 index 0000000000000000000000000000000000000000..b6cfc81d0cd9d9a39691b5f72fde25cf112b2321 --- /dev/null +++ b/src/atlasComponents/sapiViews/features/entryListItem/entryListItem.template.html @@ -0,0 +1,15 @@ +<div matRipple [matRippleDisabled]="!ripple" + class="sxplr-p-2"> + + <mat-chip-list [ngSwitch]="feature.type" class="scale-80 transform-origin-left-center"> + <mat-chip *ngSwitchCase="'siibra/receptor'" + [color]="feature | featureBadgeColour" + selected> + {{ feature | featureBadgeName }} + </mat-chip> + </mat-chip-list> + + <span class="d-block mat-body"> + {{ label }} + </span> +</div> diff --git a/src/atlasComponents/sapiViews/features/entryListItem/entryListitem.stories.ts b/src/atlasComponents/sapiViews/features/entryListItem/entryListitem.stories.ts new file mode 100644 index 0000000000000000000000000000000000000000..434fe9e1ec4fee2181e27077222441200d56dc3a --- /dev/null +++ b/src/atlasComponents/sapiViews/features/entryListItem/entryListitem.stories.ts @@ -0,0 +1,85 @@ +import { CommonModule } from "@angular/common" +import { Meta, moduleMetadata, Story } from "@storybook/angular" +import { SapiFeatureModel } from "src/atlasComponents/sapi" +import { getHoc1Features, getJba29Features, provideDarkTheme } from "src/atlasComponents/sapi/stories.base" +import { AngularMaterialModule } from "src/sharedModules" +import { SapiViewsFeaturesEntryListItem } from "./entryListItem.component" +import { Component, EventEmitter, Input, Output } from "@angular/core" +import { SapiViewsFeaturesModule } from ".." + +@Component({ + selector: `feature-list-item-wrapper`, + template: ` + <mat-card> + <sxplr-sapiviews-features-entry-list-item + *ngFor="let feat of features" + (click)="clicked.emit(feat)" + [sxplr-sapiviews-features-entry-list-item-feature]="feat" + [sxplr-sapiviews-features-entry-list-item-ripple]="ripple"> + </sxplr-sapiviews-features-entry-list-item> + </mat-card> + ` +}) + +class FeatureListItemWrapper { + features: SapiFeatureModel[] = [] + + @Input() + ripple: boolean = true + + @Output() + clicked = new EventEmitter() +} + +export default { + component: FeatureListItemWrapper, + decorators: [ + moduleMetadata({ + imports: [ + CommonModule, + AngularMaterialModule, + SapiViewsFeaturesModule, + ], + declarations: [], + providers: [ + ...provideDarkTheme, + ], + }) + ], + +} as Meta + +const Template: Story<SapiViewsFeaturesEntryListItem> = (args: SapiViewsFeaturesEntryListItem, { loaded }) => { + const { features } = loaded + return ({ + props: { + ...args, + features + }, + }) +} + + +export const RegionalFeatures = Template.bind({}) +RegionalFeatures.args = { + +} +RegionalFeatures.loaders = [ + async () => { + const features = await getHoc1Features() + return { + features + } + } +] + +export const ParcellationFeatures = Template.bind({}) +ParcellationFeatures.loaders = [ + async () => { + + const features = await getJba29Features() + return { + features + } + } +] \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/features/featureBadgeColor.pipe.ts b/src/atlasComponents/sapiViews/features/featureBadgeColor.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..9d8be8736f56934d4e39f6b9bfb52f6523d2326d --- /dev/null +++ b/src/atlasComponents/sapiViews/features/featureBadgeColor.pipe.ts @@ -0,0 +1,16 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { SapiFeatureModel } from "src/atlasComponents/sapi"; + +@Pipe({ + name: 'featureBadgeColour', + pure: true +}) + +export class FeatureBadgeColourPipe implements PipeTransform{ + public transform(regionalFeature: SapiFeatureModel) { + if (regionalFeature.type === "siibra/receptor") { + return "accent" + } + return "default" + } +} diff --git a/src/atlasComponents/sapiViews/features/featureBadgeName.pipe.ts b/src/atlasComponents/sapiViews/features/featureBadgeName.pipe.ts new file mode 100644 index 0000000000000000000000000000000000000000..3b0faa80ce3e6587a99b77962dd55be83c6e659f --- /dev/null +++ b/src/atlasComponents/sapiViews/features/featureBadgeName.pipe.ts @@ -0,0 +1,16 @@ +import { Pipe, PipeTransform } from "@angular/core"; +import { SapiFeatureModel } from "src/atlasComponents/sapi"; + +@Pipe({ + name: 'featureBadgeName', + pure: true +}) + +export class FeatureBadgeNamePipe implements PipeTransform{ + public transform(regionalFeature: SapiFeatureModel) { + if (regionalFeature.type === "siibra/receptor") { + return "receptor density" + } + return null + } +} diff --git a/src/atlasComponents/sapiViews/features/module.ts b/src/atlasComponents/sapiViews/features/module.ts index 61dfd3091bf1bb7d4ae815b6173b3194d0830164..654d96c9ca9143516658b3505c9916a83df26858 100644 --- a/src/atlasComponents/sapiViews/features/module.ts +++ b/src/atlasComponents/sapiViews/features/module.ts @@ -1,7 +1,11 @@ -import { CommonModule } from "@angular/common" +import { CommonModule, DOCUMENT } from "@angular/common" import { NgModule } from "@angular/core" import { AngularMaterialModule } from "src/sharedModules" +import { appendScriptFactory, APPEND_SCRIPT_TOKEN } from "src/util/constants" import { FeatureEntryCmp } from "./entry/entry.component" +import { SapiViewsFeaturesEntryListItem } from "./entryListItem/entryListItem.component" +import { FeatureBadgeColourPipe } from "./featureBadgeColor.pipe" +import { FeatureBadgeNamePipe } from "./featureBadgeName.pipe" import * as ieeg from "./ieeg" import * as receptor from "./receptors" @@ -21,10 +25,21 @@ const { declarations: [ IEEGSessionCmp, FeatureEntryCmp, + FeatureBadgeNamePipe, + FeatureBadgeColourPipe, + SapiViewsFeaturesEntryListItem, + ], + providers: [ + { + provide: APPEND_SCRIPT_TOKEN, + useFactory: appendScriptFactory, + deps: [ DOCUMENT ] + } ], exports: [ IEEGSessionCmp, FeatureEntryCmp, + SapiViewsFeaturesEntryListItem, ] }) export class SapiViewsFeaturesModule{} \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/index.ts b/src/atlasComponents/sapiViews/index.ts index 1afef564d73a7aaa4f0923b2ba62656418d76ca8..9fdab95aa0bcf8ede9d104573c674ec8f243483e 100644 --- a/src/atlasComponents/sapiViews/index.ts +++ b/src/atlasComponents/sapiViews/index.ts @@ -1,3 +1,4 @@ export { SapiViewsModule } from "./module" +export { SapiViewsUtilModule } from "./util" \ No newline at end of file diff --git a/src/util/pipes/addUnitAndJoin.pipe.ts b/src/atlasComponents/sapiViews/util/addUnitAndJoin.pipe.ts similarity index 100% rename from src/util/pipes/addUnitAndJoin.pipe.ts rename to src/atlasComponents/sapiViews/util/addUnitAndJoin.pipe.ts diff --git a/src/util/pipes/includes.pipe.ts b/src/atlasComponents/sapiViews/util/includes.pipe.ts similarity index 100% rename from src/util/pipes/includes.pipe.ts rename to src/atlasComponents/sapiViews/util/includes.pipe.ts diff --git a/src/atlasComponents/sapiViews/util/index.ts b/src/atlasComponents/sapiViews/util/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..36e2c654710830f0df9fdbbf0ea024f6a200545c --- /dev/null +++ b/src/atlasComponents/sapiViews/util/index.ts @@ -0,0 +1 @@ +export { SapiViewsUtilModule } from "./module" \ No newline at end of file diff --git a/src/atlasComponents/sapiViews/util/module.ts b/src/atlasComponents/sapiViews/util/module.ts new file mode 100644 index 0000000000000000000000000000000000000000..4d99281d6df7f3836fe278d8992475b2e90f5847 --- /dev/null +++ b/src/atlasComponents/sapiViews/util/module.ts @@ -0,0 +1,22 @@ +import { NgModule } from "@angular/core"; +import { AddUnitAndJoin } from "./addUnitAndJoin.pipe"; +import { IncludesPipe } from "./includes.pipe"; +import { NumbersPipe } from "./numbers.pipe"; +import { ParseDoiPipe } from "./parseDoi.pipe"; + +@NgModule({ + declarations: [ + ParseDoiPipe, + NumbersPipe, + AddUnitAndJoin, + IncludesPipe, + ], + exports: [ + ParseDoiPipe, + NumbersPipe, + AddUnitAndJoin, + IncludesPipe, + ] +}) + +export class SapiViewsUtilModule{} \ No newline at end of file diff --git a/src/util/pipes/numbers.pipe.ts b/src/atlasComponents/sapiViews/util/numbers.pipe.ts similarity index 100% rename from src/util/pipes/numbers.pipe.ts rename to src/atlasComponents/sapiViews/util/numbers.pipe.ts diff --git a/src/atlasComponents/sapiViews/core/datasets/parseDoi.pipe.spec.ts b/src/atlasComponents/sapiViews/util/parseDoi.pipe.spec.ts similarity index 100% rename from src/atlasComponents/sapiViews/core/datasets/parseDoi.pipe.spec.ts rename to src/atlasComponents/sapiViews/util/parseDoi.pipe.spec.ts diff --git a/src/atlasComponents/sapiViews/core/datasets/parseDoi.pipe.ts b/src/atlasComponents/sapiViews/util/parseDoi.pipe.ts similarity index 100% rename from src/atlasComponents/sapiViews/core/datasets/parseDoi.pipe.ts rename to src/atlasComponents/sapiViews/util/parseDoi.pipe.ts diff --git a/src/atlasComponents/template/index.ts b/src/atlasComponents/template/index.ts index 38cd6578cc518656abb1303d11557b86529cc996..be326b3018b3ed5e54f47973a19f6e0f511edbd5 100644 --- a/src/atlasComponents/template/index.ts +++ b/src/atlasComponents/template/index.ts @@ -1,2 +1 @@ -export { GetTemplatePreviewUrlPipe } from "./getTemplatePreviewUrl.pipe"; export { SiibraExplorerTemplateModule } from './module' diff --git a/src/atlasComponents/template/module.ts b/src/atlasComponents/template/module.ts index 9f1a49646b274dc7936b24800f99a4bf12e152c7..c5823f4a7e82a1c1a0ee3ec85e6ae59049ead5ef 100644 --- a/src/atlasComponents/template/module.ts +++ b/src/atlasComponents/template/module.ts @@ -1,15 +1,12 @@ import { NgModule } from "@angular/core"; -import { GetTemplatePreviewUrlPipe } from "./getTemplatePreviewUrl.pipe"; import { TemplateIsDarkThemePipe } from "./templateIsDarkTheme.pipe"; @NgModule({ imports: [], declarations: [ - GetTemplatePreviewUrlPipe, TemplateIsDarkThemePipe, ], exports: [ - GetTemplatePreviewUrlPipe, TemplateIsDarkThemePipe, ] }) diff --git a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.component.spec.ts b/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.component.spec.ts deleted file mode 100644 index 70b786d12ed055a08b57f5cf47f717bf6a266301..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.component.spec.ts +++ /dev/null @@ -1 +0,0 @@ -// TODO diff --git a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.component.ts b/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.component.ts deleted file mode 100644 index d3ef7a4d602c0b4298f1dff7caabbdbdce9aa3f4..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/atlasDropdown/atlasDropdown.component.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Component } from "@angular/core"; -import { Store, select } from "@ngrx/store"; -import { Observable } from "rxjs"; -import { ARIA_LABELS } from 'common/constants' -import { atlasSelection } from "src/state" -import { SAPI } from "src/atlasComponents/sapi"; - -@Component({ - selector: 'atlas-dropdown-selector', - templateUrl: './atlasDropdown.template.html', - styleUrls: [ - './atlasDropdown.style.css' - ] -}) - -export class AtlasDropdownSelector{ - - public fetchedAtlases$: Observable<any[]> - public selectedAtlas$: Observable<any> - - public SELECT_ATLAS_ARIA_LABEL = ARIA_LABELS.SELECT_ATLAS - - constructor( - private store$: Store<any>, - private sapi: SAPI, - ){ - this.fetchedAtlases$ = this.sapi.atlases$ - this.selectedAtlas$ = this.store$.pipe( - select(atlasSelection.selectors.selectedAtlas) - ) - } - - handleChangeAtlas({ value }) { - this.store$.dispatch( - atlasSelection.actions.selectATPById({ - atlasId: value - }) - ) - } -} - diff --git a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.spec.ts b/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.spec.ts deleted file mode 100644 index ac1cba2b02e1210747c708aadf634cd3ec219cf1..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.component.spec.ts +++ /dev/null @@ -1,100 +0,0 @@ -import { CommonModule } from "@angular/common" -import { ComponentFixture, TestBed } from "@angular/core/testing" -import { NoopAnimationsModule } from "@angular/platform-browser/animations" -import { MockStore, provideMockStore } from "@ngrx/store/testing" -import { ComponentsModule } from "src/components" -import { viewerStateSelectTemplateWithId } from "src/services/state/viewerState.store.helper" -import { AngularMaterialModule } from "src/sharedModules" -import { QuickTourModule } from "src/ui/quickTour" -import { GetGroupedParcPipe } from "../pipes/getGroupedParc.pipe" -import { GetIndividualParcPipe } from "../pipes/getIndividualParc.pipe" -import { GetNonbaseParcPipe } from "../pipes/getNonBaseParc.pipe" -import { AtlasLayerSelector } from "./atlasLayerSelector.component" - -describe("> atlasLayerSelector.component.ts", () => { - describe("> AtlasLayerSelector", () => { - let fixture: ComponentFixture<AtlasLayerSelector> - beforeEach(async () => { - await TestBed.configureTestingModule({ - imports: [ - CommonModule, - AngularMaterialModule, - NoopAnimationsModule, - QuickTourModule, - ComponentsModule, - ], - declarations: [ - AtlasLayerSelector, - GetIndividualParcPipe, - GetNonbaseParcPipe, - GetGroupedParcPipe, - ], - providers: [ - provideMockStore() - ] - }).compileComponents() - }) - - it("> can be init", () => { - fixture = TestBed.createComponent(AtlasLayerSelector) - expect(fixture).toBeTruthy() - }) - - describe("> methods", () => { - beforeEach(() => { - fixture = TestBed.createComponent(AtlasLayerSelector) - }) - describe("> selectParcellationWithName", () => { - let tmplSupportParcPipeTransform: jasmine.Spy - let storeDispatchSpy: jasmine.Spy - const dummySelectedTmpl = { - "this": "obj" - } - const dummyParc = { - "foo": "bar", - "availableIn": [{ - "baz": "yoo" - }] - } - beforeEach(() => { - tmplSupportParcPipeTransform = spyOn(fixture.componentInstance['currTmplSupportParcPipe'], 'transform') - const store = TestBed.inject(MockStore) - storeDispatchSpy = spyOn(store, 'dispatch') - fixture.componentInstance['selectedTemplate'] = dummySelectedTmpl - }) - afterEach(() => { - if (tmplSupportParcPipeTransform) { - tmplSupportParcPipeTransform.calls.reset() - } - }) - it("> calls pipe.transform", () => { - tmplSupportParcPipeTransform.and.returnValue(true) - fixture.componentInstance.selectParcellationWithName(dummyParc) - expect(tmplSupportParcPipeTransform).toHaveBeenCalledWith(dummySelectedTmpl, dummyParc) - expect(storeDispatchSpy).toHaveBeenCalledTimes(1) - }) - - const tmplChgReqParam = [true, false] - - for (const tmplChgReq of tmplChgReqParam) { - describe(`> tmplChgReq: ${tmplChgReq}`, () => { - it("> expect the correct type of method to be called", () => { - tmplSupportParcPipeTransform.and.returnValue(!tmplChgReq) - fixture.componentInstance.selectParcellationWithName(dummyParc) - const allArgs = storeDispatchSpy.calls.allArgs() - expect(allArgs.length).toEqual(1) - expect(allArgs[0].length).toEqual(1) - const action = allArgs[0][0] - - const expectedAction = tmplChgReq - ? viewerStateSelectTemplateWithId - : viewerStateToggleLayer - - expect(action.type).toEqual(expectedAction.type) - }) - }) - } - }) - }) - }) -}) diff --git a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html b/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html deleted file mode 100644 index b93e61fe24b492d47d332d594cdc4d129caa4bee..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/atlasLayerSelector/atlasLayerSelector.template.html +++ /dev/null @@ -1,168 +0,0 @@ -<!-- selector panel when expanded --> - -<mat-card class="selector-container m-2 position-absolute" - [ngClass]="{'pe-all': selectorExpanded}" - [@toggleAtlasLayerSelector]="selectorExpanded" - (@toggleAtlasLayerSelector.done)="atlasSelectorTour?.attachTo(selectorExpanded ? selectorPanelTemplateRef : null)" - #selectorPanelTmpl> - <mat-card-content> - - <!-- templates --> - <mat-card-subtitle> - {{ CONST.ATLAS_SELECTOR_LABEL_SPACES }} - </mat-card-subtitle> - - <!-- template grid and tiles --> - <mat-grid-list cols="3" - rowHeight="2:3" - gutterSize="16"> - - <mat-grid-tile *ngFor="let template of availableTemplates$ | async; trackBy: trackbyAtId" - [attr.aria-checked]="(selectedTemplate$ | async | getProperty : '@id') === template['@id']"> - - <div [hidden] - iav-dataset-show-dataset-dialog - [iav-dataset-show-dataset-dialog-name]="template.fullName" - #kgInfo="iavDatasetShowDatasetDialog"> - </div> - <tile-cmp [tile-image-src]="template | getPreviewUrlPipe" - class="cursor-pointer pe-all" - tile-image-alt="Preview of this tile" - [tile-text]="template.displayName || template.name" - [tile-show-info]="template.originDatainfos?.length > 0" - [tile-disabled]="!(selectedParcellation$ | async | currParcSupportsTmpl : template)" - [tile-image-darktheme]="template.darktheme" - [tile-selected]="(selectedTemplate$ | async | getProperty : '@id') === template['@id']" - (tile-on-click)="selectTemplatewithId(template['@id'])" - (tile-on-info-click)="kgInfo && kgInfo.onClick()"> - </tile-cmp> - </mat-grid-tile> - </mat-grid-list> - - <mat-divider></mat-divider> - - <!-- parcellations --> - <mat-card-subtitle class="mt-2"> - {{ CONST.ATLAS_SELECTOR_LABEL_PARC_MAPS }} - </mat-card-subtitle> - - <mat-grid-list cols="3" - rowHeight="2:3" - gutterSize="16"> - - <!-- non grouped layers --> - <mat-grid-tile *ngFor="let layer of (atlasLayersLatest$ | async ); trackBy: trackbyAtId" - [attr.aria-checked]="selectedParcellation$ | async | groupParcSelected : layer"> - {{ layer.name }} - <!-- <div [hidden] - iav-dataset-show-dataset-dialog - [iav-dataset-show-dataset-dialog-name]="layer.originDatainfos[0]?.name" - [iav-dataset-show-dataset-dialog-description]="layer.originDatainfos[0]?.description" - [iav-dataset-show-dataset-dialog-urls]="layer.originDatainfos[0]?.urls" - #kgInfo="iavDatasetShowDatasetDialog"> - </div> - <tile-cmp [tile-image-src]="layer | getPreviewUrlPipe" - class="cursor-pointer pe-all" - tile-image-alt="Preview of this tile" - [tile-text]="layer.displayName || layer.name" - [tile-show-info]="layer.originDatainfos?.length > 0" - [tile-disabled]="!(selectedTemplate$ | async | currentTemplateSupportsParcellation : layer)" - [tile-image-darktheme]="layer.darktheme" - - [tile-selected]="selectedParcellation$ | async | groupParcSelected : layer" - - (tile-on-click)="selectParcellationWithName(layer)" - (tile-on-info-click)="kgInfo && kgInfo.onClick()"> - </tile-cmp> --> - - </mat-grid-tile> - - <!-- grouped layers --> - <mat-grid-tile *ngFor="let groupKeyVal of (atlasLayersLatest$ | async | getNonbaseParc | getGroupedParc | keyvalue); trackBy: trackKeyVal" - [attr.aria-checked]="false"> - - <!-- prevent click bubbling to document is necessary --> - <!-- or else, the outsideclick directive will fire immediately --> - <!-- resulting in immediate opening and closing of mat menu --> - <tile-cmp [tile-image-src]="groupKeyVal['value'][0] | getPreviewUrlPipe" - class="cursor-pointer pe-all" - tile-image-alt="Preview of this tile" - [tile-text]="groupKeyVal['key']" - [tile-show-info]="false" - [tile-disabled]="!(selectedTemplate$ | async | currentTemplateSupportsParcellation : groupKeyVal['value'])" - [tile-image-darktheme]="groupKeyVal['value'][0].darktheme" - [tile-is-dir]="true" - [matMenuTriggerFor]=layerGroupMenu - [matMenuTriggerData]="{ - layerGroupItems: groupKeyVal['value'] - }" - [tile-selected]="selectedParcellation$ | async | groupParcSelected : groupKeyVal['value']" - iav-stop="click"> - </tile-cmp> - </mat-grid-tile> - </mat-grid-list> - </mat-card-content> - - <div [hidden]="!(showLoadingOverlay$ | async)" - class="loading-overlay"> - <spinner-cmp class="spinner"></spinner-cmp> - </div> -</mat-card> - -<!-- place holder when not expanded --> -<div class="position-relative m-2 cursor-pointer scale-up-bl pe-all" - quick-tour - [quick-tour-description]="quickTourData.description" - [quick-tour-order]="quickTourData.order" - #atlasSelectorTour="quickTour"> - <!-- TODO check when do we disable atlas selector --> - <button color="primary" - *ngIf="true" - matTooltip="Select layer" - mat-mini-fab - [attr.aria-label]="ARIA_LABELS.TOGGLE_ATLAS_LAYER_SELECTOR" - (click)="toggleSelector()"> - <i class="fas fa-layer-group"></i> - </button> -</div> - -<!-- mat menu for grouped layer --> -<mat-menu - #layerGroupMenu="matMenu" - hasBackdrop="false"> - - <ng-template matMenuContent let-layerGroupItems="layerGroupItems"> - <mat-grid-list cols="1" - rowHeight="6:7" - gutterSize="8" - iav-stop="click" - (iav-outsideClick)="collapseExpandedGroup()"> - <mat-grid-tile *ngFor="let layer of layerGroupItems" - [attr.aria-checked]="selectedParcellation$ | async | groupParcSelected : layer"> - - <div [hidden] - iav-dataset-show-dataset-dialog - [iav-dataset-show-dataset-dialog-name]="layer.originDatainfos[0]?.name" - [iav-dataset-show-dataset-dialog-description]="layer.originDatainfos[0]?.description" - [iav-dataset-show-dataset-dialog-urls]="layer.originDatainfos[0]?.urls" - #kgInfo="iavDatasetShowDatasetDialog"> - </div> - - <tile-cmp [tile-image-src]="layer | getPreviewUrlPipe" - class="iv-custom-comp text m-3 cursor-pointer pe-all" - tile-image-alt="Preview of this tile" - [tile-text]="layer.displayName || layer.name" - [tile-show-info]="layer.originDatainfos?.length > 0" - [tile-disabled]="!(selectedTemplate$ | async | currentTemplateSupportsParcellation : layer)" - [tile-image-darktheme]="layer.darktheme" - - [tile-selected]="selectedParcellation$ | async | groupParcSelected : layer" - (tile-on-click)="selectParcellationWithId(layer)" - (tile-on-info-click)="kgInfo && kgInfo.onClick()"> - </tile-cmp> - - </mat-grid-tile> - </mat-grid-list> - - </ng-template> -</mat-menu> diff --git a/src/atlasComponents/uiSelectors/index.ts b/src/atlasComponents/uiSelectors/index.ts deleted file mode 100644 index 28925e7dac73fcc4f6b8896a1026ec6c556a24e4..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export { AtlasCmpUiSelectorsModule } from "./module" -export { AtlasDropdownSelector } from "./atlasDropdown/atlasDropdown.component" -export { AtlasLayerSelector } from "./atlasLayerSelector/atlasLayerSelector.component" \ No newline at end of file diff --git a/src/atlasComponents/uiSelectors/module.ts b/src/atlasComponents/uiSelectors/module.ts deleted file mode 100644 index 2ab98df7ca53d16da552731ba4b67abb725e4301..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/module.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { CommonModule } from "@angular/common"; -import { NgModule } from "@angular/core"; -import { AngularMaterialModule } from "src/sharedModules"; -import { UtilModule } from "src/util"; -import { AtlasDropdownSelector } from "./atlasDropdown/atlasDropdown.component"; -import { AtlasLayerSelector } from "./atlasLayerSelector/atlasLayerSelector.component"; -import {QuickTourModule} from "src/ui/quickTour/module"; -import { AtlaslayerTooltipPipe } from "./pipes/atlasLayerTooltip.pipe"; -import { ComponentsModule } from "src/components"; -import { GetNonbaseParcPipe } from "./pipes/getNonBaseParc.pipe"; -import { GetIndividualParcPipe } from "./pipes/getIndividualParc.pipe"; -import { GetGroupedParcPipe } from "./pipes/getGroupedParc.pipe"; -import { CurrentTmplSupportsParcPipe } from "./pipes/currTmplSupportsParc.pipe"; -import { GroupParcSelectedPipe } from "./pipes/groupParcSelected.pipe"; -import { GetPreviewUrlPipe } from "./pipes/getPreviewUrl.pipe"; -import { CurrParcSupportsTmplPipe } from "./pipes/currParcSupportsTmpl.pipe"; -import { AtlasCmpParcellationModule } from "../parcellation"; -import { SiibraExplorerTemplateModule } from "../template"; -import { DialogInfoModule } from "src/ui/dialogInfo"; - -@NgModule({ - imports: [ - CommonModule, - AngularMaterialModule, - UtilModule, - QuickTourModule, - ComponentsModule, - AtlasCmpParcellationModule, - SiibraExplorerTemplateModule, - DialogInfoModule, - ], - declarations: [ - AtlasDropdownSelector, - AtlasLayerSelector, - GetPreviewUrlPipe, - AtlaslayerTooltipPipe, - GetNonbaseParcPipe, - GetIndividualParcPipe, - GetGroupedParcPipe, - CurrentTmplSupportsParcPipe, - GroupParcSelectedPipe, - CurrParcSupportsTmplPipe, - ], - exports: [ - AtlasDropdownSelector, - AtlasLayerSelector, - ] -}) - -export class AtlasCmpUiSelectorsModule{} diff --git a/src/atlasComponents/uiSelectors/pipes/atlasLayerTooltip.pipe.ts b/src/atlasComponents/uiSelectors/pipes/atlasLayerTooltip.pipe.ts deleted file mode 100644 index 285f134543afa5151de4627fe2f507515e5f81de..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/atlasLayerTooltip.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; - -@Pipe({ - name: 'atlasLayerTooltip', - pure: true -}) - -export class AtlaslayerTooltipPipe implements PipeTransform{ - public transform(layer: any){ - return layer.name - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/currParcSupportsTmpl.pipe.ts b/src/atlasComponents/uiSelectors/pipes/currParcSupportsTmpl.pipe.ts deleted file mode 100644 index dcdf13d404ba747a5ce65f9f1bbe6fb08189b196..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/currParcSupportsTmpl.pipe.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; - -@Pipe({ - name: 'currParcSupportsTmpl', - pure: true -}) - -export class CurrParcSupportsTmplPipe implements PipeTransform{ - public transform(parc: any, tmpl: any){ - /** - * TODO - * buggy. says julich brain v290 is not supported in fsaverage - * related to https://github.com/FZJ-INM1-BDA/siibra-python/issues/98 - */ - const parcSupportTmpl = (p: any) => !!(tmpl.availableIn || []).find(tmplP => tmplP['@id'] === p && p['@id']) - return Array.isArray(parc) - ? parc.some(parcSupportTmpl) - : parcSupportTmpl(parc) - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/currTmplSupportsParc.pipe.ts b/src/atlasComponents/uiSelectors/pipes/currTmplSupportsParc.pipe.ts deleted file mode 100644 index 6d1ed06bd92acea21148e64bc6815c5d4345aa73..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/currTmplSupportsParc.pipe.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; - -@Pipe({ - name: 'currentTemplateSupportsParcellation', - pure: true -}) - -export class CurrentTmplSupportsParcPipe implements PipeTransform{ - public transform(tmpl: any, parc: any): boolean { - const testParc = (p: any) => !!(p?.availableIn || []).find((availTmpl: any) => availTmpl['@id'] === tmpl['@id']) - return Array.isArray(parc) - ? parc.some(testParc) - : testParc(parc) - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/getGroupedParc.pipe.ts b/src/atlasComponents/uiSelectors/pipes/getGroupedParc.pipe.ts deleted file mode 100644 index cd98f91a417520f57af7f9ae9952ffd134716a8f..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/getGroupedParc.pipe.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; - -type TReturn = { - [key: string]: any[] -} - -@Pipe({ - name: 'getGroupedParc', - pure: true -}) -export class GetGroupedParcPipe implements PipeTransform{ - - public transform(arr: any[]):TReturn{ - const returnObj: TReturn = {} - const filteredArr = arr.filter(p => p['groupName']) - for (const obj of filteredArr) { - const groupName: string = obj['groupName'] - returnObj[groupName] = (returnObj[groupName] || []).concat(obj) - } - return returnObj - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/getIndividualParc.pipe.ts b/src/atlasComponents/uiSelectors/pipes/getIndividualParc.pipe.ts deleted file mode 100644 index 1e7b155b258819a4490ed41083aa0f55f6051ee4..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/getIndividualParc.pipe.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; - -@Pipe({ - name: 'getIndividualParc', - pure: true -}) -export class GetIndividualParcPipe implements PipeTransform{ - - public transform(arr: any[]){ - return arr.filter(p => !p['groupName']) - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/getNonBaseParc.pipe.ts b/src/atlasComponents/uiSelectors/pipes/getNonBaseParc.pipe.ts deleted file mode 100644 index 71e236bb56d6846458553c4e310e8f48829c60dc..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/getNonBaseParc.pipe.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; -import { SapiParcellationModel } from "src/atlasComponents/sapi"; - -@Pipe({ - name: 'getNonbaseParc', - pure: true -}) -export class GetNonbaseParcPipe implements PipeTransform{ - - public transform(arr: SapiParcellationModel[]){ - if (!arr) return [] - return arr.filter(p => p.name.toLowerCase().indexOf("julich") < 0) - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/getPreviewUrl.pipe.ts b/src/atlasComponents/uiSelectors/pipes/getPreviewUrl.pipe.ts deleted file mode 100644 index 7826f44e267119a0cab9c848f0dd368280629b95..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/getPreviewUrl.pipe.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; -import { GetParcPreviewUrlPipe } from "src/atlasComponents/parcellation"; -import { GetTemplatePreviewUrlPipe } from "src/atlasComponents/template"; - -const templateUrlPipe = new GetTemplatePreviewUrlPipe() -const parcUrlPipe = new GetParcPreviewUrlPipe() - -@Pipe({ - name: 'getPreviewUrlPipe', - pure: true -}) - -export class GetPreviewUrlPipe implements PipeTransform{ - public transform(tile: any){ - const filename = templateUrlPipe.transform(tile) || parcUrlPipe.transform(tile) - return filename - } -} diff --git a/src/atlasComponents/uiSelectors/pipes/groupParcSelected.pipe.ts b/src/atlasComponents/uiSelectors/pipes/groupParcSelected.pipe.ts deleted file mode 100644 index 6beb302be626272f72e62f23b722ce1ce7411015..0000000000000000000000000000000000000000 --- a/src/atlasComponents/uiSelectors/pipes/groupParcSelected.pipe.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Pipe, PipeTransform } from "@angular/core"; - -@Pipe({ - name: 'groupParcSelected', - pure: true -}) - -export class GroupParcSelectedPipe implements PipeTransform{ - public transform(selectedParc: any, parc: any){ - const isSelected = (p: any) => p['@id'] === selectedParc['@id'] - return Array.isArray(parc) - ? parc.some(isSelected) - : isSelected(parc) - } -} diff --git a/src/components/tile/tile.style.css b/src/components/tile/tile.style.css index e877c720820a2a9b6fbf6a0d988fad5b90385054..0fa6bb8a8a8834d9fd378d10f331b9092323337c 100644 --- a/src/components/tile/tile.style.css +++ b/src/components/tile/tile.style.css @@ -17,6 +17,7 @@ img display: block; width: 100%; height: 100%; + max-width: 16rem; } img diff --git a/src/components/tile/tile.template.html b/src/components/tile/tile.template.html index 44cc134d2a135d88ad24d04c1631cb68ed827b5e..d56ad788ba2b1bc0043f19df11f44e51c111f23d 100644 --- a/src/components/tile/tile.template.html +++ b/src/components/tile/tile.template.html @@ -1,7 +1,7 @@ -<div class="position-relative"> +<div class="sxplr-position-relative"> <!-- info icon --> <div *ngIf="tileShowInfo" - class="position-absolute right-0"> + class="sxplr-position-absolute right-0"> <div mat-icon-button iav-stop="click" (click)="onInfoClick.emit($event)" @@ -18,8 +18,12 @@ <!-- directory icon --> - <div *ngIf="isDir" class="position-absolute bottom-0 right-0"> - <i class="fas fa-folder folder-container fa-2x"></i> + <div *ngIf="isDir" class="sxplr-position-absolute bottom-0 right-0" + [ngClass]="{ + 'darktheme': darktheme, + 'lighttheme': !darktheme + }"> + <i class="fas fa-folder folder-container fa-2x iv-custom-comp text"></i> </div> <img [src]="tileImgSrc" @@ -30,6 +34,6 @@ draggable="false"> </div> -<div class="tile-text"> +<div class="tile-text mat-body"> {{ tileText }} </div> diff --git a/src/overwrite.scss b/src/overwrite.scss index 9ffe638d491a2fe839ae59831c4392cdea489f7e..c955e1032ca9a930b2a4def71ffec32131c2abba 100644 --- a/src/overwrite.scss +++ b/src/overwrite.scss @@ -55,13 +55,13 @@ $media-map: ( $overflow-directive: hidden, scroll, auto, visible; @each $directive in $overflow-directive { - .of-x-#{$directive} { + .#{$nsp}-of-x-#{$directive} { overflow-x: $directive } - .of-y-#{$directive} { + .#{$nsp}-of-y-#{$directive} { overflow-y: $directive } - .of-#{$directive} { + .#{$nsp}-of-#{$directive} { overflow: $directive } } @@ -158,6 +158,13 @@ $align-items-vars: center, stretch; } } +$justify-content-vars: end, center, space-between; +@each $justify-content-var in $justify-content-vars { + .#{$nsp}-justify-content-#{$justify-content-var} { + justify-content: $justify-content-var; + } +} + .#{$nsp}-m-a { margin: auto; } @@ -165,3 +172,10 @@ $align-items-vars: center, stretch; .#{$nsp}-muted { opacity: 0.75; } + +$position-vars: relative, absolute; +@each $position-var in $position-vars { + .#{$nsp}-position-#{$position-var} { + position: $position-var; + } +} diff --git a/src/sharedModules/angularMaterial.module.ts b/src/sharedModules/angularMaterial.module.ts index d5384113b07877cc3d0c0a726387c2c38d5e64bf..b2d27d67a09a1ff277802b4318acec9e54281784 100644 --- a/src/sharedModules/angularMaterial.module.ts +++ b/src/sharedModules/angularMaterial.module.ts @@ -28,11 +28,14 @@ import {MatMenuModule} from "@angular/material/menu"; import { MatToolbarModule } from '@angular/material/toolbar' import { ClipboardModule } from '@angular/cdk/clipboard' +import { BrowserAnimationsModule } from "@angular/platform-browser/animations"; const defaultDialogOption: MatDialogConfig = new MatDialogConfig() @NgModule({ imports: [ + BrowserAnimationsModule, + MatButtonModule, MatSnackBarModule, MatCheckboxModule, diff --git a/src/state/atlasSelection/index.ts b/src/state/atlasSelection/index.ts index 603220cde6013640c42cb4f86d9fdeac342b7140..d058f9d5049d3864c10e66aaa0e82f95c2b1d6c5 100644 --- a/src/state/atlasSelection/index.ts +++ b/src/state/atlasSelection/index.ts @@ -1,6 +1,6 @@ export * as selectors from "./selectors" export { fromRootStore } from "./util" export { nameSpace } from "./const" -export { reducer } from "./store" +export { reducer, AtlasSelectionState, defaultState } from "./store" export * as actions from "./actions" export { Effect } from "./effects" \ No newline at end of file diff --git a/src/state/atlasSelection/store.ts b/src/state/atlasSelection/store.ts index 2f1caaf5419913b6991055248a485a316336ec90..f36738bf1febc95b28dc7b6b4dff47377298c28e 100644 --- a/src/state/atlasSelection/store.ts +++ b/src/state/atlasSelection/store.ts @@ -25,7 +25,7 @@ export type AtlasSelectionState = { viewerMode: ViewerMode } -const defaultState: AtlasSelectionState = { +export const defaultState: AtlasSelectionState = { selectedAtlas: null, selectedParcellation: null, selectedRegions: [], diff --git a/src/util/util.module.ts b/src/util/util.module.ts index 87d40da9c9a74170324af8f90061ab0ba21e1ea4..43bfb479f1988fe728d6f6cdf53881e331217041 100644 --- a/src/util/util.module.ts +++ b/src/util/util.module.ts @@ -3,12 +3,9 @@ import { FilterRowsByVisbilityPipe } from "src/components/flatTree/filterRowsByV import { KeyListner } from "./directives/keyDownListener.directive"; import { StopPropagationDirective } from "./directives/stopPropagation.directive"; -import { IncludesPipe } from "./pipes/includes.pipe"; import { SafeResourcePipe } from "./pipes/safeResource.pipe"; import { CaptureClickListenerDirective } from "./directives/captureClickListener.directive"; -import { AddUnitAndJoin } from "./pipes/addUnitAndJoin.pipe"; import { NmToMm } from "./pipes/nmToMm.pipe"; -import { NumbersPipe } from "./pipes/numbers.pipe" import { SwitchDirective } from "./directives/switch.directive"; import { MediaQueryDirective } from './directives/mediaQuery.directive' import { LayoutModule } from "@angular/cdk/layout"; @@ -32,12 +29,9 @@ import { MergeObjPipe } from "./mergeObj.pipe"; FilterRowsByVisbilityPipe, StopPropagationDirective, KeyListner, - IncludesPipe, SafeResourcePipe, CaptureClickListenerDirective, - AddUnitAndJoin, NmToMm, - NumbersPipe, SwitchDirective, MediaQueryDirective, MapToPropertyPipe, @@ -56,12 +50,9 @@ import { MergeObjPipe } from "./mergeObj.pipe"; FilterRowsByVisbilityPipe, StopPropagationDirective, KeyListner, - IncludesPipe, SafeResourcePipe, CaptureClickListenerDirective, - AddUnitAndJoin, NmToMm, - NumbersPipe, SwitchDirective, MediaQueryDirective, MapToPropertyPipe, diff --git a/src/viewerModule/module.ts b/src/viewerModule/module.ts index 1656efc6e608f235822cba5d0012aad8fd5a78cb..58cc6ae77a0925a0e2eb4f25de82b114b0fc93bd 100644 --- a/src/viewerModule/module.ts +++ b/src/viewerModule/module.ts @@ -4,7 +4,6 @@ import { Observable } from "rxjs"; import { AtlasCmpParcellationModule } from "src/atlasComponents/parcellation"; import { ParcellationRegionModule } from "src/atlasComponents/parcellationRegion"; import { SplashUiModule } from "src/atlasComponents/splashScreen"; -import { AtlasCmpUiSelectorsModule } from "src/atlasComponents/uiSelectors"; import { ComponentsModule } from "src/components"; import { ContextMenuModule, ContextMenuService, TContextMenuReg } from "src/contextMenuModule"; import { LayoutModule } from "src/layouts/layout.module"; @@ -28,7 +27,7 @@ import { ViewerInternalStateSvc } from "./viewerInternalState.service"; import { LayerBrowserModule } from "src/ui/layerbrowser"; import { SAPIModule } from 'src/atlasComponents/sapi'; import { NehubaVCtxToBbox } from "./pipes/nehubaVCtxToBbox.pipe"; -import { SapiViewsModule } from "src/atlasComponents/sapiViews"; +import { SapiViewsModule, SapiViewsUtilModule } from "src/atlasComponents/sapiViews"; @NgModule({ imports: [ @@ -36,7 +35,6 @@ import { SapiViewsModule } from "src/atlasComponents/sapiViews"; NehubaModule, ThreeSurferModule, LayoutModule, - AtlasCmpUiSelectorsModule, AngularMaterialModule, SplashUiModule, TopMenuModule, @@ -52,6 +50,7 @@ import { SapiViewsModule } from "src/atlasComponents/sapiViews"; LayerBrowserModule, SAPIModule, SapiViewsModule, + SapiViewsUtilModule ], declarations: [ ViewerCmp, diff --git a/src/viewerModule/viewerCmp/viewerCmp.component.ts b/src/viewerModule/viewerCmp/viewerCmp.component.ts index 39a38881fe0e2629f58a2218f995bc24e1730331..edbdcda41e63f4a5756bb282a26bf78ea1e769c8 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.component.ts +++ b/src/viewerModule/viewerCmp/viewerCmp.component.ts @@ -13,7 +13,7 @@ import { DialogService } from "src/services/dialogService.service"; import { SAPI, SapiRegionModel } from "src/atlasComponents/sapi"; import { actions } from "src/state/atlasSelection"; import { atlasSelection, userInteraction } from "src/state"; -import { SapiSpatialFeatureModel, SapiRegionalFeatureModel, SapiFeatureModel } from "src/atlasComponents/sapi/type"; +import { SapiSpatialFeatureModel, SapiFeatureModel } from "src/atlasComponents/sapi/type"; type TCStoreViewerCmp = { overlaySideNav: any diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html index 2acce6eae5cbe909596794f7db01afeb81b55a30..dc657df1215eec9b072fa721953536a497a432c6 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.template.html +++ b/src/viewerModule/viewerCmp/viewerCmp.template.html @@ -331,12 +331,12 @@ [viewerLoaded]="viewerLoaded"> </top-menu-cmp> - <atlas-dropdown-selector + <sxplr-sapiviews-core-atlas-dropdown-selector class="v-align-top sxplr-pt-2 pe-all mt-2 iv-custom-comp bg card m-2 mat-elevation-z2 d-inline-block" quick-tour [quick-tour-description]="quickTourAtlasSelector.description" [quick-tour-order]="quickTourAtlasSelector.order"> - </atlas-dropdown-selector> + </sxplr-sapiviews-core-atlas-dropdown-selector> </ng-template> @@ -359,11 +359,14 @@ <ng-template #bottomLeftTmpl let-showFullSideNav="showFullSideNav"> <!-- atlas selector --> - <atlas-layer-selector *ngIf="viewerLoaded && !(isStandaloneVolumes$ | async)" + <sxplr-sapiviews-core-atlas-tmplparcselector *ngIf="viewerLoaded && !(isStandaloneVolumes$ | async)"> + </sxplr-sapiviews-core-atlas-tmplparcselector> + + <!-- <atlas-layer-selector *ngIf="viewerLoaded && !(isStandaloneVolumes$ | async)" #alSelector="atlasLayerSelector" class="d-inline-block flex-grow-0 flex-shrink-0 pe-all" (iav-outsideClick)="alSelector.selectorExpanded = false"> - </atlas-layer-selector> + </atlas-layer-selector> --> <!-- chips --> <div *ngIf="parcellationSelected$ | async" @@ -591,14 +594,15 @@ <!-- single region tmpl --> <ng-template #singleRegionTmpl let-region="region"> <!-- region detail --> - <region-menu - [region-base-atlas]="selectedAtlas$ | async" - [region-base-template]="templateSelected$ | async" - [region-base-parcellation]="parcellationSelected$ | async" - [region-base-region]="region" - (region-menu-feat-clicked)="showDataset($event)" - class="flex-grow-1 bs-border-box mat-elevation-z4"> - </region-menu> + <sxplr-sapiviews-core-region-region-rich + [sxplr-sapiviews-core-region-atlas]="selectedAtlas$ | async" + [sxplr-sapiviews-core-region-template]="templateSelected$ | async" + [sxplr-sapiviews-core-region-parcellation]="parcellationSelected$ | async" + [sxplr-sapiviews-core-region-region]="region" + (sxplr-sapiviews-core-region-region-rich-feature-clicked)="showDataset($event)" + > + <div class="sapi-container" header></div> + </sxplr-sapiviews-core-region-region-rich> </ng-template> @@ -652,10 +656,11 @@ <!-- multi region tmpl --> <ng-template #multiRegionTmpl let-regions="regions"> <ng-template [ngIf]="regions.length > 0" [ngIfElse]="regionPlaceholderTmpl"> - <region-menu + <!-- <region-menu [region-base-region]="{ name: CONST.MULTI_REGION_SELECTION }" class="bs-border-box ml-15px-n mr-15px-n mat-elevation-z4"> - </region-menu> + </region-menu> --> + MULTI_REGION_SELECTION <!-- other regions detail accordion --> <mat-accordion class="bs-border-box ml-15px-n mr-15px-n mt-2">