Select what ETF's you would like to use
This commit is contained in:
parent
deb5251b5a
commit
37a8889a9d
@ -1,30 +1,57 @@
|
||||
<!--The content below is only a placeholder and can be replaced.-->
|
||||
<!-- Toolbar -->
|
||||
<mat-toolbar>
|
||||
<img class="mr-3" src="assets/logo.png" height="36px" width="auto">
|
||||
<span class="mr-3">ETF Demo</span>
|
||||
<small *ngIf="timer" class="text-muted">{{timer}} microseconds to upload</small>
|
||||
<span class="mx-auto"><!-- Spacer --></span>
|
||||
<mat-chip-list class="mr-2">
|
||||
<mat-chip *ngFor="let file of fileNames; let i = index" class="text-white" [style.backgroundColor]="colorScheme.domain[i]"
|
||||
<mat-chip *ngFor="let file of fileNames; let i = index" class="text-white"
|
||||
[style.backgroundColor]="colorScheme.domain[i]"
|
||||
[removable]="true" (removed)="remove($event.chip.value)" [value]="file">
|
||||
{{file}}
|
||||
<mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
</mat-chip-list>
|
||||
|
||||
<button mat-button (click)="fileUploader.click()">
|
||||
<mat-icon>add</mat-icon>
|
||||
Upload
|
||||
</button>
|
||||
<input #fileUploader type="file" accept="text/csv" multiple hidden (change)="upload(fileUploader.files)">
|
||||
</mat-toolbar>
|
||||
<img *ngIf="!chartResults" class="float-right mt-2 mr-5" src="assets/starthere.png">
|
||||
<div *ngIf="chartResults" class="w-100" [style.height]="chartHeight">
|
||||
<ngx-charts-bar-horizontal-2d #chart
|
||||
[scheme]="colorScheme"
|
||||
[results]="chartResults"
|
||||
[xAxis]="true"
|
||||
[yAxis]="true"
|
||||
[xAxisTickFormatting]="format">
|
||||
</ngx-charts-bar-horizontal-2d>
|
||||
|
||||
<!-- Start Here image -->
|
||||
<img *ngIf="!fileNames.length" class="float-right mt-2 mr-5" src="assets/starthere.png">
|
||||
|
||||
<!-- Content -->
|
||||
<div *ngIf="fileNames.length" class="content-height w-100" style="overflow: hidden auto">
|
||||
<!-- Input for selecting holdings -->
|
||||
<div class="p-3">
|
||||
<mat-form-field class="w-50">
|
||||
<mat-chip-list #chipList>
|
||||
<mat-chip *ngFor="let holding of graphHoldings; let i = index" [removable]="true" (removed)="graphHoldings.splice(i, 1); updateGraph()">
|
||||
{{holding}}
|
||||
<mat-icon matChipRemove>cancel</mat-icon>
|
||||
</mat-chip>
|
||||
<input #holdingInput class="w-100"
|
||||
placeholder="Add Holdings"
|
||||
[matAutocomplete]="auto"
|
||||
[matChipInputFor]="chipList"
|
||||
(keyup)="search($event.target.value)">
|
||||
</mat-chip-list>
|
||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="updateGraph($event.option.value); holdingInput.blur()">
|
||||
<mat-option *ngFor="let holding of autoCompleteList | async" [value]="holding">
|
||||
{{holding}}
|
||||
</mat-option>
|
||||
</mat-autocomplete>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
|
||||
<!-- Chart -->
|
||||
<ngx-charts-bar-vertical-2d #chart
|
||||
[scheme]="colorScheme"
|
||||
[results]="chartResults"
|
||||
[xAxis]="true"
|
||||
[yAxis]="true"
|
||||
[yAxisTickFormatting]="format">
|
||||
</ngx-charts-bar-vertical-2d>
|
||||
</div>
|
||||
<input #fileUploader type="file" accept="text/csv" multiple hidden (change)="upload(fileUploader.files)">
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Component} from '@angular/core';
|
||||
import {Component, ElementRef, EventEmitter, ViewChild} from '@angular/core';
|
||||
import {timer} from './timer';
|
||||
import {colorScheme} from './colorScheme';
|
||||
|
||||
@ -7,10 +7,16 @@ import {colorScheme} from './colorScheme';
|
||||
templateUrl: './app.component.html'
|
||||
})
|
||||
export class AppComponent {
|
||||
@ViewChild('holdingInput') holdingInput: ElementRef;
|
||||
|
||||
autoCompleteList = new EventEmitter<string[]>(); // Async pipe to provide autocomplete list after being filtered by the text input
|
||||
colorScheme = colorScheme; // colors
|
||||
chartResults; // This is where the chart reads the data from
|
||||
chartHeight = '100%'; // Dynamic height for chart
|
||||
chartResults = []; // This is where the chart reads the data from
|
||||
holdings: string[] = []; // All the merged holdings
|
||||
fileNames: string[] = []; // All the filenames
|
||||
mergedData = {}; // All the holdings merged together
|
||||
timer = window['timer']; // Async pipe to display the timed data
|
||||
graphHoldings: string[] = []; // Holdings we are graphing
|
||||
|
||||
// ngx-charts requires a different data structure than the hash map we built so I will use a setter to handle converting it when we go to save the processed data.
|
||||
private _data = {};
|
||||
@ -19,7 +25,7 @@ export class AppComponent {
|
||||
this._data = data;
|
||||
|
||||
// merge the files together
|
||||
let mergedData = Object.values(data).reduce((acc, file) => {
|
||||
this.mergedData = Object.values(data).reduce((acc, file) => {
|
||||
Object.keys(file).forEach(key => {
|
||||
if(!acc[key]) acc[key] = [];
|
||||
file[key].forEach(val => acc[key].push(val));
|
||||
@ -27,14 +33,14 @@ export class AppComponent {
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
// Take the merged data set and get everything ready for it to be charted
|
||||
this.chartHeight = `${Object.keys(mergedData).length * 100}px`;
|
||||
this.chartResults = Object.keys(mergedData).map(key => ({name: key, series: mergedData[key].map((val, i) => ({name: i, value: val}))}));
|
||||
// Store the keys for easy referencing
|
||||
this.fileNames = Object.keys(this.data);
|
||||
this.holdings = Object.keys(this.mergedData).sort();
|
||||
this.autoCompleteList.next(this.holdings);
|
||||
}
|
||||
|
||||
get fileNames() { return Object.keys(this.data); }
|
||||
|
||||
constructor() {
|
||||
// Hack to connect angular context to the native one
|
||||
setInterval(() => this.timer = Math.round(window['timer'] * 10) / 10, 250);
|
||||
}
|
||||
|
||||
@ -44,6 +50,12 @@ export class AppComponent {
|
||||
this.data = Object.assign({}, this.data);
|
||||
}
|
||||
|
||||
search(text: string) {
|
||||
// Filter the holdings list by the text and push it through the async pipe
|
||||
if(!text) this.autoCompleteList.next(this.holdings);
|
||||
this.autoCompleteList.next(this.holdings.filter(holding => holding.toLowerCase().indexOf(text) != -1));
|
||||
}
|
||||
|
||||
@timer
|
||||
upload(fileList: FileList) {
|
||||
// Because we enabled uploading multiple fileNames at once we need to process each one individually
|
||||
@ -74,5 +86,20 @@ export class AppComponent {
|
||||
});
|
||||
}
|
||||
|
||||
updateGraph(holding?: string) {
|
||||
if(holding) {
|
||||
this.graphHoldings.push(holding);
|
||||
this.holdingInput.nativeElement.value = '';
|
||||
}
|
||||
|
||||
// Take the merged data set and get everything ready for it to be charted
|
||||
this.chartResults = Object.keys(this.mergedData)
|
||||
.filter(key => this.graphHoldings.indexOf(key) != -1)
|
||||
.map(key => ({
|
||||
name: key,
|
||||
series: this.mergedData[key].map((val, i) => ({name: i, value: val}))
|
||||
}));
|
||||
}
|
||||
|
||||
format(text) { return `${text} %`}
|
||||
}
|
||||
|
@ -1,20 +1,33 @@
|
||||
import {BrowserModule} from '@angular/platform-browser';
|
||||
import {NgModule} from '@angular/core';
|
||||
import {AppComponent} from './app.component';
|
||||
import {MatButtonModule, MatChipsModule, MatIconModule, MatToolbarModule} from '@angular/material';
|
||||
import {
|
||||
MatAutocompleteModule,
|
||||
MatButtonModule,
|
||||
MatChipsModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatToolbarModule
|
||||
} from '@angular/material';
|
||||
import {NgxChartsModule} from '@swimlane/ngx-charts';
|
||||
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent
|
||||
],
|
||||
declarations: [AppComponent],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
BrowserModule,
|
||||
FormsModule,
|
||||
MatAutocompleteModule,
|
||||
MatButtonModule,
|
||||
MatChipsModule,
|
||||
MatFormFieldModule,
|
||||
MatIconModule,
|
||||
MatInputModule,
|
||||
MatSelectModule,
|
||||
MatToolbarModule,
|
||||
NgxChartsModule,
|
||||
],
|
||||
|
@ -10,6 +10,14 @@ html, body {
|
||||
font-family: 'Archivo', sans-serif;
|
||||
}
|
||||
|
||||
.content-height {
|
||||
height: calc(100vh - 64px);
|
||||
}
|
||||
|
||||
.w-50 {
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
// Bootstrap overrides
|
||||
.text-muted {
|
||||
color: #bbbbbb !important;
|
||||
|
Loading…
Reference in New Issue
Block a user