From 813026c03e50a76571dca18b8bedb6e2d1cac918 Mon Sep 17 00:00:00 2001 From: Michael Hartung <hartungmichael@outlook.com> Date: Wed, 7 Apr 2021 13:10:34 +0200 Subject: [PATCH] default legend --- src/app/analysis.service.ts | 6 +- src/app/app.module.ts | 2 + .../network-legend.component.html | 32 + .../network-legend.component.scss | 47 ++ .../network-legend.component.spec.ts | 25 + .../network-legend.component.ts | 18 + src/app/config.ts | 40 +- .../explorer-page.component.html | 626 +++++++++--------- .../explorer-page/explorer-page.component.ts | 10 +- src/index.html | 20 +- src/styles.scss | 20 +- src/variables.scss | 15 + 12 files changed, 528 insertions(+), 333 deletions(-) create mode 100644 src/app/components/network-legend/network-legend.component.html create mode 100644 src/app/components/network-legend/network-legend.component.scss create mode 100644 src/app/components/network-legend/network-legend.component.spec.ts create mode 100644 src/app/components/network-legend/network-legend.component.ts create mode 100644 src/variables.scss diff --git a/src/app/analysis.service.ts b/src/app/analysis.service.ts index 3e679780..d3857e01 100644 --- a/src/app/analysis.service.ts +++ b/src/app/analysis.service.ts @@ -68,7 +68,7 @@ export class AnalysisService { if (finishedTokens) { this.finishedTokens = JSON.parse(finishedTokens); } - this.startWatching(); + // this.startWatching(); this.http.get<Tissue[]>(`${environment.backend}tissues/`).subscribe((tissues) => { this.tissues = tissues; @@ -269,7 +269,7 @@ export class AnalysisService { }).toPromise(); this.tokens.push(resp.token); localStorage.setItem('tokens', JSON.stringify(this.tokens)); - this.startWatching(); + // this.startWatching(); toast({ message: 'Quick analysis started. This may take a while.' + @@ -304,7 +304,7 @@ export class AnalysisService { }).toPromise(); this.tokens.push(resp.token); localStorage.setItem('tokens', JSON.stringify(this.tokens)); - this.startWatching(); + // this.startWatching(); } public isLaunchingQuick(): boolean { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 5b501dc5..d5fb3674 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -21,6 +21,7 @@ import {CustomProteinsComponent} from './dialogs/custom-proteins/custom-proteins import {AnalysisService} from './analysis.service'; import { AddExpressedProteinsComponent } from './dialogs/add-expressed-proteins/add-expressed-proteins.component'; import {createCustomElement} from '@angular/elements'; +import { NetworkLegendComponent } from './components/network-legend/network-legend.component'; @NgModule({ @@ -36,6 +37,7 @@ import {createCustomElement} from '@angular/elements'; InfoTileComponent, CustomProteinsComponent, AddExpressedProteinsComponent, + NetworkLegendComponent, ], imports: [ BrowserModule, diff --git a/src/app/components/network-legend/network-legend.component.html b/src/app/components/network-legend/network-legend.component.html new file mode 100644 index 00000000..c568d40b --- /dev/null +++ b/src/app/components/network-legend/network-legend.component.html @@ -0,0 +1,32 @@ +<div class="legend" [class.right]="this.config.legendPos === 'right'"> + + <!-- default legend in html --> + <table *ngIf="!this.config.legendUrl.length"> + <ng-container *ngIf="this.config.showLegendNodes"> + <tr *ngFor="let nodeGroup of this.config.nodeGroups | keyvalue" class="list-item"> + <td *ngIf="nodeGroup.value.shape !== 'triangle'"> + <span class="node {{ nodeGroup.value.shape }}" [style.background-color]=nodeGroup.value.color> + </span> + </td> + <td *ngIf="nodeGroup.value.shape === 'triangle'"> + <span class="node {{ nodeGroup.value.shape }}" [style.border-bottom-color]=nodeGroup.value.color> + </span> + </td> + <td> {{ nodeGroup.value.name }}</td> + </tr> + </ng-container> + + <ng-container *ngIf="this.config.showLegendEdges"> + <tr *ngFor="let edgeGroup of this.config.edgeGroups | keyvalue" class="list-item"> + <td> + <hr class="edge" [style.background-color]=edgeGroup.value.color > + </td> + <td> {{ edgeGroup.value.name }}</td> + </tr> + </ng-container> + </table> + + + <!-- custom legend image if url given by user --> + <img *ngIf="this.config.legendUrl.length" [src]="this.config.legendUrl" [ngClass]="this.config.legendClass"/> +</div> diff --git a/src/app/components/network-legend/network-legend.component.scss b/src/app/components/network-legend/network-legend.component.scss new file mode 100644 index 00000000..aca175ad --- /dev/null +++ b/src/app/components/network-legend/network-legend.component.scss @@ -0,0 +1,47 @@ +@import "~src/variables"; + +div.legend { + position: absolute; + bottom: $network-footer-height; + &.right { + right: 0; + } + tr.list-item{ + padding: 0; + height: 40px; + td{ + height: $legend-circle-size; + vertical-align: middle !important; + padding: 0 !important; + .round{ + background: $legend-default-background-color; + border-radius: 50%; + width: $legend-circle-size; + height: $legend-circle-size; + display: inline-block; + } + .triangle{ + width: 0; + height: 0; + border-left: calc(#{$legend-circle-size} / 2) solid transparent; + border-right: calc(#{$legend-circle-size} / 2) solid transparent; + border-bottom: $legend-circle-size solid black; + display: inline-block; + } + .rectangle{ + background: $legend-default-background-color; + border-radius: $legend-rectangle-radius; + width: $legend-rectangle-width; + height: $legend-rectangle-height; + margin-bottom: calc((#{$legend-rectangle-height} - #{$legend-rectangle-width}) / 2); + display: inline-block; + } + .edge{ + width: $legend-edge-width; + height: $legend-edge-height; + } + } + + } +} + diff --git a/src/app/components/network-legend/network-legend.component.spec.ts b/src/app/components/network-legend/network-legend.component.spec.ts new file mode 100644 index 00000000..adddf86c --- /dev/null +++ b/src/app/components/network-legend/network-legend.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { NetworkLegendComponent } from './network-legend.component'; + +describe('NetworkLegendComponent', () => { + let component: NetworkLegendComponent; + let fixture: ComponentFixture<NetworkLegendComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ NetworkLegendComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(NetworkLegendComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/components/network-legend/network-legend.component.ts b/src/app/components/network-legend/network-legend.component.ts new file mode 100644 index 00000000..b3e9079a --- /dev/null +++ b/src/app/components/network-legend/network-legend.component.ts @@ -0,0 +1,18 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {IConfig} from '../../config'; + +@Component({ + selector: 'app-network-legend', + templateUrl: './network-legend.component.html', + styleUrls: ['./network-legend.component.scss'] +}) +export class NetworkLegendComponent implements OnInit { + + @Input() config: IConfig; + + constructor() { } + + ngOnInit(): void { + } + +} diff --git a/src/app/config.ts b/src/app/config.ts index 6495a82b..1f7354d7 100644 --- a/src/app/config.ts +++ b/src/app/config.ts @@ -6,12 +6,22 @@ // color: string; // } -type NodeGroup = any; -type EdgeGroup = any; +export interface NodeGroup { + name: string; + color: string; + shape: 'round' | 'triangle' | 'rectangle'; + type: 'gene' | 'protein' | 'drug'; +} + +export interface EdgeGroup { + name: string; + color: string; +} export interface IConfig { legendUrl: string; legendClass: string; + legendPos: 'left' | 'right'; taskName: string; showLeftSidebar: boolean; showOverview: boolean; @@ -22,14 +32,21 @@ export interface IConfig { showTasks: boolean; showSelection: boolean; showFooter: boolean; + showLegend: boolean; + showLegendNodes: boolean; + showLegendEdges: boolean; nodeGroups: { [key: string]: NodeGroup }; edgeGroups: { [key: string]: EdgeGroup }; + } export const defaultConfig: IConfig = { - legendUrl: 'https://exbio.wzw.tum.de/covex/assets/leg1.png', + legendUrl: '', // 'https://exbio.wzw.tum.de/covex/assets/leg1.png' show legend image if set, otherwise default legend legendClass: 'legend', + legendPos: 'left', taskName: 'Run Task X', + showLegendNodes: true, + showLegendEdges: true, showLeftSidebar: true, showOverview: true, showQuery: true, @@ -39,19 +56,30 @@ export const defaultConfig: IConfig = { showSelection: true, showTasks: true, showFooter: true, + showLegend: true, nodeGroups: { default: { - color: 'white' + name: 'Default Group', + color: 'yellow', + shape: 'triangle', + type: 'gene', }, protein: { - color: 'red' + name: 'Resulting Proteins', + color: 'red', + shape: 'round', + type: 'protein', }, drug: { - color: 'green' + name: 'Possible Drugs', + color: 'green', + shape: 'rectangle', + type: 'drug', } }, edgeGroups: { default: { + name: 'Edgy edges', color: 'black' } }, diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index ba67fd35..3f14d75e 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -12,509 +12,523 @@ [currentViewProteins]="currentViewProteins"> </app-add-expressed-proteins> + <!-- Start explorer --> <div class="covex explorer"> - <div class="covex left-window"> - <div> - <div class="covex sidebar bar-left"> + <!-- Start left window --> + <div class="covex left-window"> + <div> - <div *ngIf="myConfig.showOverview" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> - <span class="icon"> - <i class="fas fa-info" aria-hidden="true"></i> - </span> Network Overview - </p> - <a (click)="collapseOverview= !collapseOverview" data-action="collapse" - class="card-header-icon is-hidden-fullscreen" aria-label="more options"> + <!-- Start left sidebar --> + <div class="covex sidebar bar-left"> + + <div *ngIf="myConfig.showOverview" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> + <span class="icon"> + <i class="fas fa-info" aria-hidden="true"></i> + </span> Network Overview + </p> + <a (click)="collapseOverview= !collapseOverview" data-action="collapse" + class="card-header-icon is-hidden-fullscreen" aria-label="more options"> <span class="icon"> <i *ngIf="collapseOverview" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseOverview" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseOverview"> - <div class="card-content"> - <nav class="level" *ngIf="proteinData"> + </a> + </header> + <div *ngIf="collapseOverview"> + <div class="card-content"> + <nav class="level" *ngIf="proteinData"> - <!-- TO DO : CHANGE THIS LATER - <div class="level-item has-text-centered"> - <div> - <p class="heading">Viral<br>Proteins</p> - <p class="title"> {{ proteinData.effects.length }}</p> + <!-- TO DO : CHANGE THIS LATER + <div class="level-item has-text-centered"> + <div> + <p class="heading">Viral<br>Proteins</p> + <p class="title"> {{ proteinData.effects.length }}</p> + </div> </div> - </div> - --> + --> - <div class="level-item has-text-centered"> - <div> - <p class="heading">Proteins</p> - <p class="title">{{ proteinData.proteins.length }}</p> + <div class="level-item has-text-centered"> + <div> + <p class="heading">Proteins</p> + <p class="title">{{ proteinData.proteins.length }}</p> + </div> </div> - </div> - <div class="level-item has-text-centered"> - <div> - <p class="heading">Interactions</p> - <p class="title">{{ proteinData.edges.length }}</p> + <div class="level-item has-text-centered"> + <div> + <p class="heading">Interactions</p> + <p class="title">{{ proteinData.edges.length }}</p> + </div> </div> - </div> - </nav> + </nav> + </div> </div> </div> - </div> - <div *ngIf="myConfig.showQuery" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> - <span class="icon"> - <i class="fas fa-search" aria-hidden="true"></i> - </span> Query Protein/Gene - </p> - <a (click)="collapseQuery = !collapseQuery" data-action="collapse" - class="card-header-icon is-hidden-fullscreen" aria-label="more options"> + <div *ngIf="myConfig.showQuery" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> + <span class="icon"> + <i class="fas fa-search" aria-hidden="true"></i> + </span> Query Protein/Gene + </p> + <a (click)="collapseQuery = !collapseQuery" data-action="collapse" + class="card-header-icon is-hidden-fullscreen" aria-label="more options"> <span class="icon"> <i *ngIf="collapseQuery" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseQuery" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseQuery"> - <div class="card-content"> - <div class="field"> - <div class="control"> - <app-query-tile-component (selectItem)="queryAction($event)" - [queryItems]="queryItems"></app-query-tile-component> + </a> + </header> + <div *ngIf="collapseQuery"> + <div class="card-content"> + <div class="field"> + <div class="control"> + <app-query-tile-component (selectItem)="queryAction($event)" + [queryItems]="queryItems"></app-query-tile-component> + </div> </div> </div> </div> </div> </div> - </div> - <div class="covex network"> - <div class="card network"> - <header class="card-header"> - <p class="card-header-title"> - Protein-Protein Interaction Network - </p> - </header> - <div class="card-content"> - <div class="card-image" id="canvas-content"> - <div class="parent"> - <div class="network center image1" #network> - <button class="button is-loading center" alt="loading...">Loading</button> + <!-- Start network block --> + <div class="covex network"> + <div class="card network"> + + <div *ngIf="myConfig.showLegend"> + <app-network-legend [config]="myConfig"></app-network-legend> + </div> + + + <header class="card-header"> + <p class="card-header-title"> + Protein-Protein Interaction Network + </p> + </header> + <div class="card-content"> + <div class="card-image" id="canvas-content"> + <div class="parent"> + <div class="network center image1" #network> + <button class="button is-loading center" alt="loading...">Loading</button> + </div> </div> - <img class="image2" [src]="myConfig.legendUrl" [ngClass]="myConfig.legendClass"/> </div> - </div> - <footer *ngIf="myConfig.showFooter" class="card-footer toolbar"> - <button (click)="toCanvas()" class="button is-primary is-rounded has-tooltip" - data-tooltip="Take a screenshot of the current network."> + <footer *ngIf="myConfig.showFooter" class="card-footer toolbar"> + <button (click)="toCanvas()" class="button is-primary is-rounded has-tooltip" + data-tooltip="Take a screenshot of the current network."> <span class="icon"> <i class="fas fa-camera" aria-hidden="true"></i> </span> <span>Screenshot</span> - </button> + </button> - <div class="footer-buttons dropdown is-up" [class.is-active]="expressionExpanded"> - <div class="dropdown-trigger"> - <button (click)="expressionExpanded=!expressionExpanded" - class="button is-rounded is-primary" [class.is-outlined]="!selectedTissue" - aria-haspopup="true" aria-controls="dropdown-menu" - data-tooltip="Tissue expression data is provided by the GTEx project."> - <span *ngIf="!selectedTissue">Tissue</span> - <span *ngIf="selectedTissue">{{selectedTissue.name}}</span> - <span class="icon is-small"> + <div class="footer-buttons dropdown is-up" [class.is-active]="expressionExpanded"> + <div class="dropdown-trigger"> + <button (click)="expressionExpanded=!expressionExpanded" + class="button is-rounded is-primary" [class.is-outlined]="!selectedTissue" + aria-haspopup="true" aria-controls="dropdown-menu" + data-tooltip="Tissue expression data is provided by the GTEx project."> + <span *ngIf="!selectedTissue">Tissue</span> + <span *ngIf="selectedTissue">{{selectedTissue.name}}</span> + <span class="icon is-small"> <i class="fas" [class.fa-angle-up]="expressionExpanded" [class.fa-angle-left]="!expressionExpanded" aria-hidden="true"></i> </span> - </button> - </div> - <div class="dropdown-menu" id="dropdown-menu" role="menu"> - <div class="dropdown-content tissue-dropdown"> - <div class="scroll-area"> - <a (click)="selectTissue(null)" - [class.is-active]="!selectedTissue" - class="dropdown-item"> - None - </a> - <a *ngFor="let tissue of analysis.getTissues()" - (click)="selectTissue(tissue)" - [class.is-active]="selectedTissue && tissue.id === selectedTissue.id" - class="dropdown-item"> - {{tissue.name}} - </a> + </button> + </div> + <div class="dropdown-menu" id="dropdown-menu" role="menu"> + <div class="dropdown-content tissue-dropdown"> + <div class="scroll-area"> + <a (click)="selectTissue(null)" + [class.is-active]="!selectedTissue" + class="dropdown-item"> + None + </a> + <a *ngFor="let tissue of analysis.getTissues()" + (click)="selectTissue(tissue)" + [class.is-active]="selectedTissue && tissue.id === selectedTissue.id" + class="dropdown-item"> + {{tissue.name}} + </a> + </div> </div> </div> </div> - </div> - <app-toggle class="footer-buttons" textOn="Animation On" textOff="Off" - tooltipOn="Enable the network animation." tooltipOff="Disable the network animation and freeze nodes." - [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)"></app-toggle> - </footer> + <app-toggle class="footer-buttons" textOn="Animation On" textOff="Off" + tooltipOn="Enable the network animation." + tooltipOff="Disable the network animation and freeze nodes." + [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)"></app-toggle> + </footer> + </div> </div> </div> + + <!-- End network block --> </div> - </div> - <div class="analysis-view" *ngIf="selectedAnalysisToken"> - <app-analysis-panel [(token)]="selectedAnalysisToken" - (showDetailsChange)="selectedWrapper = $event" - (visibleItems)="analysisWindowChanged($event)"></app-analysis-panel> + <div class="analysis-view" *ngIf="selectedAnalysisToken"> + <app-analysis-panel [(token)]="selectedAnalysisToken" + (showDetailsChange)="selectedWrapper = $event" + (visibleItems)="analysisWindowChanged($event)"></app-analysis-panel> + </div> </div> - </div> - <div *ngIf="myConfig.showLeftSidebar" class="covex sidebar bar-right"> - <div *ngIf="myConfig.showItemSelector" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> + <div *ngIf="myConfig.showLeftSidebar" class="covex sidebar bar-right"> + <div *ngIf="myConfig.showItemSelector" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> <span class="icon"> <i *ngIf="!selectedWrapper" class="fas fa-info" aria-hidden="true"></i> <i *ngIf="selectedWrapper && selectedWrapper.type === 'protein'" class="fas fa-dna" aria-hidden="true"></i> <i *ngIf="selectedWrapper && selectedWrapper.type === 'drug'" class="fas fa-capsules" aria-hidden="true"></i> </span> - <span *ngIf="!selectedWrapper">No item selected</span> - <span *ngIf="selectedWrapper"> + <span *ngIf="!selectedWrapper">No item selected</span> + <span *ngIf="selectedWrapper"> <span *ngIf="selectedWrapper.type === 'protein'">Host Protein</span> <span *ngIf="selectedWrapper.type === 'drug'">Drug</span> </span> - </p> - <a (click)="collapseDetails = !collapseDetails" data-action="collapse" - class="card-header-icon is-hidden-fullscreen" aria-label="more options"> + </p> + <a (click)="collapseDetails = !collapseDetails" data-action="collapse" + class="card-header-icon is-hidden-fullscreen" aria-label="more options"> <span class="icon"> <i *ngIf="collapseDetails" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseDetails" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseDetails"> - <div class="card-content"> - <app-info-tile [wrapper]="selectedWrapper"></app-info-tile> + </a> + </header> + <div *ngIf="collapseDetails"> + <div class="card-content"> + <app-info-tile [wrapper]="selectedWrapper"></app-info-tile> + </div> </div> </div> - </div> - <div *ngIf="myConfig.showSimpleAnalysis" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> + <div *ngIf="myConfig.showSimpleAnalysis" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> <span class="icon"> <i class="fas fa-flask" aria-hidden="true"></i> </span> - Simple Analysis - </p> - <a (click)="collapseAnalysisQuick = !collapseAnalysisQuick" data-action="collapse" - class="card-header-icon is-hidden-fullscreen" aria-label="more options"> + Simple Analysis + </p> + <a (click)="collapseAnalysisQuick = !collapseAnalysisQuick" data-action="collapse" + class="card-header-icon is-hidden-fullscreen" aria-label="more options"> <span class="icon"> <i *ngIf="collapseAnalysisQuick" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseAnalysisQuick" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseAnalysisQuick"> - <div class="card-content quick-find"> - <div class="field"> - <div class="control"> - <div class="tile notification is-danger"> - <div class="align-vmiddle"> - <div class="digit"><i class="fa fa-fast-forward"></i></div> - <button (click)="analysis.startQuickAnalysis(true, null)" - [disabled]="analysis.isLaunchingQuick()" - class="button is-white is-rounded has-tooltip" data-tooltip="Find drugs for all proteins."> + </a> + </header> + <div *ngIf="collapseAnalysisQuick"> + <div class="card-content quick-find"> + <div class="field"> + <div class="control"> + <div class="tile notification is-danger"> + <div class="align-vmiddle"> + <div class="digit"><i class="fa fa-fast-forward"></i></div> + <button (click)="analysis.startQuickAnalysis(true, null)" + [disabled]="analysis.isLaunchingQuick()" + class="button is-white is-rounded has-tooltip" data-tooltip="Find drugs for all proteins."> <span class="icon"> <i class="fa fa-capsules" *ngIf="!analysis.isLaunchingQuick()"></i> <i class="fa fa-spin fa-spinner" *ngIf="analysis.isLaunchingQuick()"></i> </span> - <span> + <span> Quick Start </span> - </button> + </button> + </div> </div> - </div> - <div class="divisor-rapid"> - — or — - </div> - <div class="tile notification is-info"> - <div class="align-vmiddle"> - <div class="digit" *ngIf="analysis.getCount() == 0">1</div> - <div class="digit" *ngIf="analysis.getCount() > 0"><i class="fa fa-check"></i></div> - <div> - <span>Select Proteins</span> + <div class="divisor-rapid"> + — or — + </div> + <div class="tile notification is-info"> + <div class="align-vmiddle"> + <div class="digit" *ngIf="analysis.getCount() == 0">1</div> + <div class="digit" *ngIf="analysis.getCount() > 0"><i class="fa fa-check"></i></div> + <div> + <span>Select Proteins</span> + </div> </div> </div> - </div> - <div class="tile notification is-info"> - <div class="align-vmiddle"> - <div class="digit">2</div> - <button (click)="analysis.startQuickAnalysis(false, null)" - [disabled]="analysis.getCount() === 0 || analysis.isLaunchingQuick()" - class="button is-white is-rounded has-tooltip" - data-tooltip="Find drugs for the selected proteins."> + <div class="tile notification is-info"> + <div class="align-vmiddle"> + <div class="digit">2</div> + <button (click)="analysis.startQuickAnalysis(false, null)" + [disabled]="analysis.getCount() === 0 || analysis.isLaunchingQuick()" + class="button is-white is-rounded has-tooltip" + data-tooltip="Find drugs for the selected proteins."> <span class="icon"> <i class="fa fa-capsules" *ngIf="!analysis.isLaunchingQuick()"></i> <i class="fa fa-spin fa-spinner" *ngIf="analysis.isLaunchingQuick()"></i> </span> - <span> + <span> {{ myConfig.taskName }} </span> - </button> + </button> + </div> </div> </div> </div> </div> </div> </div> - </div> - <div *ngIf="myConfig.showAdvAnalysis" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> + <div *ngIf="myConfig.showAdvAnalysis" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> <span class="icon"> <i class="fas fa-flask" aria-hidden="true"></i> </span> - Analysis - </p> - <a (click)="collapseAnalysis = !collapseAnalysis" data-action="collapse" - class="card-header-icon is-hidden-fullscreen" aria-label="more options"> + Analysis + </p> + <a (click)="collapseAnalysis = !collapseAnalysis" data-action="collapse" + class="card-header-icon is-hidden-fullscreen" aria-label="more options"> <span class="icon"> <i *ngIf="collapseAnalysis" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseAnalysis" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseAnalysis"> - <div class="card-content"> - <div class="field"> - <div class="control"> - <button (click)="analysisDialogTarget = 'drug-target'; showAnalysisDialog = true;" - class="button is-primary is-fullwidth is-rounded has-tooltip" - data-tooltip="Find drug targets for the selected proteins." - [disabled]="analysis.getCount() === 0"> + </a> + </header> + <div *ngIf="collapseAnalysis"> + <div class="card-content"> + <div class="field"> + <div class="control"> + <button (click)="analysisDialogTarget = 'drug-target'; showAnalysisDialog = true;" + class="button is-primary is-fullwidth is-rounded has-tooltip" + data-tooltip="Find drug targets for the selected proteins." + [disabled]="analysis.getCount() === 0"> <span class="icon"> <i class="fa fa-crosshairs"></i> </span> - <span> + <span> Find Drug Targets </span> - </button> + </button> + </div> </div> - </div> - <div class="field"> - <div class="control"> - <button (click)="analysisDialogTarget = 'drug'; showAnalysisDialog = true;" - class="button is-primary is-fullwidth is-rounded has-tooltip" - data-tooltip="Find drugs for the selected proteins." - [disabled]="analysis.getCount() === 0"> + <div class="field"> + <div class="control"> + <button (click)="analysisDialogTarget = 'drug'; showAnalysisDialog = true;" + class="button is-primary is-fullwidth is-rounded has-tooltip" + data-tooltip="Find drugs for the selected proteins." + [disabled]="analysis.getCount() === 0"> <span class="icon"> <i class="fa fa-capsules"></i> </span> - <span> + <span> {{myConfig.taskName}} </span> - </button> + </button> + </div> </div> - </div> - <div class="field"> - <div class="control"> - <a *ngIf="analysis.getCount() > 0" [href]="gProfilerLink()" target="_blank" - class="button is-primary is-fullwidth is-rounded has-tooltip" - data-tooltip="Use enrichment analysis via g:Profiler (external)."> + <div class="field"> + <div class="control"> + <a *ngIf="analysis.getCount() > 0" [href]="gProfilerLink()" target="_blank" + class="button is-primary is-fullwidth is-rounded has-tooltip" + data-tooltip="Use enrichment analysis via g:Profiler (external)."> <span class="icon"> <i class="fa fa-external-link-alt"></i> </span> - <span> + <span> Enrichment Analysis </span> - </a> - <a *ngIf="analysis.getCount() === 0" disabled - class="button is-primary is-fullwidth is-rounded has-tooltip" - data-tooltip="Use enrichment analysis via g:Profiler (external)."> + </a> + <a *ngIf="analysis.getCount() === 0" disabled + class="button is-primary is-fullwidth is-rounded has-tooltip" + data-tooltip="Use enrichment analysis via g:Profiler (external)."> <span class="icon"> <i class="fa fa-external-link-alt"></i> </span> - <span> + <span> Enrichment Analysis </span> - </a> + </a> + </div> </div> </div> </div> </div> - </div> - <div *ngIf="myConfig.showTasks" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> + <div *ngIf="myConfig.showTasks" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> <span class="icon"> <i class="fas fa-tasks" aria-hidden="true"></i> </span> - Tasks ({{analysis.tasks.length}}) - </p> - <a (click)="collapseTask = !collapseTask" data-action="collapse" class="card-header-icon is-hidden-fullscreen" - aria-label="more options"> + Tasks ({{analysis.tasks.length}}) + </p> + <a (click)="collapseTask = !collapseTask" data-action="collapse" class="card-header-icon is-hidden-fullscreen" + aria-label="more options"> <span class="icon"> <i *ngIf="collapseTask" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseTask" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseTask"> - <div class="card-content overflow" *ngIf="analysis.tasks && analysis.tasks.length > 0"> - <app-task-list [(token)]="selectedAnalysisToken"></app-task-list> - </div> - <footer class="card-footer"> - <a *ngIf="analysis.tasks && analysis.tasks.length > 0" (click)="analysis.removeAllTasks(); selectedAnalysisToken = null;" - class="card-footer-item has-text-danger" data-tooltip="Delete all tasks."> + </a> + </header> + <div *ngIf="collapseTask"> + <div class="card-content overflow" *ngIf="analysis.tasks && analysis.tasks.length > 0"> + <app-task-list [(token)]="selectedAnalysisToken"></app-task-list> + </div> + <footer class="card-footer"> + <a *ngIf="analysis.tasks && analysis.tasks.length > 0" + (click)="analysis.removeAllTasks(); selectedAnalysisToken = null;" + class="card-footer-item has-text-danger" data-tooltip="Delete all tasks."> <span class="icon"> <i class="fa fa-trash"></i> </span> - <span> + <span> Delete all </span> - </a> - </footer> + </a> + </footer> + </div> </div> - </div> - <div *ngIf="myConfig.showSelection" class="card bar-large"> - <header class="card-header"> - <p class="card-header-title"> + <div *ngIf="myConfig.showSelection" class="card bar-large"> + <header class="card-header"> + <p class="card-header-title"> <span class="icon"> <i class="fas fa-filter" aria-hidden="true"></i> </span> Selection ({{analysis.getCount()}}) - </p> - <a (click)="collapseSelection = !collapseSelection" data-action="collapse" - class="card-header-icon is-hidden-fullscreen" aria-label="more options"> + </p> + <a (click)="collapseSelection = !collapseSelection" data-action="collapse" + class="card-header-icon is-hidden-fullscreen" aria-label="more options"> <span class="icon"> <i *ngIf="collapseSelection" class="fas fa-angle-down" aria-hidden="true"></i> <i *ngIf="!collapseSelection" class="fas fa-angle-left" aria-hidden="true"></i> </span> - </a> - </header> - <div *ngIf="collapseSelection" class="seed-selection"> - <div class="card-content overflow"> - <table class="table selection-table" *ngIf="analysis.getCount() > 0"> - <thead> - <tr> - <td>Type</td> - <td>Name</td> - <td>Actions</td> - </tr> - </thead> - <tbody> - <tr *ngFor="let p of analysis.getSelection()"> - <td> + </a> + </header> + <div *ngIf="collapseSelection" class="seed-selection"> + <div class="card-content overflow"> + <table class="table selection-table" *ngIf="analysis.getCount() > 0"> + <thead> + <tr> + <td>Type</td> + <td>Name</td> + <td>Actions</td> + </tr> + </thead> + <tbody> + <tr *ngFor="let p of analysis.getSelection()"> + <td> <span class="icon"> <i class="fa fa-dna" *ngIf="p.type == 'protein'"></i> </span> - </td> - <td *ngIf="p.type == 'protein'">{{p.data.name}}</td> - <td> - <button (click)="analysis.removeItems([p])" class="button is-small is-danger is-outlined has-tooltip" - data-tooltip="Remove from selection."> - <i class="fa fa-trash"></i> - </button> - </td> - </tr> - </tbody> - </table> - <i *ngIf="analysis.getCount() === 0"> - Double-click on a protein to select it for the analysis. - </i> - </div> + </td> + <td *ngIf="p.type == 'protein'">{{p.data.name}}</td> + <td> + <button (click)="analysis.removeItems([p])" class="button is-small is-danger is-outlined has-tooltip" + data-tooltip="Remove from selection."> + <i class="fa fa-trash"></i> + </button> + </td> + </tr> + </tbody> + </table> + <i *ngIf="analysis.getCount() === 0"> + Double-click on a protein to select it for the analysis. + </i> + </div> - <footer class="card-footer"> - <a (click)="analysis.addVisibleHostProteins(currentViewNodes, currentViewProteins)" - class="card-footer-item has-text-success" data-tooltip="Add all visible proteins."> + <footer class="card-footer"> + <a (click)="analysis.addVisibleHostProteins(currentViewNodes, currentViewProteins)" + class="card-footer-item has-text-success" data-tooltip="Add all visible proteins."> <span class="icon"> <i class="fa fa-plus"></i> </span> - <span> + <span> Add proteins </span> - </a> - <a (click)="analysis.removeAllHostProteins()" - class="card-footer-item has-text-danger" data-tooltip="Remove all proteins."> + </a> + <a (click)="analysis.removeAllHostProteins()" + class="card-footer-item has-text-danger" data-tooltip="Remove all proteins."> <span class="icon"> <i class="fa fa-minus"></i> </span> - <span> + <span> Remove proteins </span> - </a> - </footer> + </a> + </footer> - <footer class="card-footer" *ngIf="selectedAnalysisToken"> - <a (click)="analysis.addSeeds(currentViewNodes)" - class="card-footer-item has-text-success" data-tooltip="Add all visible seeds."> + <footer class="card-footer" *ngIf="selectedAnalysisToken"> + <a (click)="analysis.addSeeds(currentViewNodes)" + class="card-footer-item has-text-success" data-tooltip="Add all visible seeds."> <span class="icon"> <i class="fa fa-plus"></i> </span> - <span> + <span> Add seeds </span> - </a> - <a (click)="analysis.removeSeeds(currentViewNodes)" - class="card-footer-item has-text-danger" data-tooltip="Remove all seeds."> + </a> + <a (click)="analysis.removeSeeds(currentViewNodes)" + class="card-footer-item has-text-danger" data-tooltip="Remove all seeds."> <span class="icon"> <i class="fa fa-minus"></i> </span> - <span> + <span> Remove seeds </span> - </a> - </footer> + </a> + </footer> - <footer class="card-footer"> - <a (click)="showCustomProteinsDialog = true" - class="card-footer-item has-text-primary" - data-tooltip="Add a custom list of proteins."> + <footer class="card-footer"> + <a (click)="showCustomProteinsDialog = true" + class="card-footer-item has-text-primary" + data-tooltip="Add a custom list of proteins."> <span class="icon"> <i class="fa fa-upload"></i> </span> - <span> + <span> Custom proteins </span> - </a> - <a (click)="showThresholdDialog = true" - class="card-footer-item has-text-primary" - data-tooltip="Add proteins expressed in the tissue."> + </a> + <a (click)="showThresholdDialog = true" + class="card-footer-item has-text-primary" + data-tooltip="Add proteins expressed in the tissue."> <span class="icon"> <i class="fa fa-angle-double-up"></i> </span> - <span> + <span> Tissue proteins </span> - </a> - </footer> + </a> + </footer> - <footer class="card-footer"> - <a (click)="analysis.invertSelection(currentViewNodes)" class="card-footer-item has-text-primary" - data-tooltip="Invert the current selection."> + <footer class="card-footer"> + <a (click)="analysis.invertSelection(currentViewNodes)" class="card-footer-item has-text-primary" + data-tooltip="Invert the current selection."> <span class="icon"> <i class="fa fa-sync"></i> </span> - <span> + <span> Invert </span> - </a> - <a (click)="analysis.resetSelection()" class="card-footer-item has-text-danger" - data-tooltip="Remove all entries from the selection."> + </a> + <a (click)="analysis.resetSelection()" class="card-footer-item has-text-danger" + data-tooltip="Remove all entries from the selection."> <span class="icon"> <i class="fa fa-broom"></i> </span> - <span> + <span> Reset </span> - </a> - </footer> + </a> + </footer> + </div> </div> </div> </div> </div> -</div> <div class="is-hidden-tablet mobile-fallback"> Sorry, CoVex is not available for mobile phones. diff --git a/src/app/pages/explorer-page/explorer-page.component.ts b/src/app/pages/explorer-page/explorer-page.component.ts index 8ac0357a..4c826024 100644 --- a/src/app/pages/explorer-page/explorer-page.component.ts +++ b/src/app/pages/explorer-page/explorer-page.component.ts @@ -10,14 +10,14 @@ import { Node, Wrapper, getWrapperFromProtein, - Tissue, getNodeIdsFromI + Tissue } from '../../interfaces'; import {ProteinNetwork} from '../../main-network'; import {HttpClient} from '@angular/common/http'; import {AnalysisService} from '../../analysis.service'; import html2canvas from 'html2canvas'; import {NetworkSettings} from '../../network-settings'; -import {defaultConfig, IConfig} from '../../config'; +import {defaultConfig, EdgeGroup, IConfig, NodeGroup} from '../../config'; declare var vis: any; @@ -288,6 +288,12 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit { }); } + public setConfigEdgeGroup(key: string, values: EdgeGroup) { + // make sure all keys are set + + this.myConfig[key] = {...this.myConfig[key], ...values}; + } + private mapCustomNode(customNode: Node): any { let group = customNode.group; if (typeof group === 'undefined' || typeof this.myConfig.nodeGroups[group] === 'undefined') { diff --git a/src/index.html b/src/index.html index 36090d59..9405cd07 100644 --- a/src/index.html +++ b/src/index.html @@ -18,19 +18,35 @@ <input type="checkbox" onclick=changeConfigStr('{"showOverview":'+this.checked+'}') checked /> Show overview<br> <input type="checkbox" onclick=changeConfigStr('{"showQuery":'+this.checked+'}') /> Show query<br> <input type="checkbox" onclick=changeConfigStr('{"showLeftSidebar":'+this.checked+'}') checked /> Show sidebar<br> +<input type="checkbox" onclick=changeConfigStr('{"showItemSelector":'+this.checked+'}') checked /> Show ItemSelector<br> +<input type="checkbox" onclick=changeConfigStr('{"showSimpleAnalysis":'+this.checked+'}') /> Show SimpleAnalysis<br> +<input type="checkbox" onclick=changeConfigStr('{"showAdvAnalysis":'+this.checked+'}') checked /> Show Advanced Analysis<br> +<input type="checkbox" onclick=changeConfigStr('{"showTasks":'+this.checked+'}') checked /> Show Tasks<br> +<input type="checkbox" onclick=changeConfigStr('{"showSelection":'+this.checked+'}') checked /> Show Selection<br> +<input type="checkbox" onclick=changeConfigStr('{"showFooter":'+this.checked+'}') checked /> Show Footer<br> +<input type="checkbox" onclick=changeConfigStr('{"showLegend":'+this.checked+'}') checked /> Show Legend<br> +<!--<input type="checkbox" onclick=changeConfigStr('{"showSimpleAnalysis":'+this.checked+'}') checked /> Show SimpleAnalysis<br>--> <br> <button onclick="setNetwork('netexp1')">Add proteins</button> + +<!-- "legendUrl": "https://exbio.wzw.tum.de/covex/assets/leg1.png",--> <div> - <network-expander id="netexp1" config='{"showQuery": false, "nodeGroups": {"default": {"color": "grey"}}, "edgeGroups":{"default": {"color": "grey"}, "custom": {"color": "red"}}}' onload="init1()" style="height: 100vh"></network-expander> + <network-expander id="netexp1" config='{ + "showQuery": false, + "legendPos": "right", + "nodeGroups": {"default": {"color": "grey", "name": "Default Group", "shape": "triangle"}}, + "edgeGroups":{"default": {"color": "grey", "name": "Default Edge Group"}, "custom": {"color": "red", "name": "Custom Edge Group"}} + }' onload="init1()" style="height: 100vh"></network-expander> </div> <!-- -<div> <div style="border: 3px solid red"> +<div> <div style="border: 3px solid red"> <network-expander id="netexp2" config='{"legendUrl": "https://i.pinimg.com/originals/ff/72/80/ff72801189f650f11672915cda0f1bdf.png", "legendClass": "my-legend-2"}'></network-expander> </div> + --> <script> diff --git a/src/styles.scss b/src/styles.scss index 11392e29..92062951 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -16,7 +16,7 @@ $info: $primary; @import "~primeng/resources/primeng.min.css"; @import "~primeicons/primeicons.css"; -$height: '1000px'; +@import "variables"; nav.navbar { height: 60px; @@ -36,10 +36,6 @@ span.icon { margin-right: 5px; } -img { - margin: 10px; -} - img.inline { height: 30px; align: middle; @@ -107,11 +103,11 @@ div.covex.network { div.card.network { width: 100%; - height: calc(100% - 75px); + height: calc(100% - #{$network-footer-height}); } div.network { - height: calc(#{$height} - 200px); + height: calc(#{$height} - #{$network-footer-height} - #{$navbar-height} - 48px); } div.parent { @@ -122,12 +118,6 @@ div.image1 { position: relative; } -img.image2 { - position: absolute; - bottom: 0px; - right: 0px; -} - div.center { display: flex; align-items: center; @@ -136,7 +126,7 @@ div.center { div.covex.explorer { - height: calc(#{$height} - 70px); + height: calc(#{$height} - #{$navbar-height}); margin-left: 10px; margin-right: 10px; } @@ -221,3 +211,5 @@ body { .mb-3 { margin-bottom: 10px; } + + diff --git a/src/variables.scss b/src/variables.scss new file mode 100644 index 00000000..0c9a900f --- /dev/null +++ b/src/variables.scss @@ -0,0 +1,15 @@ +$sidebar-width: 38vw; +$sidebar-width-max: 665px; +$navbar-height: 80px; +$row-data-selector-height: auto; +$network-footer-height: 75px; + +$legend-default-background-color: #143d1f; +$legend-circle-size: 35px; +$legend-rectangle-height: 25px; +$legend-rectangle-width: 35px; +$legend-rectangle-radius: 5px; +$legend-edge-width: 20px; +$legend-edge-height: 3px; + +$height: 1000px; -- GitLab