Select what ETF's you would like to use
This commit is contained in:
		@@ -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;
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user