Select what ETF's you would like to use

This commit is contained in:
Zakary Timson 2018-11-29 21:39:13 -05:00
parent deb5251b5a
commit 37a8889a9d
4 changed files with 101 additions and 26 deletions

View File

@ -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
<!-- 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"
[xAxisTickFormatting]="format">
</ngx-charts-bar-horizontal-2d>
[yAxisTickFormatting]="format">
</ngx-charts-bar-vertical-2d>
</div>
<input #fileUploader type="file" accept="text/csv" multiple hidden (change)="upload(fileUploader.files)">

View File

@ -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} %`}
}

View File

@ -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,
],

View File

@ -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;