src/app/modules/root/root.component.ts
OnDestroy
selector | app-root |
styleUrls | ./root.component.scss |
templateUrl | ./root.component.html |
Properties |
|
Methods |
Outputs |
constructor(configService: ConfigService, store: Store, ts: TreeService, route: ActivatedRoute, dialog: MatDialog, snackbar: MatSnackBar, indent: IndentedListService, report: ReportService, infoSheet: MatBottomSheet, sheetService: SheetService, router: Router, bms: BimodalService)
|
|||||||||||||||||||||||||||||||||||||||
Defined in src/app/modules/root/root.component.ts:171
|
|||||||||||||||||||||||||||||||||||||||
Parameters :
|
export | |
Type : EventEmitter
|
|
Defined in src/app/modules/root/root.component.ts:122
|
closeLoading |
closeLoading()
|
Defined in src/app/modules/root/root.component.ts:508
|
Close loading dialog
Returns :
void
|
compareData | ||||||||
compareData(data: CompareData[])
|
||||||||
Defined in src/app/modules/root/root.component.ts:526
|
||||||||
Set compare data
Parameters :
Returns :
void
|
deleteSheet | ||||||||
deleteSheet(i: number)
|
||||||||
Defined in src/app/modules/root/root.component.ts:455
|
||||||||
Deletes a sheeet from the compare
Parameters :
Returns :
void
|
exportVis | ||||||||
exportVis(option: string)
|
||||||||
Defined in src/app/modules/root/root.component.ts:571
|
||||||||
Exports the visualiation into 3 formats
Parameters :
Returns :
void
|
getStructureInfo | ||||||
getStructureInfo(data: literal type)
|
||||||
Defined in src/app/modules/root/root.component.ts:562
|
||||||
Dispatch action to open bottom sheet
Parameters :
Returns :
void
|
openLoading | ||||||||
openLoading(text?: string)
|
||||||||
Defined in src/app/modules/root/root.component.ts:464
|
||||||||
Opens loading dialog
Parameters :
Returns :
void
|
openSnackBarToUpdateFilter |
openSnackBarToUpdateFilter()
|
Defined in src/app/modules/root/root.component.ts:678
|
Returns :
void
|
parseSheetUrl | ||||||||
parseSheetUrl(url: string)
|
||||||||
Defined in src/app/modules/root/root.component.ts:481
|
||||||||
Parameters :
Returns :
literal type
a object with the sheetID, gid, and CsvUrl |
toggleSideNav |
toggleSideNav()
|
Defined in src/app/modules/root/root.component.ts:518
|
Toggling sidebars for Report, IL, Debug, Compare
Returns :
void
|
updateReport | ||||||||
updateReport(data: Report)
|
||||||||
Defined in src/app/modules/root/root.component.ts:446
|
||||||||
Function to update the report with the data
Parameters :
Returns :
void
|
allCompareData$ |
Type : Observable<literal type>
|
Decorators :
@Select(SheetState.getAllCompareData)
|
Defined in src/app/modules/root/root.component.ts:129
|
bimodalConfig |
Type : BimodalConfig
|
Defined in src/app/modules/root/root.component.ts:117
|
Bimodal filter values to snd via snackbar update |
bm$ |
Type : Observable<BimodalData>
|
Decorators :
@Select(TreeState.getBimodal)
|
Defined in src/app/modules/root/root.component.ts:146
|
Public bms |
Type : BimodalService
|
Defined in src/app/modules/root/root.component.ts:185
|
bmType$ |
Type : Observable<string>
|
Decorators :
@Select(TreeState.getBiomarkerType)
|
Defined in src/app/modules/root/root.component.ts:147
|
bottomSheetDOI$ |
Type : Observable<DOI[]>
|
Decorators :
@Select(SheetState.getBottomSheetDOI)
|
Defined in src/app/modules/root/root.component.ts:136
|
bottomSheetInfo$ |
Type : Observable<SheetInfo>
|
Decorators :
@Select(SheetState.getBottomSheetInfo)
|
Defined in src/app/modules/root/root.component.ts:135
|
bs$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getBottomSheet)
|
Defined in src/app/modules/root/root.component.ts:164
|
c$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getCompareState)
|
Defined in src/app/modules/root/root.component.ts:165
|
compareData$ |
Type : Observable<Row[]>
|
Decorators :
@Select(SheetState.getCompareData)
|
Defined in src/app/modules/root/root.component.ts:128
|
compareDetails |
Type : CompareData[]
|
Default value : []
|
Defined in src/app/modules/root/root.component.ts:113
|
Comparison sheets details |
compareSheets$ |
Type : Observable<CompareData[]>
|
Decorators :
@Select(SheetState.getCompareSheets)
|
Defined in src/app/modules/root/root.component.ts:126
|
config$ |
Type : Observable<BimodalConfig>
|
Decorators :
@Select(TreeState.getBimodalConfig)
|
Defined in src/app/modules/root/root.component.ts:150
|
Public configService |
Type : ConfigService
|
Defined in src/app/modules/root/root.component.ts:174
|
data |
Type : Row[]
|
Default value : []
|
Defined in src/app/modules/root/root.component.ts:72
|
Organ sheet data |
data$ |
Type : Observable<Row[]>
|
Decorators :
@Select(SheetState.getData)
|
Defined in src/app/modules/root/root.component.ts:125
|
Public dialog |
Type : MatDialog
|
Defined in src/app/modules/root/root.component.ts:178
|
dl$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getDebugLog)
|
Defined in src/app/modules/root/root.component.ts:163
|
error |
Type : Error
|
Defined in src/app/modules/root/root.component.ts:92
|
Stores the error |
error$ |
Type : Observable<literal type>
|
Decorators :
@Select(UIState.getError)
|
Defined in src/app/modules/root/root.component.ts:157
|
fullAsData$ |
Type : Observable<Row[]>
|
Decorators :
@Select(SheetState.getFullAsData)
|
Defined in src/app/modules/root/root.component.ts:138
|
fullDataByOrgan$ |
Type : Observable<[][]>
|
Decorators :
@Select(SheetState.getFullDataByOrgan)
|
Defined in src/app/modules/root/root.component.ts:139
|
getFromCache$ |
Type : Observable<boolean>
|
Decorators :
@Select(SheetState.getDataFromCache)
|
Defined in src/app/modules/root/root.component.ts:140
|
hasError |
Default value : false
|
Defined in src/app/modules/root/root.component.ts:88
|
Denotesthe error state |
il$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getIndentList)
|
Defined in src/app/modules/root/root.component.ts:154
|
Public indent |
Type : IndentedListService
|
Defined in src/app/modules/root/root.component.ts:180
|
infoSheetRef |
Type : MatBottomSheetRef
|
Defined in src/app/modules/root/root.component.ts:104
|
Botton input sheet ref |
isControlPaneOpen |
Default value : false
|
Defined in src/app/modules/root/root.component.ts:100
|
Dnotes of sidebar control pane is open |
links$ |
Type : Observable<LinksASCTBData>
|
Decorators :
@Select(TreeState.getLinksData)
|
Defined in src/app/modules/root/root.component.ts:145
|
loading |
Default value : true
|
Defined in src/app/modules/root/root.component.ts:76
|
Denotes if loading |
loading$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getLoading)
|
Defined in src/app/modules/root/root.component.ts:158
|
loadingText$ |
Type : Observable<string>
|
Decorators :
@Select(UIState.getLoadingText)
|
Defined in src/app/modules/root/root.component.ts:159
|
logs$ |
Type : Observable<Logs>
|
Decorators :
@Select(LogsState)
|
Defined in src/app/modules/root/root.component.ts:168
|
mode |
Type : string
|
Default value : 'vis'
|
Defined in src/app/modules/root/root.component.ts:109
|
Mode of the application. Playground or visualiization Default is vis |
mode$ |
Type : Observable<string>
|
Decorators :
@Select(SheetState.getMode)
|
Defined in src/app/modules/root/root.component.ts:133
|
omapSheetConfig |
Type : SheetDetails[]
|
Default value : []
|
Defined in src/app/modules/root/root.component.ts:171
|
pane$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getControlPaneState)
|
Defined in src/app/modules/root/root.component.ts:153
|
rd$ |
Type : Observable<Report>
|
Decorators :
@Select(SheetState.getReportdata)
|
Defined in src/app/modules/root/root.component.ts:127
|
Public report |
Type : ReportService
|
Defined in src/app/modules/root/root.component.ts:181
|
report$ |
Type : Observable<boolean>
|
Decorators :
@Select(UIState.getReport)
|
Defined in src/app/modules/root/root.component.ts:162
|
Public route |
Type : ActivatedRoute
|
Defined in src/app/modules/root/root.component.ts:177
|
Public router |
Type : Router
|
Defined in src/app/modules/root/root.component.ts:184
|
searchOption$ |
Type : Observable<SearchStructure>
|
Decorators :
@Select(TreeState.getLatestSearchStructure)
|
Defined in src/app/modules/root/root.component.ts:149
|
sheet |
Type : Sheet
|
Defined in src/app/modules/root/root.component.ts:84
|
Selected sheet |
sheetConfig |
Type : SheetDetails[]
|
Default value : []
|
Defined in src/app/modules/root/root.component.ts:170
|
sheetConfig$ |
Type : Observable<SheetConfig>
|
Decorators :
@Select(SheetState.getSheetConfig)
|
Defined in src/app/modules/root/root.component.ts:137
|
Public sheetService |
Type : SheetService
|
Defined in src/app/modules/root/root.component.ts:183
|
snack$ |
Type : Observable<Snackbar>
|
Decorators :
@Select(UIState.getSnackbar)
|
Defined in src/app/modules/root/root.component.ts:161
|
snackbarRef |
Type : MatSnackBarRef<TextOnlySnackBar>
|
Defined in src/app/modules/root/root.component.ts:96
|
Reference to the snackbar |
Public store |
Type : Store
|
Defined in src/app/modules/root/root.component.ts:175
|
treeData$ |
Type : Observable<TNode[]>
|
Decorators :
@Select(TreeState.getTreeData)
|
Defined in src/app/modules/root/root.component.ts:143
|
Public ts |
Type : TreeService
|
Defined in src/app/modules/root/root.component.ts:176
|
uiState$ |
Type : Observable<UIStateModel>
|
Decorators :
@Select(UIState)
|
Defined in src/app/modules/root/root.component.ts:160
|
verticalScrollEntity |
Type : TreeComponent
|
Decorators :
@ViewChild(TreeComponent)
|
Defined in src/app/modules/root/root.component.ts:121
|
view |
Type : View
|
Defined in src/app/modules/root/root.component.ts:80
|
Vega view |
import { Component, EventEmitter, OnDestroy, Output, ViewChild } from '@angular/core';
import { MatBottomSheet, MatBottomSheetRef } from '@angular/material/bottom-sheet';
import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
import { MatSnackBar, MatSnackBarConfig, MatSnackBarRef, TextOnlySnackBar } from '@angular/material/snack-bar';
import { ActivatedRoute, Router } from '@angular/router';
import { Select, Store } from '@ngxs/store';
import * as moment from 'moment';
import { StateReset } from 'ngxs-reset-plugin';
import { Observable } from 'rxjs';
import { View } from 'vega';
import { UpdateBimodalConfig } from '../../actions/tree.actions';
import {
CloseCompare,
CloseLoading,
CloseRightSideNav,
CloseSnackbar,
HasError,
OpenBottomSheet,
} from '../../actions/ui.actions';
import { ConfigService } from '../../app-config.service';
import { DoiComponent } from '../../components/doi/doi.component';
import { IndentedListService } from '../../components/indented-list/indented-list.service';
import { InfoComponent } from '../../components/info/info.component';
import { LoadingComponent } from '../../components/loading/loading.component';
import { OrganTableSelectorComponent } from '../../components/organ-table-selector/organ-table-selector.component';
import { ReportService } from '../../components/report/report.service';
import { BimodalConfig, BimodalData } from '../../models/bimodal.model';
import { Report } from '../../models/report.model';
import { Error } from '../../models/response.model';
import {
CompareData,
DOI,
GraphData,
Row,
Sheet,
SheetConfig,
SheetDetails,
SheetInfo,
VersionDetail,
} from '../../models/sheet.model';
import { LinksASCTBData, SearchStructure, TNode } from '../../models/tree.model';
import { Logs, OpenBottomSheetData, Snackbar } from '../../models/ui.model';
import { SheetService } from '../../services/sheet.service';
import { LogsState } from '../../store/logs.state';
import { UIState, UIStateModel } from '../../store/ui.state';
import { BimodalService } from '../tree/bimodal.service';
import { TreeComponent } from '../tree/tree.component';
import {
DeleteCompareSheet,
FetchAllOrganData,
FetchDataFromAssets,
FetchInitialPlaygroundData,
FetchSelectedOrganData,
FetchSheetData,
UpdateGetFromCache,
UpdateMode,
UpdateReport,
} from './../../actions/sheet.actions';
import { SheetState } from './../../store/sheet.state';
import { TreeState } from './../../store/tree.state';
import { TreeService } from './../tree/tree.service';
@Component({
selector: 'app-root',
templateUrl: './root.component.html',
styleUrls: ['./root.component.scss'],
})
export class RootComponent implements OnDestroy {
/**
* Organ sheet data
*/
data: Row[] = [];
/**
* Denotes if loading
*/
loading = true;
/**
* Vega view
*/
view!: View;
/**
* Selected sheet
*/
sheet!: Sheet;
/**
* Denotesthe error state
*/
hasError = false;
/**
* Stores the error
*/
error!: Error;
/**
* Reference to the snackbar
*/
snackbarRef!: MatSnackBarRef<TextOnlySnackBar>;
/**
* Dnotes of sidebar control pane is open
*/
isControlPaneOpen = false;
/**
* Botton input sheet ref
*/
infoSheetRef!: MatBottomSheetRef;
/**
* Mode of the application. Playground or visualiization
* Default is vis
*/
mode = 'vis';
/**
* Comparison sheets details
*/
compareDetails: CompareData[] = [];
/**
* Bimodal filter values to snd via snackbar update
*/
bimodalConfig!: BimodalConfig;
// The container used for vertical scrolling of the viz is different than the one used for horizontal scrolling
// Here we get references to both values.
@ViewChild(TreeComponent) verticalScrollEntity!: TreeComponent;
@Output() export = new EventEmitter<unknown>();
// Sheet Observables
@Select(SheetState.getData) data$!: Observable<Row[]>;
@Select(SheetState.getCompareSheets) compareSheets$!: Observable<CompareData[]>;
@Select(SheetState.getReportdata) rd$!: Observable<Report>;
@Select(SheetState.getCompareData) compareData$!: Observable<Row[]>;
@Select(SheetState.getAllCompareData) allCompareData$!: Observable<{
data: Row[];
sheets: CompareData[];
}>;
@Select(SheetState.getMode) mode$!: Observable<string>;
@Select(SheetState.getBottomSheetInfo)
bottomSheetInfo$!: Observable<SheetInfo>;
@Select(SheetState.getBottomSheetDOI) bottomSheetDOI$!: Observable<DOI[]>;
@Select(SheetState.getSheetConfig) sheetConfig$!: Observable<SheetConfig>;
@Select(SheetState.getFullAsData) fullAsData$!: Observable<Row[]>;
@Select(SheetState.getFullDataByOrgan) fullDataByOrgan$!: Observable<Row[][]>;
@Select(SheetState.getDataFromCache) getFromCache$!: Observable<boolean>;
// Tree Observables
@Select(TreeState.getTreeData) treeData$!: Observable<TNode[]>;
// @Select(TreeState.getBottomSheetData) bsd$!: Observable<any>;
@Select(TreeState.getLinksData) links$!: Observable<LinksASCTBData>;
@Select(TreeState.getBimodal) bm$!: Observable<BimodalData>;
@Select(TreeState.getBiomarkerType) bmType$!: Observable<string>;
@Select(TreeState.getLatestSearchStructure)
searchOption$!: Observable<SearchStructure>;
@Select(TreeState.getBimodalConfig) config$!: Observable<BimodalConfig>;
// Control Pane Observables
@Select(UIState.getControlPaneState) pane$!: Observable<boolean>;
@Select(UIState.getIndentList) il$!: Observable<boolean>;
// UI Observables
@Select(UIState.getError) error$!: Observable<{ error: Error }>;
@Select(UIState.getLoading) loading$!: Observable<boolean>;
@Select(UIState.getLoadingText) loadingText$!: Observable<string>;
@Select(UIState) uiState$!: Observable<UIStateModel>;
@Select(UIState.getSnackbar) snack$!: Observable<Snackbar>;
@Select(UIState.getReport) report$!: Observable<boolean>;
@Select(UIState.getDebugLog) dl$!: Observable<boolean>;
@Select(UIState.getBottomSheet) bs$!: Observable<boolean>;
@Select(UIState.getCompareState) c$!: Observable<boolean>;
// Logs Oberservables
@Select(LogsState) logs$!: Observable<Logs>;
sheetConfig: SheetDetails[] = [];
omapSheetConfig: SheetDetails[] = [];
constructor(
public configService: ConfigService,
public store: Store,
public ts: TreeService,
public route: ActivatedRoute,
public dialog: MatDialog,
private readonly snackbar: MatSnackBar,
public indent: IndentedListService,
public report: ReportService,
private readonly infoSheet: MatBottomSheet,
public sheetService: SheetService,
public router: Router,
public bms: BimodalService,
) {
this.configService.sheetConfiguration$.subscribe((sheetOptions) => {
this.sheetConfig = sheetOptions;
});
this.configService.omapsheetConfiguration$.subscribe((sheetOptions) => {
this.omapSheetConfig = sheetOptions;
});
this.data$.subscribe((data) => {
if (data.length) {
this.data = data;
try {
this.ts.makeTreeData(this.sheet, data, []);
} catch (err) {
console.log(err);
this.store.dispatch(new HasError({ hasError: true, msg: err as string, status: 400 }));
}
}
});
this.error$.subscribe((err) => {
this.error = err.error;
});
this.config$.subscribe((config) => {
this.bimodalConfig = config;
});
this.route.queryParamMap.subscribe((query) => {
const selectedOrgans = query.get('selectedOrgans') ?? '';
const version = query.get('version');
const comparisonCSV = query.get('comparisonCSVURL');
const comparisonName = query.get('comparisonName');
const comparisonColor = query.get('comparisonColor');
const comparisonHasFile = query.get('comparisonHasFile');
const sheet = query.get('sheet');
const playground = query.get('playground');
const omapSelectedOrgans = query.get('omapSelectedOrgans') ?? '';
if (!(selectedOrgans || omapSelectedOrgans) && playground !== 'true') {
store.dispatch(new UpdateMode('vis'));
store.dispatch(new CloseLoading('Select Organ Model Rendered'));
const config = new MatDialogConfig();
config.disableClose = true;
config.autoFocus = true;
config.id = 'OrganTableSelector';
config.width = 'fit-content';
config.data = {
isIntilalSelect: true,
getFromCache: true,
};
const dialogRef = this.dialog.open(OrganTableSelectorComponent, config);
dialogRef.afterClosed().subscribe(({ organs, cache, omapOrgans }) => {
store.dispatch(new UpdateGetFromCache(cache));
if (organs !== false) {
this.router.navigate(['/vis'], {
queryParams: {
selectedOrgans: organs?.join(','),
playground: false,
omapSelectedOrgans: omapOrgans?.join(','),
},
queryParamsHandling: 'merge',
});
}
});
} else if (
(selectedOrgans || omapSelectedOrgans) &&
playground !== 'true' &&
(comparisonCSV || comparisonHasFile)
) {
store.dispatch(new UpdateMode('vis'));
const comparisonCSVURLList = comparisonCSV?.split('|');
const comparisonColorList = comparisonColor?.split('|');
const comparisonNameList = comparisonName?.split('|');
const comparisonDetails = this.compareDetails;
this.sheet = this.sheetConfig.find((i) => i.name === 'some') as Sheet;
if (!comparisonDetails.length) {
const colors = [
'#6457A6',
'#2C666E',
'#72A98F',
'#3D5A6C',
'#F37748',
'#FB4B4E',
'#FFCBDD',
'#7C0B2B',
'#067BC2',
'#ECC30B',
];
comparisonCSVURLList?.forEach((linkUrl, index) => {
linkUrl = linkUrl.trim();
comparisonDetails.push({
title:
comparisonNameList !== undefined && comparisonNameList.length - 1 >= index
? comparisonNameList[index]
: `Sheet ${index + 1}`,
description: '',
link: linkUrl,
color:
comparisonColorList !== undefined && comparisonColorList.length - 1 >= index
? comparisonColorList[index]
: colors[index % colors.length],
sheetId: this.parseSheetUrl(linkUrl).sheetID,
gid: this.parseSheetUrl(linkUrl).gid,
csvUrl: this.parseSheetUrl(linkUrl).csvUrl,
});
});
}
store.dispatch(
new FetchSelectedOrganData(
this.sheet,
selectedOrgans.split(','),
omapSelectedOrgans.split(','),
comparisonDetails,
),
);
sessionStorage.setItem('selectedOrgans', selectedOrgans);
if (omapSelectedOrgans) {
this.openSnackBarToUpdateFilter();
}
} else if ((selectedOrgans || omapSelectedOrgans) && playground !== 'true') {
store.dispatch(new UpdateMode('vis'));
this.sheet = this.sheetConfig.find((i) => i.name === 'some') as Sheet;
store.dispatch(
new FetchSelectedOrganData(this.sheet, selectedOrgans.split(','), omapSelectedOrgans.split(',')),
);
sessionStorage.setItem('selectedOrgans', selectedOrgans);
if (omapSelectedOrgans) {
this.openSnackBarToUpdateFilter();
}
} else if (playground === 'true') {
store.dispatch(new UpdateMode('playground'));
this.sheet = this.sheetConfig.find((i) => i.name === 'some') as Sheet;
this.store.dispatch(new FetchInitialPlaygroundData());
store.dispatch(new CloseLoading());
} else {
store.dispatch(new UpdateMode('vis'));
this.sheet = this.sheetConfig.find((i) => i.name === sheet) as Sheet;
localStorage.setItem('sheet', this.sheet.name);
if (version === 'latest') {
if (this.sheet.name === 'all') {
store.dispatch(new FetchAllOrganData(this.sheet));
} else {
store.dispatch(new FetchSheetData(this.sheet));
}
} else {
store.dispatch(new FetchDataFromAssets(version ?? '', this.sheet));
}
}
});
this.loading$.subscribe((l) => {
if (l && !this.dialog.getDialogById('LoadingDialog')) {
this.openLoading();
} else if (!l) {
this.closeLoading();
}
});
this.uiState$.subscribe((state) => {
this.isControlPaneOpen = state.controlPaneOpen;
});
this.snack$.subscribe((sb) => {
if (sb.opened) {
const config: MatSnackBarConfig = {
duration: 1500,
verticalPosition: 'bottom',
horizontalPosition: 'end',
panelClass: [`${sb.type}-snackbar`],
};
this.snackbarRef = this.snackbar.open(sb.text, 'Dismiss', config);
this.snackbarRef.afterDismissed();
store.dispatch(new CloseSnackbar());
}
});
this.pane$.subscribe((_unused) => {
if (this.data) {
ts.makeTreeData(this.sheet, this.data, []);
}
});
this.bs$.subscribe((value) => {
if (value) {
this.infoSheetRef = this.infoSheet.open(InfoComponent, {
disableClose: false,
hasBackdrop: false,
autoFocus: false,
panelClass: 'bottom-sheet-style',
data: this.bottomSheetInfo$,
});
} else {
if (this.infoSheetRef) {
this.infoSheetRef.dismiss();
}
}
});
this.bottomSheetDOI$.subscribe((data) => {
if (data.length) {
this.infoSheetRef = this.infoSheet.open(DoiComponent, {
disableClose: false,
hasBackdrop: false,
autoFocus: false,
panelClass: 'bottom-sheet-style',
data,
});
} else {
if (this.infoSheetRef) {
this.infoSheetRef.dismiss();
}
}
});
// Listen for changes in the last selected search structure
this.searchOption$.subscribe((structure) => {
// Structure will be null when all structures are deselected
if (this.verticalScrollEntity && structure) {
const yPos = structure.y + 30; // 30 accounts for top-padding
const xPos = structure.x;
// The vertical scroll div is a CdkScrollable component, but the horizontal scroll element is a normal div.
// This leads to differences in the scrollTo interface.
const contentHeight = this.verticalScrollEntity.treeElementRef.nativeElement.offsetHeight;
const contentWidth = this.verticalScrollEntity.treeElementRef.nativeElement.offsetWidth;
const yScrollPos = this.verticalScrollEntity.treeElementRef.nativeElement.scrollTop;
const xScrollPos = this.verticalScrollEntity.treeElementRef.nativeElement.scrollLeft;
// Scroll to the selected structure if it's outside the area of the screen
if (xPos > xScrollPos + contentWidth || xPos < xScrollPos) {
this.verticalScrollEntity.treeElementRef.nativeElement.scrollTo(xPos, yScrollPos);
}
if (yPos > yScrollPos + contentHeight || yPos < yScrollPos) {
this.verticalScrollEntity.treeElementRef.nativeElement.scrollTo({
top: yPos - contentHeight / 2,
});
}
}
});
this.compareSheets$.subscribe((sheets) => {
const omapSheets = sheets.filter((sheet) => sheet.isOmap);
if (omapSheets.length > 0) {
this.openSnackBarToUpdateFilter();
}
});
}
ngOnDestroy() {
this.store.dispatch(new StateReset(SheetState));
}
/**
* Function to update the report with the data
*
* @param data sheet data
*/
updateReport(data: Report) {
this.store.dispatch(new UpdateReport(data));
}
/**
* Deletes a sheeet from the compare
*
* @param i index of sheet
*/
deleteSheet(i: number) {
this.store.dispatch(new DeleteCompareSheet(i));
}
/**
* Opens loading dialog
*
* @param text Loading text
*/
openLoading(text?: string) {
const config = new MatDialogConfig();
config.disableClose = true;
config.autoFocus = true;
config.id = 'LoadingDialog';
config.data = text;
config.width = '300px';
this.dialog.open(LoadingComponent, config);
}
/**
*
* @param url of the sheet to compare
* @returns a object with the sheetID, gid, and CsvUrl
*/
parseSheetUrl(url: string): { sheetID: string; gid: string; csvUrl: string } {
if (url.startsWith('https://docs.google.com/spreadsheets/d/')) {
const splitUrl = url.split('/');
if (splitUrl.length === 7) {
return {
sheetID: splitUrl[5],
gid: splitUrl[6].split('=')[1],
csvUrl: '',
};
}
return {
sheetID: '0',
gid: '0',
csvUrl: url,
};
} else {
return {
sheetID: '0',
gid: '0',
csvUrl: url,
};
}
}
/**
* Close loading dialog
*/
closeLoading() {
const loadingDialog = this.dialog.getDialogById('LoadingDialog');
if (loadingDialog) {
loadingDialog.close();
}
}
/**
* Toggling sidebars for Report, IL, Debug, Compare
*/
toggleSideNav() {
this.store.dispatch(new CloseRightSideNav());
}
/**
* Set compare data
* @param data compare data
*/
compareData(data: CompareData[]) {
this.store.dispatch(new CloseCompare());
this.compareDetails = data;
const compareDataString = data
.filter((compareData: CompareData) => compareData.link !== '')
.map((compareData: CompareData) => compareData.link)
.join('|');
const compareColorString = data
.filter((compareData: CompareData) => compareData.color !== '')
.map((compareData: CompareData) => compareData.color)
.join('|');
const compareNameString = data
.filter((compareData: CompareData) => compareData.title !== '')
.map((compareData: CompareData) => compareData.title)
.join('|');
const compareHasFile = data // check if any of the sheets has a file
.some((compareData: CompareData) => compareData.formData !== null);
this.router.navigate(['/vis'], {
queryParams: {
comparisonCSVURL: compareDataString,
comparisonName: compareNameString,
comparisonColor: compareColorString,
comparisonHasFile: compareHasFile ? 'true' : 'false',
},
queryParamsHandling: 'merge',
});
}
/**
* Dispatch action to open bottom sheet
* @param id ontology id
*/
getStructureInfo(data: { name: string; ontologyId: string }) {
this.store.dispatch(new OpenBottomSheet(data as OpenBottomSheetData));
}
/**
* Exports the visualiation into 3 formats
*
* @param option Export option. PNG | SVG | Vega Spec
*/
exportVis(option: string) {
const dt = moment(new Date()).format('YYYY.MM.DD_hh.mm');
const sn = this.sheet.display.toLowerCase().replace(' ', '_');
const formatType = option.toLowerCase();
let csvURL;
const sheet = this.store.selectSnapshot(SheetState.getSheet);
const selectedOrgans = this.store.selectSnapshot(SheetState.getSelectedOrgans);
const omapSelectedOrgans = this.store.selectSnapshot(SheetState.getOMAPSelectedOrgans);
const urls: string[] = [];
if (sheet.name === 'all' || sheet.name === 'some') {
for (const organ of selectedOrgans) {
this.sheetConfig.forEach((config) => {
config.version?.forEach((version: VersionDetail) => {
if (version.value === organ) {
if (version.csvUrl) {
urls.push(version.csvUrl);
} else {
urls.push(this.sheetService.formURL(version.sheetId ?? '', version.gid ?? ''));
}
}
});
});
}
for (const organ of omapSelectedOrgans) {
this.omapSheetConfig.forEach((config) => {
config.version?.forEach((version: VersionDetail) => {
if (version.value === organ) {
if (version.csvUrl) {
urls.push(version.csvUrl);
} else {
urls.push(this.sheetService.formURL(version.sheetId ?? '', version.gid ?? ''));
}
}
});
});
}
csvURL = urls.join('|');
}
if (option === 'Graph Data') {
this.sheetService
.fetchSheetData(sheet.sheetId ?? '', sheet.gid ?? '', csvURL ? csvURL : sheet.csvUrl, undefined, 'graph')
.subscribe((g) => {
const graphData = g as GraphData;
const graphDataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(graphData.data));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', graphDataStr);
downloadAnchorNode.setAttribute('download', `asct+b_graph_data_${sn}_${dt}` + '.json');
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
});
} else if (option === 'Vega Spec') {
const spec = this.store.selectSnapshot(TreeState.getVegaSpec);
const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(spec, null, 4));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', dataStr);
downloadAnchorNode.setAttribute('download', `asct+b_${sn}_${dt}` + '.json');
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
} else if (option === 'JSON-LD') {
this.sheetService
.fetchSheetData(sheet.sheetId ?? '', sheet.gid ?? '', csvURL ? csvURL : sheet.csvUrl, undefined, 'jsonld')
.subscribe((g) => {
const graphData = g as GraphData;
const graphDataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(graphData));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', graphDataStr);
downloadAnchorNode.setAttribute('download', `asct+b_json_ld_${sn}_${dt}` + '.json');
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
});
} else if (option === 'OWL (RDF/XML)') {
this.sheetService
.fetchSheetData(sheet.sheetId ?? '', sheet.gid ?? '', csvURL ? csvURL : sheet.csvUrl, undefined, 'owl')
.subscribe((g) => {
const graphData = g as GraphData;
const graphDataStr =
'data:application/rdf+xml;charset=utf-8,' + encodeURIComponent(JSON.stringify(graphData));
const downloadAnchorNode = document.createElement('a');
downloadAnchorNode.setAttribute('href', graphDataStr);
downloadAnchorNode.setAttribute('download', `asct+b_owl_${sn}_${dt}` + '.owl');
document.body.appendChild(downloadAnchorNode);
downloadAnchorNode.click();
downloadAnchorNode.remove();
});
} else {
const view = this.store.selectSnapshot(TreeState.getVegaView);
const fileName = `asct+b_${sn}_${dt}.${formatType}`;
view.background('#fafafa');
view
.toImageURL(formatType)
.then((url: string) => {
const link = document.createElement('a');
link.setAttribute('href', url);
link.setAttribute('target', '_blank');
link.setAttribute('download', fileName);
link.dispatchEvent(new MouseEvent('click'));
})
.catch((error) => {
console.log(error);
});
}
}
openSnackBarToUpdateFilter() {
if (this.bimodalConfig.BM.type !== 'Protein') {
const config: MatSnackBarConfig = {
duration: 10000,
verticalPosition: 'bottom',
horizontalPosition: 'center',
};
setTimeout(() => {
this.snackbarRef = this.snackbar.open(
'OMAP Detected, Do you want to filter out only Proteins ' + 'from the available BioMarkers?',
'Filter',
config,
);
this.snackbarRef.onAction().subscribe(() => {
this.bimodalConfig.BM.type = 'Protein';
this.store.dispatch(new UpdateBimodalConfig(this.bimodalConfig)).subscribe((states) => {
const data = states.sheetState.data;
const treeData = states.treeState.treeData;
const bimodalConfig = states.treeState.bimodal.config;
const sheetConfig = states.sheetState.sheetConfig;
const omapConfig = states.treeState.omapConfig;
const filteredProtiens = states.sheetState.filteredProtiens;
if (data.length) {
this.bms.makeBimodalData(data, treeData, bimodalConfig, false, sheetConfig, omapConfig, filteredProtiens);
}
});
});
}, 2000);
}
}
}
<div class="h-100 w-100">
<mat-drawer-container class="control-pane-container h-100" autosize>
<mat-drawer #controlPaneDrawer class="control-pane" mode="side" [opened]="pane$ | async">
<app-control-pane [error]="error"></app-control-pane>
</mat-drawer>
<mat-drawer
#rightDrawer
class="right-sidenav"
mode="over"
[opened]="(il$ | async) || (report$ | async) || (dl$ | async) || (c$ | async)"
position="end"
(closedStart)="toggleSideNav()"
autoFocus="false"
style="z-index: 3"
>
<app-report
(deleteSheet)="deleteSheet($event)"
[compareData]="allCompareData$"
[inputReportData]="rd$"
(closeReport)="rightDrawer.close()"
*ngIf="report$ | async"
[sheetData]="data"
[asFullData]="(fullAsData$ | async) ?? []"
[fullDataByOrgan]="(fullDataByOrgan$ | async) ?? []"
[currentSheet]="sheet"
[currentSheetConfig]="sheetConfig$"
[linksData$]="links$"
(computedReport)="updateReport($event)"
[bmType]="(bmType$ | async) ?? ''"
[hideReportCompareTab]="(mode$ | async) === 'playground'"
></app-report>
<app-indent
(closeIL)="rightDrawer.close()"
*ngIf="il$ | async"
[sheetData]="data"
[currentSheet]="sheet"
(openBottomSheet)="getStructureInfo($event)"
></app-indent>
<app-debug-logs
(closeDebug)="rightDrawer.close()"
*ngIf="dl$ | async"
[currentSheet]="sheet"
[logs]="(logs$ | async)!"
></app-debug-logs>
<app-compare
(closeCompare)="rightDrawer.close()"
*ngIf="c$ | async"
class="compare-sidenav"
(compareData)="compareData($event)"
[compareSheets]="compareSheets$"
></app-compare>
</mat-drawer>
<mat-drawer-content>
<app-navbar (export)="exportVis($event)" [cache]="(getFromCache$ | async) ?? false"></app-navbar>
<div id="content" class="h-100 w-100">
<app-error *ngIf="error.hasError" [error]="error"></app-error>
<div
class="example-box box-container"
cdkDrag
[ngStyle]="{
'margin-top': (mode$ | async) === 'vis' ? '1.25rem' : '4.0625rem'
}"
*ngIf="(pane$ | async) === false"
>
<app-legend
[treeData]="(treeData$ | async) ?? []"
[bimodalData]="(bm$ | async)!"
[compareData]="(compareSheets$ | async) ?? []"
[error]="error"
></app-legend>
</div>
<div #treeDiv class="tree-div" *ngIf="(mode$ | async) === 'vis'">
<app-tree *ngIf="!error.hasError"></app-tree>
</div>
<div class="playground-dig" *ngIf="(mode$ | async) === 'playground'">
<app-playground></app-playground>
</div>
</div>
</mat-drawer-content>
</mat-drawer-container>
</div>
./root.component.scss
.control-pane-container {
height: 100%;
width: 100%;
position: absolute;
left: 0;
}
.control-pane {
width: 15.625rem;
border-right: 0.1875rem solid #444a6510;
min-width: 3.125rem;
}
.tree-div {
max-width: 100%;
overflow-x: auto;
}
.right-sidenav {
min-width: 31.25rem;
max-width: 43.75rem;
overflow-x: auto;
border-left: 0.1875rem solid #ececec;
box-shadow: none !important;
z-index: 10 !important;
}
.compare-sidenav {
width: 40.625rem !important;
}
.example-box {
cursor: move;
z-index: 5;
}
.box-container {
position: absolute;
width: 15.625rem;
left: 0.625rem;
z-index: 2;
}
#content {
padding-top: 4rem;
}