diff --git a/src/app/components/analysis-panel/analysis-panel.component.html b/src/app/components/analysis-panel/analysis-panel.component.html index 43a2424c784ff6aaff414b51d026c1f2db6d92bd..55c72b13d14a65cda202821fd05f58e3308cf02e 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.html +++ b/src/app/components/analysis-panel/analysis-panel.component.html @@ -13,7 +13,7 @@ </span> </a> </header> - <div class="card-content"> + <div class="card-content fullheight"> <div class="tabs is-centered"> <ul> <li [class.is-active]="tab === 'table'"><a (click)="tab = 'table'">Table</a></li> @@ -21,7 +21,7 @@ <li [class.is-active]="tab === 'meta'"><a (click)="tab = 'meta'">Parameters</a></li> </ul> </div> - <div class="content tab-content meta" *ngIf="task && task.info.done" [class.is-visible]="tab === 'meta'"> + <div class="tab-content meta" *ngIf="task && task.info.done" [class.is-visible]="tab === 'meta'"> <div *ngIf="task"> <p *ngIf="task.info.algorithm !== 'quick' && task.info.algorithm !== 'super'"> Algorithm: <strong>{{algorithmNames[task.info.algorithm]}}</strong> @@ -124,16 +124,16 @@ </div> </div> </div> - <div class="content tab-content" *ngIf="task && task.info.done" [class.is-visible]="tab === 'network'"> - <div class="card-image"> - <div class="network center image1" #network> - <button class="button is-loading center">Loading</button> + <div class="tab-content" *ngIf="task && task.info.done" [class.is-visible]="tab === 'network'"> + <div class="card-image canvas-content" #networkWithLegend> + <div *ngIf="myConfig.showLegend"> + <app-network-legend [config]="myConfig" [analysis]="false"></app-network-legend> </div> - <div class="image2"> - <img src="assets/ll2.png" width="200px"/> + <div class="fullheight center image1" #network> + <button class="button is-loading center">Loading</button> </div> </div> - <footer class="card-footer toolbar"> + <footer class="card-footer toolbar scroll-y" *ngIf="myConfig.showFooter"> <div class="field"> <p class="control footer-buttons"> <button class="button is-primary is-rounded has-tooltip" @@ -141,7 +141,7 @@ <span class="icon"> <i class="fas fa-camera" aria-hidden="true"></i> </span> - <span> + <span [ngClass]="{'text-normal':smallStyle}"> Screenshot </span> </button> @@ -150,48 +150,51 @@ <div class="field"> <p class="control footer-buttons"> - <a [href]="graphmlLink()" class="button is-success is-rounded has-tooltip" data-tooltip="Export this network as .graphml file."> + <a [href]="graphmlLink()" class="button is-success is-rounded has-tooltip" + data-tooltip="Export this network as .graphml file."> <span class="icon"> <i class="fas fa-download" aria-hidden="true"></i> </span> - <span> + <span [ngClass]="{'text-normal':smallStyle}"> Export as .graphml </span> </a> </p> </div> -<!-- <div class="field">--> -<!-- <p class="control footer-buttons">--> -<!-- <button class="button is-danger is-rounded has-tooltip" data-tooltip="Delete the current analysis."--> -<!-- (click)="analysis.removeTask(token); close()">--> -<!-- <span class="icon">--> -<!-- <i class="fas fa-trash" aria-hidden="true"></i>--> -<!-- </span>--> -<!-- <span>--> -<!-- Delete Analysis--> -<!-- </span>--> -<!-- </button>--> -<!-- </p>--> -<!-- </div>--> + <!-- <div class="field">--> + <!-- <p class="control footer-buttons">--> + <!-- <button class="button is-danger is-rounded has-tooltip" data-tooltip="Delete the current analysis."--> + <!-- (click)="analysis.removeTask(token); close()">--> + <!-- <span class="icon">--> + <!-- <i class="fas fa-trash" aria-hidden="true"></i>--> + <!-- </span>--> + <!-- <span>--> + <!-- Delete Analysis--> + <!-- </span>--> + <!-- </button>--> + <!-- </p>--> + <!-- </div>--> <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"> - <span *ngIf="!selectedTissue">Tissue</span> - <span *ngIf="selectedTissue">{{selectedTissue.name}}</span> - <span class="icon is-small"> + aria-haspopup="true" aria-controls="dropdown-menu" [ngClass]="{'button-small':smallStyle}"> + <div [ngClass]="{'text-small':smallStyle}"> + <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> + </div> </button> </div> <div class="dropdown-menu" id="dropdown-menu" role="menu"> - <div class="dropdown-content tissue-dropdown"> - <div class="scroll-area"> + <div class="dropdown-content tissue-dropdown" [ngClass]="{'button-small':smallStyle}"> + <div class="scroll-area" [ngClass]="{'text-small':smallStyle}"> <a (click)="selectTissue(null)" [class.is-active]="!selectedTissue" class="dropdown-item"> @@ -210,10 +213,13 @@ <app-toggle *ngIf="task.info.target === 'drug-target'" class="footer-buttons" textOn="Drugs On" textOff="Off" tooltipOn="Display drugs in the network" tooltipOff="Hide drugs in the network" + [smallStyle]="smallStyle" [value]="showDrugs" (valueChange)="toggleDrugs($event)"></app-toggle> <app-toggle class="footer-buttons" textOn="Animation On" textOff="Off" - tooltipOn="Enable the network animation." tooltipOff="Disable the network animation and freeze nodes." + tooltipOn="Enable the network animation." + tooltipOff="Disable the network animation and freeze nodes." + [smallStyle]="smallStyle" [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)"></app-toggle> </footer> </div> diff --git a/src/app/components/analysis-panel/analysis-panel.component.scss b/src/app/components/analysis-panel/analysis-panel.component.scss index 202f31a1670b87f79457d751cc9c432c20009c6c..2d7bc5b5dc9b093b12c324d1ab9e969721767afd 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.scss +++ b/src/app/components/analysis-panel/analysis-panel.component.scss @@ -12,7 +12,7 @@ div.network { visibility: hidden; position: absolute; width: calc(100% - 50px); - height: calc(100vh - 210px - 24px); + height: calc(100% - 41px - 67px - 24px); &.is-visible { visibility: visible; @@ -51,3 +51,26 @@ div.network { font-size: 10px; width: 10px; } + +.text-small { + font-size: 11px; +} + +.text-normal{ + font-size:12px; +} + +.b-text-small{ + font-size:14px +} + +.b-text-smaller{ + font-size:12px +} + +.button-small{ + padding: 3px 10px 3px 10px; +} +.scroll-y{ + overflow-y: auto; +} diff --git a/src/app/components/analysis-panel/analysis-panel.component.ts b/src/app/components/analysis-panel/analysis-panel.component.ts index 9cc61b9cad32ba7a826c7f1a5356b688f5c2d7a1..b90d64ce57978ec1dabe8f628aa0746d49c4ff4a 100644 --- a/src/app/components/analysis-panel/analysis-panel.component.ts +++ b/src/app/components/analysis-panel/analysis-panel.component.ts @@ -29,8 +29,8 @@ import { import domtoimage from 'dom-to-image'; import {toast} from 'bulma-toast'; import {NetworkSettings} from '../../network-settings'; -import { NetexControllerService } from 'src/app/services/netex-controller/netex-controller.service'; -import { IConfig } from 'src/app/config'; +import {NetexControllerService} from 'src/app/services/netex-controller/netex-controller.service'; +import {defaultConfig, IConfig} from 'src/app/config'; declare var vis: any; @@ -56,14 +56,25 @@ interface Baited { export class AnalysisPanelComponent implements OnInit, OnChanges { @ViewChild('network', {static: false}) networkEl: ElementRef; - + @ViewChild('networkWithLegend', {static: false}) networkWithLegendEl: ElementRef; @Input() token: string | null = null; - + @Input() public smallStyle = false; + @Input() + public set config(config: IConfig | undefined) { + if (typeof config === 'undefined') { + return; + } + for (const key of Object.keys(config)) { + this.myConfig[key] = config[key]; + } + } @Output() tokenChange = new EventEmitter<string | null>(); @Output() showDetailsChange = new EventEmitter<Wrapper>(); @Output() visibleItems = new EventEmitter<[any[], [Node[], Tissue]]>(); public task: Task | null = null; + public myConfig: IConfig = JSON.parse(JSON.stringify(defaultConfig)); + private network: any; private nodeData: { nodes: any, edges: any } = {nodes: null, edges: null}; @@ -139,8 +150,6 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { if (this.task && this.task.info.done) { const result = await this.netex.getTaskResult(this.token); - console.log("result") - console.log(result) const nodeAttributes = result.nodeAttributes || {}; const isSeed: { [key: string]: boolean } = nodeAttributes.isSeed || {}; @@ -177,7 +186,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { this.tableProteins.forEach((r) => { r.rawScore = r.score; r.isSeed = isSeed[r.id]; - const wrapper = getWrapperFromNode(r) + const wrapper = getWrapperFromNode(r); if (this.analysis.inSelection(wrapper)) { this.tableSelectedProteins.push(r); } @@ -375,14 +384,12 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { * For the third case, fall back to a default case which can also be set by user. */ public inferNodeGroup(wrapper: Wrapper): string { - console.log(wrapper) + console.log(wrapper); if (wrapper.data.group !== undefined) { - return wrapper.data.group - } - else if (wrapper.data.netexId !== undefined && wrapper.data.netexId.startsWith('d')) { + return wrapper.data.group; + } else if (wrapper.data.netexId !== undefined && wrapper.data.netexId.startsWith('d')) { return 'drug'; - } - else if (wrapper.data.netexId !== undefined && wrapper.data.netexId.startsWith('p')) { + } else if (wrapper.data.netexId !== undefined && wrapper.data.netexId.startsWith('p')) { return 'protein'; } } @@ -392,7 +399,7 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { return wrapper.data.label; } const identifier = config.identifier; - if (identifier === 'uniprot'){ + if (identifier === 'uniprot') { return wrapper.data.uniprotAc; } else if (identifier === 'symbol') { return wrapper.data.symbol; @@ -470,14 +477,14 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { */ private mapNode(config: IConfig, wrapper: Wrapper, isSeed?: boolean, score?: number): any { - console.log("node group") - console.log(config.nodeGroups) - console.log("node") + console.log('node group'); + console.log(config.nodeGroups); + console.log('node'); console.log(wrapper.data); // override group is node is seed - wrapper.data.group = isSeed ? 'seedNode' : wrapper.data.group + wrapper.data.group = isSeed ? 'seedNode' : wrapper.data.group; const node = JSON.parse(JSON.stringify(config.nodeGroups[wrapper.data.group])); node.id = wrapper.id; node.label = this.inferNodeLabel(config, wrapper); @@ -576,12 +583,22 @@ export class AnalysisPanelComponent implements OnInit, OnChanges { } public toImage() { - domtoimage.toPng(this.networkEl.nativeElement, { bgcolor: '#ffffff' }).then((generatedImage) => { + this.downloadDom(this.networkWithLegendEl.nativeElement).catch(error => { + console.error("Falling back to network only screenshot. Some components seem to be inaccessable, most likely the legend is a custom image with CORS access problems on the host server side.") + this.downloadDom(this.networkEl.nativeElement).catch(e => { + console.error("Some network content seems to be inaccessable for saving as a screenshot. This can happen due to custom images used as nodes. Please ensure correct CORS accessability on the images host server.") + console.error(e) + }); + }); + } + + public downloadDom(dom: object) { + return domtoimage.toPng(dom, {bgcolor: '#ffffff'}).then((generatedImage) => { const a = document.createElement('a'); a.href = generatedImage; a.download = `Network.png`; a.click(); - }).catch(e => console.error(e)); + }); } public tableProteinSelection(e) { diff --git a/src/app/pages/explorer-page/explorer-page.component.html b/src/app/pages/explorer-page/explorer-page.component.html index 1fced32e3f690a0965dbe4f35f9566d4dda24e7c..dc9860fd99f6fc4ce645c1d6f50c3907396476a6 100644 --- a/src/app/pages/explorer-page/explorer-page.component.html +++ b/src/app/pages/explorer-page/explorer-page.component.html @@ -100,7 +100,7 @@ <div class="analysis-view" *ngIf="selectedAnalysisToken"> <app-analysis-panel [(token)]="selectedAnalysisToken" (showDetailsChange)="selectedWrapper = $event" - (visibleItems)="analysisWindowChanged($event)"></app-analysis-panel> + (visibleItems)="analysisWindowChanged($event)" [config]="myConfig" [smallStyle]="smallStyle"></app-analysis-panel> </div> <div class="card network"> @@ -111,7 +111,7 @@ </p> </header> <div class="card-content fullheight"> - <div class="card-image" id="canvas-content" #networkWithLegend> + <div class="card-image canvas-content" #networkWithLegend> <div *ngIf="myConfig.showLegend"> <app-network-legend [config]="myConfig" [analysis]="false"></app-network-legend> </div> @@ -122,8 +122,7 @@ </div> </div> - <footer *ngIf="myConfig.showFooter" class="card-footer toolbar explorer-footer" - [ngClass]="{'footer-small':smallStyle}"> + <footer *ngIf="myConfig.showFooter" class="card-footer toolbar explorer-footer"> <button (click)="toImage()" class="button is-primary is-rounded has-tooltip" data-tooltip="Take a screenshot of the current network."> <span class="icon"> diff --git a/src/styles.scss b/src/styles.scss index ce6f6d24ec9250a73e77effa1536b0cc44771e33..5bf5007ba5771ffb7c21b16ff9c2d1e5ac79d96f 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -21,7 +21,7 @@ height: 100%; } -#canvas-content { +.canvas-content { height: calc(100% - #{$network-footer-height}); }