Skip to content
Snippets Groups Projects
Commit e27f0802 authored by Xiao Gui's avatar Xiao Gui
Browse files

feat: restore download data in receptor components

parent 399a6ffc
No related branches found
No related tags found
No related merge requests found
......@@ -53,6 +53,7 @@ export class Autoradiography extends BaseReceptor implements OnChanges, AfterVie
}
rerender(){
this.dataBlobAvailable = false
if (!this.el || !this.renderBuffer) {
this.pleaseRender = true
return
......@@ -71,6 +72,11 @@ export class Autoradiography extends BaseReceptor implements OnChanges, AfterVie
const imgData = ctx.createImageData(this.width, this.height)
imgData.data.set(this.renderBuffer)
ctx.putImageData(imgData, 0, 0)
canvas.toBlob(blob => {
this.dataBlobAvailable = true
this.dataBlob$.next(blob)
})
this.pleaseRender = false
}
}
import { Directive, Input, SimpleChanges } from "@angular/core";
import { BehaviorSubject } from "rxjs";
import { SAPI, SapiAtlasModel, SapiParcellationModel, SapiRegionModel, SapiSpaceModel } from "src/atlasComponents/sapi";
import { SapiRegionalFeatureReceptorModel } from "src/atlasComponents/sapi/type";
......@@ -83,6 +84,15 @@ export abstract class BaseReceptor{
abstract rerender(): void
/**
* flag to indicate that getDataBlob() can be called.
*/
dataBlobAvailable = false
/**
* blob object observable, representing the data of the component. This allows the data to be downloaded.
*/
dataBlob$ = new BehaviorSubject<Blob>(null)
constructor(
protected sapi: SAPI
){
......
import { ChangeDetectorRef, Component, Input, OnChanges, SimpleChanges } from "@angular/core";
import { ChangeDetectorRef, Component, OnChanges, SimpleChanges } from "@angular/core";
import { SAPI } from "src/atlasComponents/sapi";
import { SapiRegionalFeatureReceptorModel } from "src/atlasComponents/sapi/type";
import { BaseReceptor } from "../base";
@Component({
......@@ -37,4 +36,8 @@ export class Entry extends BaseReceptor implements OnChanges {
setSelectedSymbol(select: string){
this.selectedSymbol = select
}
getDataBlob(): Promise<Blob> {
throw new Error(`cannot get blob of entry component`)
}
}
<mat-card>
<spinner-cmp *ngIf="loading"></spinner-cmp>
<ng-template [ngTemplateOutlet]="downloadBtn"
[ngTemplateOutletContext]="{
label: 'fingerprint.tsv',
filename: 'fingerprint.tsv',
receptorCmp: fp
}">
</ng-template>
<sxplr-sapiviews-features-receptor-fingerprint
[sxplr-sapiviews-features-receptor-data]="receptorData"
(sxplr-sapiviews-features-receptor-fingerprint-receptor-selected)="setSelectedSymbol($event)"
#fp="sxplrSapiViewsFeaturesReceptorFP"
>
</sxplr-sapiviews-features-receptor-fingerprint>
......@@ -22,16 +30,51 @@
<ng-template [ngIf]="selectedSymbol">
<ng-template [ngTemplateOutlet]="downloadBtn"
[ngTemplateOutletContext]="{
label: 'profile.tsv',
filename: 'profile.tsv',
receptorCmp: profile
}">
</ng-template>
<sxplr-sapiviews-features-receptor-profile
[sxplr-sapiviews-features-receptor-data]="receptorData"
[sxplr-sapiviews-features-receptor-profile-selected-symbol]="selectedSymbol">
[sxplr-sapiviews-features-receptor-profile-selected-symbol]="selectedSymbol"
#profile="sxplrSapiViewsFeaturesReceptorProfile">
</sxplr-sapiviews-features-receptor-profile>
<ng-template [ngTemplateOutlet]="downloadBtn"
[ngTemplateOutletContext]="{
label: 'autoradiograph.png',
filename: 'autoradiograph.png',
receptorCmp: ar
}">
</ng-template>
<sxplr-sapiviews-features-receptor-autoradiograph
[sxplr-sapiviews-features-receptor-data]="receptorData"
[sxplr-sapiviews-features-receptor-autoradiograph-selected-symbol]="selectedSymbol"
#ar="sxplrSapiViewsFeaturesReceptorAR"
>
</sxplr-sapiviews-features-receptor-autoradiograph>
</ng-template>
</mat-card>
<!-- download data button template -->
<ng-template #downloadBtn
let-label="label"
let-filename="filename"
let-receptorCmp="receptorCmp">
<button mat-button
*ngIf="receptorCmp.dataBlobAvailable"
single-file-output
[single-file-output-blob]="receptorCmp.dataBlob$ | async"
[single-file-output-filename]="filename">
<i class="fas fa-download"></i>
<span>
{{ label }}
</span>
</button>
</ng-template>
......@@ -45,7 +45,8 @@ function transformRadar(input: SapiRegionalFeatureReceptorModel['data']['fingerp
templateUrl: './fingerprint.template.html',
styleUrls: [
'./fingerprint.style.css'
]
],
exportAs: "sxplrSapiViewsFeaturesReceptorFP"
})
export class Fingerprint extends BaseReceptor implements OnChanges, AfterViewInit, OnDestroy{
......@@ -105,6 +106,23 @@ export class Fingerprint extends BaseReceptor implements OnChanges, AfterViewIni
this.dumbRadarCmp.metaBs = this.receptorData.data.receptor_symbols
this.dumbRadarCmp.radar= transformRadar(this.receptorData.data.fingerprints)
this.setDumbRadarPlease = false
this.dataBlob$.next(this.getDataBlob())
this.dataBlobAvailable = true
this.setDumbRadarPlease = false
}
private getDataBlob(): Blob {
if (!this.receptorData?.data?.fingerprints) throw new Error(`raw data unavailable. Try again later.`)
const fingerprints = this.receptorData.data.fingerprints
const output: string[] = []
output.push(
["name", "mean", "std"].join("\t")
)
for (const key in fingerprints) {
output.push(
[key, fingerprints[key].mean, fingerprints[key].std].join("\t")
)
}
return new Blob([output.join("\n")], { type: 'text/tab-separated-values' })
}
}
......@@ -5,6 +5,7 @@ import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
import { SpinnerModule } from "src/components/spinner";
import { AngularMaterialModule } from "src/sharedModules";
import { APPEND_SCRIPT_TOKEN } from "src/util/constants";
import { ZipFilesOutputModule } from "src/zipFilesOutput/module";
import { Autoradiography } from "./autoradiography/autoradiography.component";
import { Entry } from "./entry/entry.component";
import { Fingerprint } from "./fingerprint/fingerprint.component"
......@@ -17,6 +18,7 @@ import { Profile } from "./profile/profile.component"
FormsModule,
BrowserAnimationsModule,
SpinnerModule,
ZipFilesOutputModule,
],
declarations: [
Autoradiography,
......
......@@ -10,7 +10,8 @@ import { BaseReceptor } from "../base";
templateUrl: './profile.template.html',
styleUrls: [
'./profile.style.css'
]
],
exportAs: "sxplrSapiViewsFeaturesReceptorProfile"
})
export class Profile extends BaseReceptor implements AfterViewInit, OnChanges{
......@@ -46,6 +47,7 @@ export class Profile extends BaseReceptor implements AfterViewInit, OnChanges{
}
async rerender() {
this.dataBlobAvailable = false
if (!this.dumbLineCmp) {
this.pleaseRender = true
return
......@@ -67,7 +69,23 @@ export class Profile extends BaseReceptor implements AfterViewInit, OnChanges{
for (const idx in prof) {
this.dumbLineData[idx] = prof[idx]
}
this.dataBlob$.next(this.getDataBlob())
this.dataBlobAvailable = true
this.dumbLineCmp.profileBs = this.dumbLineData
}
}
private getDataBlob(): Blob {
if (!this.dumbLineData) throw new Error(`data has not been populated. Perhaps wait until render finishes?`)
const output: string[] = []
output.push(
["cortical depth (%)", "receptor density (fmol/mg)"].join("\t")
)
for (const key in this.dumbLineData) {
output.push(
[key, this.dumbLineData[key]].join("\t")
)
}
return new Blob([output.join("\n")], { type: 'text/tab-separated-values' })
}
}
......@@ -12,12 +12,18 @@ export class SingleFileOutput {
@Input('single-file-output')
singleFile: TZipFileConfig
@Input('single-file-output-filename')
singleFileFileName: string
@Input('single-file-output-blob')
singleFileBlob: Blob
@HostListener('click')
onClick(): void{
const anchor = this.doc.createElement('a')
const blob = new Blob([this.singleFile.filecontent], { type: 'text/plain' })
const blob = this.singleFileBlob || new Blob([this.singleFile.filecontent], { type: 'text/plain' })
anchor.href = URL.createObjectURL(blob)
anchor.download = this.singleFile.filename
anchor.download = this.singleFileFileName || this.singleFile.filename
this.doc.body.appendChild(anchor)
anchor.click()
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment