Made it work
This commit is contained in:
parent
4f5f7cff72
commit
44cafb9fd9
@ -4,7 +4,7 @@ root = true
|
|||||||
[*]
|
[*]
|
||||||
charset = utf-8
|
charset = utf-8
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 4
|
||||||
insert_final_newline = true
|
insert_final_newline = true
|
||||||
trim_trailing_whitespace = true
|
trim_trailing_whitespace = true
|
||||||
|
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
<!--The content below is only a placeholder and can be replaced.-->
|
<!--The content below is only a placeholder and can be replaced.-->
|
||||||
<div style="text-align:center">
|
<mat-toolbar>
|
||||||
<h1>
|
<span>ETF Demo</span>
|
||||||
Welcome to {{ title }}!
|
<span class="mx-auto"><!-- Spacer --></span>
|
||||||
</h1>
|
<button mat-button (click)="fileUploader.click()">
|
||||||
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
|
<mat-icon>add</mat-icon>
|
||||||
|
Upload
|
||||||
|
</button>
|
||||||
|
</mat-toolbar>
|
||||||
|
<div *ngIf="chartResults" class="w-100" [style.height]="chartHeight">
|
||||||
|
<ngx-charts-bar-horizontal-2d #chart
|
||||||
|
[results]="chartResults"
|
||||||
|
[xAxis]="true"
|
||||||
|
[yAxis]="true"
|
||||||
|
[yAxisTickFormatting]="format">
|
||||||
|
</ngx-charts-bar-horizontal-2d>
|
||||||
</div>
|
</div>
|
||||||
<h2>Here are some links to help you start: </h2>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h2><a target="_blank" rel="noopener" href="https://angular.io/cli">CLI Documentation</a></h2>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
|
<input #fileUploader type="file" accept="text/csv" multiple hidden (change)="upload(fileUploader.files)">
|
||||||
|
@ -1,31 +0,0 @@
|
|||||||
import { TestBed, async } from '@angular/core/testing';
|
|
||||||
import { AppComponent } from './app.component';
|
|
||||||
|
|
||||||
describe('AppComponent', () => {
|
|
||||||
beforeEach(async(() => {
|
|
||||||
TestBed.configureTestingModule({
|
|
||||||
declarations: [
|
|
||||||
AppComponent
|
|
||||||
],
|
|
||||||
}).compileComponents();
|
|
||||||
}));
|
|
||||||
|
|
||||||
it('should create the app', () => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.debugElement.componentInstance;
|
|
||||||
expect(app).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`should have as title 'ETFDemo'`, () => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
const app = fixture.debugElement.componentInstance;
|
|
||||||
expect(app.title).toEqual('ETFDemo');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render title in a h1 tag', () => {
|
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
|
||||||
fixture.detectChanges();
|
|
||||||
const compiled = fixture.debugElement.nativeElement;
|
|
||||||
expect(compiled.querySelector('h1').textContent).toContain('Welcome to ETFDemo!');
|
|
||||||
});
|
|
||||||
});
|
|
@ -2,9 +2,51 @@ import { Component } from '@angular/core';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html'
|
||||||
styleUrls: ['./app.component.scss']
|
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {
|
||||||
title = 'ETFDemo';
|
chartResults; // This is where the chart reads the data from
|
||||||
|
chartHeight = '100%';
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
get data() { return this._data; }
|
||||||
|
set data(data) {
|
||||||
|
this._data = data;
|
||||||
|
this.chartHeight = `${Object.keys(data).length * 100}px`;
|
||||||
|
this.chartResults = Object.keys(data).map(key => ({name: key, series: data[key].map((val, i) => ({name: i, value: val}))}));
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor() { }
|
||||||
|
|
||||||
|
upload(fileList: FileList) {
|
||||||
|
// Because we enabled uploading multiple files at once we need to process each one individually
|
||||||
|
const files: File[] = Array.from(fileList);
|
||||||
|
files.forEach(file => {
|
||||||
|
// Process CSV
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = (e: ProgressEvent) => {
|
||||||
|
// Split the file into lines
|
||||||
|
const lines = ((<FileReader>e.target).result as string).split('\n');
|
||||||
|
|
||||||
|
// Use regex to grab the holding name and its % market value
|
||||||
|
this.data = lines.map(text => {
|
||||||
|
const parse = /^(.+),.+?(\d+\.\d+)%/gm.exec(text);
|
||||||
|
if(parse) return parse.slice(1);
|
||||||
|
}).reduce((acc, line) => {
|
||||||
|
// The regex will turn lines that don't match into null values so lets filter those out here
|
||||||
|
if(!line) return acc;
|
||||||
|
|
||||||
|
// Add the parsed data into our data set
|
||||||
|
if(!acc[line[0]]) acc[line[0]] = [];
|
||||||
|
acc[line[0]].push(Number(line[1]));
|
||||||
|
|
||||||
|
return acc;
|
||||||
|
}, this.data || {});
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
format(text) { return `${text} %`}
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,24 @@
|
|||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {NgModule} from '@angular/core';
|
import {NgModule} from '@angular/core';
|
||||||
|
|
||||||
import {AppComponent} from './app.component';
|
import {AppComponent} from './app.component';
|
||||||
|
import {MatButtonModule, MatIconModule, MatToolbarModule} from '@angular/material';
|
||||||
|
import {NgxChartsModule} from '@swimlane/ngx-charts';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
AppComponent
|
AppComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
BrowserModule
|
BrowserAnimationsModule,
|
||||||
|
BrowserModule,
|
||||||
|
MatButtonModule,
|
||||||
|
MatIconModule,
|
||||||
|
MatToolbarModule,
|
||||||
|
NgxChartsModule,
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
})
|
})
|
||||||
export class AppModule { }
|
export class AppModule {
|
||||||
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||||
|
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" rel="stylesheet">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
|
@ -1 +1,11 @@
|
|||||||
/* You can add global styles to this file, and also import other style files */
|
@import url('https://fonts.googleapis.com/css?family=Archivo|Material+Icons');
|
||||||
|
@import "~@angular/material/prebuilt-themes/indigo-pink.css";
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
font-family: 'Archivo', sans-serif;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user