Skip to content
Snippets Groups Projects
Commit 87835e3a authored by Julian Späth's avatar Julian Späth
Browse files

Merge branch 'final-fixes-and-features' into 'master'

Final fixes and features

See merge request covid-19/frontend!88
parents 2c24ca88 e44177e1
No related branches found
No related tags found
No related merge requests found
import {Wrapper, Task, getWrapperFromProtein, getWrapperFromViralProtein} from './interfaces';
import {Wrapper, Task, getWrapperFromProtein, getWrapperFromViralProtein, Protein, ViralProtein} from './interfaces';
import {Subject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {environment} from '../environments/environment';
......@@ -121,6 +121,14 @@ export class AnalysisService {
return this.selectedItems.has(wrapper.nodeId);
}
proteinInSelection(protein: Protein): boolean {
return this.inSelection(getWrapperFromProtein(protein));
}
viralProteinInSelection(viralProtein: ViralProtein): boolean {
return this.inSelection(getWrapperFromViralProtein(viralProtein));
}
removeItem(wrapper: Wrapper) {
const item = this.selectedItems.get(wrapper.nodeId);
if (this.selectedItems.delete(wrapper.nodeId)) {
......
......@@ -48,8 +48,7 @@ import {AnalysisService} from './analysis.service';
TableModule,
],
providers: [AnalysisService],
bootstrap: [AppComponent]
bootstrap: [AppComponent],
})
export class AppModule {
}
......@@ -74,48 +74,40 @@
</div>
</div>
<footer class="card-footer toolbar">
<div class="field has-addons">
<p class="control">
<button class="button is-rounded is-success is-rounded" [disabled]="true">
<span class="icon">
<i class="fas fa-cloud-download-alt" aria-hidden="true"></i>
</span>
<span>
Export Results
</span>
</button>
</p>
<p class="control">
<button class="button is-primary is-rounded" [disabled]="true">
<span class="icon">
<i class="fas fa-camera" aria-hidden="true"></i>
</span>
<div class="field">
<p class="control footer-buttons">
<button class="button is-primary is-rounded" (click)="toCanvas()">
<span class="icon">
<i class="fas fa-camera" aria-hidden="true"></i>
</span>
<span>
Screenshot
</span>
Screenshot
</span>
</button>
</p>
<p class="control">
</div>
<div class="field">
<p class="control footer-buttons">
<button class="button is-danger is-rounded" (click)="analysis.removeTask(token); close()">
<span class="icon">
<i class="fas fa-trash" aria-hidden="true"></i>
</span>
<span class="icon">
<i class="fas fa-trash" aria-hidden="true"></i>
</span>
<span>
Delete Analysis
</span>
Delete Analysis
</span>
</button>
</p>
</div>
<app-toggle *ngIf="task.info.target === 'drug-target'" class="footer-toggle-buttons" textOn="Drugs On" textOff="Off"
<app-toggle *ngIf="task.info.target === 'drug-target'" class="footer-buttons" textOn="Drugs On" textOff="Off"
[value]="showDrugs" (valueChange)="toggleDrugs($event)" icon="fa-capsules"></app-toggle>
<app-toggle class="footer-toggle-buttons" textOn="Animation On" textOff="Off"
<app-toggle class="footer-buttons" textOn="Animation On" textOff="Off"
[value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)" icon="fa-wind"></app-toggle>
</footer>
</div>
<div class="content tab-content scrollable" *ngIf="task && task.info.done" [class.is-visible]="tab === 'table'">
<div class="field has-addons footer-toggle-buttons" *ngIf="tableHasScores">
<div class="field has-addons" *ngIf="tableHasScores">
<p class="control">
<button class="button is-rounded" [class.is-primary]="tableNormalize" (click)="toggleNormalization(true)">
<span class="icon is-small">
......@@ -167,7 +159,7 @@
<td><a href="https://www.drugbank.ca/drugs/{{ e.drugId }}" target="_blank">{{ e.drugId }}</a></td>
<td>{{e.name}}</td>
<td>{{e.status}}</td>
<td *ngIf="tableHasScores">{{e.score || ''}}</td>
<td *ngIf="tableHasScores">{{e.score ? (e.score | number) : ''}}</td>
</tr>
</ng-template>
</p-table>
......@@ -182,11 +174,16 @@
<span>Download</span>
</a>
</div>
<p-table *ngIf="tableProteins.length > 0" [value]="tableProteins">
<p-table *ngIf="tableProteins.length > 0" selectionMode="multiple"
[value]="tableProteins" [selection]="tableSelectedProteins" dataKey="proteinAc"
(selectionChange)="tableProteinSelection($event)">
<ng-template pTemplate="header">
<tr>
<th class="checkbox-col">
<p-tableHeaderCheckbox></p-tableHeaderCheckbox>
</th>
<th [pSortableColumn]="'proteinAc'">
AC
UniProt Code
<p-sortIcon [field]="'proteinAc'"></p-sortIcon>
</th>
<th [pSortableColumn]="'name'">
......@@ -201,9 +198,12 @@
</ng-template>
<ng-template pTemplate="body" let-e>
<tr>
<td>
<p-tableCheckbox [value]="e"></p-tableCheckbox>
</td>
<td><a href="https://www.uniprot.org/uniprot/{{ e.proteinAc }}" target="_blank">{{ e.proteinAc }}</a></td>
<td>{{e.name}}</td>
<td *ngIf="tableHasScores">{{e.score || ''}}</td>
<td *ngIf="tableHasScores">{{e.score ? (e.score | number) : ''}}</td>
</tr>
</ng-template>
</p-table>
......@@ -218,28 +218,36 @@
<span>Download</span>
</a>
</div>
<p-table *ngIf="tableViralProteins.length > 0" [value]="tableViralProteins">
<p-table *ngIf="tableViralProteins.length > 0" selectionMode="multiple"
[value]="tableViralProteins" [selection]="tableSelectedViralProteins" dataKey="effectId"
(selectionChange)="tableViralProteinSelection($event)">
<ng-template pTemplate="header">
<tr>
<td [pSortableColumn]="'effectName'">
<th class="checkbox-col">
<p-tableHeaderCheckbox></p-tableHeaderCheckbox>
</th>
<th [pSortableColumn]="'effectName'">
Name
<p-sortIcon [field]="'effectName'"></p-sortIcon>
</td>
<td [pSortableColumn]="'virusName'">
</th>
<th [pSortableColumn]="'virusName'">
Virus Strain
<p-sortIcon [field]="'virusName'"></p-sortIcon>
</td>
<td *ngIf="tableHasScores" [pSortableColumn]="'score'">
</th>
<th *ngIf="tableHasScores" [pSortableColumn]="'score'">
Score
<p-sortIcon [field]="'score'"></p-sortIcon>
</td>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-e>
<tr>
<td>
<p-tableCheckbox [value]="e"></p-tableCheckbox>
</td>
<td>{{e.effectName}}</td>
<td>{{e.virusName}}</td>
<td *ngIf="tableHasScores">{{e.score || ''}}</td>
<td *ngIf="tableHasScores">{{e.score ? (e.score | number) : ''}}</td>
</tr>
</ng-template>
</p-table>
......
......@@ -31,3 +31,7 @@ div.network {
.table-header {
margin-bottom: 50px;
}
.checkbox-col {
width: 50px;
}
......@@ -13,8 +13,19 @@ import {HttpClient, HttpErrorResponse} from '@angular/common/http';
import {environment} from '../../../environments/environment';
import {AnalysisService, algorithmNames} from '../../analysis.service';
import {
Protein, Task, ViralProtein, Drug, Wrapper, WrapperType,
getWrapperFromProtein, getWrapperFromDrug, getWrapperFromViralProtein, getNodeIdsFromPDI, getNodeIdsFromPPI
Protein,
Task,
ViralProtein,
Drug,
Wrapper,
WrapperType,
getWrapperFromProtein,
getWrapperFromDrug,
getWrapperFromViralProtein,
getNodeIdsFromPDI,
getNodeIdsFromPPI,
getViralProteinNodeId,
getProteinNodeId
} from '../../interfaces';
import html2canvas from 'html2canvas';
import {toast} from 'bulma-toast';
......@@ -59,7 +70,9 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
public tableDrugs: Array<Drug & Scored> = [];
public tableProteins: Array<Protein & Scored> = [];
public tableSelectedProteins: Array<Protein & Scored> = [];
public tableViralProteins: Array<ViralProtein & Scored> = [];
public tableSelectedViralProteins: Array<ViralProtein & Scored> = [];
public tableNormalize = false;
public tableHasScores = false;
......@@ -98,12 +111,17 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.network = new vis.Network(container, this.nodeData, options);
const promises: Promise<any>[] = [];
promises.push(this.http.get<any>(`${environment.backend}task_result/?token=${this.token}&view=proteins`).toPromise()
.then((table) => {
this.tableProteins = table;
this.tableProteins.forEach((r) => r.rawScore = r.score);
this.tableSelectedProteins = [];
this.tableProteins.forEach((r) => {
r.rawScore = r.score;
if (this.analysis.proteinInSelection(r)) {
this.tableSelectedProteins.push(r);
}
});
}));
promises.push(this.http.get<any>(`${environment.backend}task_result/?token=${this.token}&view=viral_proteins`).toPromise()
.then((table) => {
......@@ -156,8 +174,31 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
}
});
this.analysis.subscribe((item, selected) => {
if (item.type === 'host') {
// TODO: Refactor!
const found = this.tableSelectedProteins.findIndex((i) => getProteinNodeId(i) === item.nodeId);
const tableItem = this.tableProteins.find((i) => getProteinNodeId(i) === item.nodeId);
if (selected && found === -1 && tableItem) {
this.tableSelectedProteins.push(tableItem);
}
if (!selected && found !== -1 && tableItem) {
this.tableSelectedProteins.splice(found, 1);
}
this.tableSelectedProteins = [...this.tableSelectedProteins];
} else if (item.type === 'virus') {
// TODO: Refactor!
const found = this.tableSelectedViralProteins.findIndex((i) => getViralProteinNodeId(i) === item.nodeId);
const tableItem = this.tableViralProteins.find((i) => getViralProteinNodeId(i) === item.nodeId);
if (selected && found === -1 && tableItem) {
this.tableSelectedViralProteins.push(tableItem);
}
if (!selected && found !== -1 && tableItem) {
this.tableSelectedViralProteins.splice(found, 1);
}
this.tableSelectedViralProteins = [...this.tableSelectedViralProteins];
}
const node = this.nodeData.nodes.get(item.nodeId);
if (!node) {
return;
......@@ -192,10 +233,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.emitVisibleItems(false);
}
export() {
}
public toggleNormalization(normalize: boolean) {
this.tableNormalize = normalize;
......@@ -351,9 +388,9 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
this.drugNodes = [];
this.drugEdges = [];
if (this.showDrugs) {
const proteinAcs = this.proteins.map((protein) => protein.proteinAc);
// tslint:disable-next-line:max-line-length
const result = await this.http.get<any>(`${environment.backend}drug_interactions/?proteins=${JSON.stringify(proteinAcs)}`).toPromise().catch((err: HttpErrorResponse) => {
const result = await this.http.get<any>(
`${environment.backend}drug_interactions/?token=${this.token}`).toPromise().catch(
(err: HttpErrorResponse) => {
// simple logging, but you can do a lot more, see below
toast({
message: 'An error occured while fetching the drugs.',
......@@ -396,7 +433,6 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
}
}
public updatePhysicsEnabled(bool: boolean) {
this.physicsEnabled = bool;
this.network.setOptions({
......@@ -409,21 +445,48 @@ export class AnalysisWindowComponent implements OnInit, OnChanges {
});
}
public screenshot() {
const elem = document.getElementById(this.indexscreenshot.toString());
html2canvas(elem).then((canvas) => {
const generatedImage1 = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
public toCanvas() {
html2canvas(this.networkEl.nativeElement).then((canvas) => {
const generatedImage = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
const a = document.createElement('a');
a.href = generatedImage1;
a.download = `Resulting_Network.png`;
a.href = generatedImage;
a.download = `Network.png`;
a.click();
});
}
public updateshowdrugs(bool) {
this.drugstatus = bool;
public tableProteinSelection(e) {
const oldSelection = [...this.tableSelectedProteins];
this.tableSelectedProteins = e;
for (const i of this.tableSelectedProteins) {
const wrapper = getWrapperFromProtein(i);
if (oldSelection.indexOf(i) === -1) {
this.analysis.addItem(wrapper);
}
}
for (const i of oldSelection) {
const wrapper = getWrapperFromProtein(i);
if (this.tableSelectedProteins.indexOf(i) === -1) {
this.analysis.removeItem(wrapper);
}
}
}
public tableViralProteinSelection(e) {
const oldSelection = [...this.tableSelectedViralProteins];
this.tableSelectedViralProteins = e;
for (const i of this.tableSelectedViralProteins) {
const wrapper = getWrapperFromViralProtein(i);
if (oldSelection.indexOf(i) === -1) {
this.analysis.addItem(wrapper);
}
}
for (const i of oldSelection) {
const wrapper = getWrapperFromViralProtein(i);
if (this.tableSelectedViralProteins.indexOf(i) === -1) {
this.analysis.removeItem(wrapper);
}
}
}
}
......@@ -148,7 +148,7 @@
</p>
</header>
<div class="card-content">
<div class="card-image" id="0">
<div class="card-image" id="canvas-content">
<div class="parent">
<div class="network center image1" #network>
<button class="button is-loading center" alt="Snow">Loading</button>
......@@ -164,7 +164,7 @@
<i class="fas fa-camera" aria-hidden="true"></i>
</span> <span>Screenshot</span>
</button>
<app-toggle class="footer-toggle-buttons" textOn="Animation On" textOff="Off" [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)" icon="fa-wind"></app-toggle>
<app-toggle class="footer-buttons" textOn="Animation On" textOff="Off" [value]="physicsEnabled" (valueChange)="updatePhysicsEnabled($event)" icon="fa-wind"></app-toggle>
</footer>
</div>
</div>
......
......@@ -63,7 +63,6 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
public selectedAnalysisToken: string | null = null;
public currentDataset = [];
private screenshotArray = [0];
public currentViewProteins: Protein[];
public currentViewEffects: ViralProtein[];
......@@ -417,15 +416,12 @@ export class ExplorerPageComponent implements OnInit, AfterViewInit {
}
public toCanvas() {
this.screenshotArray.forEach((key, index) => {
const elem = document.getElementById(index.toString());
html2canvas(elem).then((canvas) => {
const generatedImage = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
const a = document.createElement('a');
a.href = generatedImage;
a.download = `Network.png`;
a.click();
});
html2canvas(this.networkEl.nativeElement).then((canvas) => {
const generatedImage = canvas.toDataURL('image/png').replace('image/png', 'image/octet-stream');
const a = document.createElement('a');
a.href = generatedImage;
a.download = `Network.png`;
a.click();
});
}
......
......@@ -12,7 +12,7 @@ $danger: #EF476F;
$link: $primary;
$info: $primary;
@import "~bulma/bulma.sass";
@import "~primeng/resources/primeng.css";
@import "~primeng/resources/primeng.min.css";
@import "~primeicons/primeicons.css";
html {
......@@ -174,7 +174,7 @@ div.field.has-addons.add-remove-toggle {
color: $danger;
}
.footer-toggle-buttons {
.footer-buttons {
margin-left: 20px;
margin-right: 10px;
}
......@@ -192,3 +192,8 @@ body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
.ui-chkbox-box {
border: 1px solid black !important;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment