add popup-component and dashboard-component for futher implementation

* add apex-chart dependency
This commit is contained in:
tim-herbst 2020-12-20 17:26:10 +01:00 committed by Tim Herbst
parent 3eb3570370
commit 6698381f85
14 changed files with 410 additions and 4 deletions

View File

@ -2145,6 +2145,19 @@
"picomatch": "^2.0.4"
}
},
"apexcharts": {
"version": "3.23.0",
"resolved": "https://registry.npmjs.org/apexcharts/-/apexcharts-3.23.0.tgz",
"integrity": "sha512-1mV6qouuopvYR6UFSXi/Ge4jRMe//zyAN3aK05mAs4Iuet8mA0w31Q6OU6syD77bawt9p3YKNOmNF7OO2u9w0g==",
"requires": {
"svg.draggable.js": "^2.2.2",
"svg.easing.js": "^2.0.0",
"svg.filter.js": "^2.0.2",
"svg.pathmorphing.js": "^0.1.3",
"svg.resize.js": "^1.4.3",
"svg.select.js": "^3.0.1"
}
},
"app-root-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/app-root-path/-/app-root-path-3.0.0.tgz",
@ -7885,6 +7898,21 @@
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
"dev": true
},
"ng-apexcharts": {
"version": "1.5.6",
"resolved": "https://registry.npmjs.org/ng-apexcharts/-/ng-apexcharts-1.5.6.tgz",
"integrity": "sha512-78vmZvrT9iqfZXE00+T8NTvR+EHV0wo4qqf0Zfu1/2KiwazCU9S5EROcmgqMQ1eCO7Sz4GiR19rLTMdtWL/WmQ==",
"requires": {
"tslib": "^1.10.0"
},
"dependencies": {
"tslib": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz",
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
}
}
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
@ -11892,6 +11920,70 @@
"has-flag": "^3.0.0"
}
},
"svg.draggable.js": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz",
"integrity": "sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==",
"requires": {
"svg.js": "^2.0.1"
}
},
"svg.easing.js": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/svg.easing.js/-/svg.easing.js-2.0.0.tgz",
"integrity": "sha1-iqmUawqOJ4V6XEChDrpAkeVpHxI=",
"requires": {
"svg.js": ">=2.3.x"
}
},
"svg.filter.js": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/svg.filter.js/-/svg.filter.js-2.0.2.tgz",
"integrity": "sha1-kQCOFROJ3ZIwd5/L5uLJo2LRwgM=",
"requires": {
"svg.js": "^2.2.5"
}
},
"svg.js": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/svg.js/-/svg.js-2.7.1.tgz",
"integrity": "sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA=="
},
"svg.pathmorphing.js": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz",
"integrity": "sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==",
"requires": {
"svg.js": "^2.4.0"
}
},
"svg.resize.js": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/svg.resize.js/-/svg.resize.js-1.4.3.tgz",
"integrity": "sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==",
"requires": {
"svg.js": "^2.6.5",
"svg.select.js": "^2.1.2"
},
"dependencies": {
"svg.select.js": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-2.1.2.tgz",
"integrity": "sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==",
"requires": {
"svg.js": "^2.2.5"
}
}
}
},
"svg.select.js": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/svg.select.js/-/svg.select.js-3.0.1.tgz",
"integrity": "sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==",
"requires": {
"svg.js": "^2.6.5"
}
},
"svgo": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/svgo/-/svgo-1.3.2.tgz",

View File

@ -22,8 +22,10 @@
"@angular/platform-browser": "~10.2.0",
"@angular/platform-browser-dynamic": "~10.2.0",
"@angular/router": "~10.2.0",
"apexcharts": "^3.23.0",
"leaflet": "^1.7.1",
"leaflet.markercluster": "^1.4.1",
"ng-apexcharts": "^1.5.6",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.10.2"

View File

@ -1 +1 @@
<app-map></app-map>
<router-outlet></router-outlet>

View File

@ -10,13 +10,20 @@ import {FlexLayoutModule} from '@angular/flex-layout';
import {MatIconModule} from '@angular/material/icon';
import {MatButtonModule} from '@angular/material/button';
import {HttpClientModule} from '@angular/common/http';
import { PopupComponent } from './map/popup/popup.component';
import {NgApexchartsModule} from 'ng-apexcharts';
import {DashboardComponent} from './dashboard/dashboard.component';
import {MatGridListModule} from '@angular/material/grid-list';
import {MatCardModule} from '@angular/material/card';
import {MatMenuModule} from '@angular/material/menu';
import {LayoutModule} from '@angular/cdk/layout';
import {PopUpComponent} from './map/pop-up/pop-up.component';
@NgModule({
declarations: [
AppComponent,
MapComponent,
PopupComponent
DashboardComponent,
PopUpComponent
],
imports: [
BrowserModule,
@ -26,7 +33,12 @@ import { PopupComponent } from './map/popup/popup.component';
MatIconModule,
MatButtonModule,
FlexLayoutModule,
HttpClientModule
HttpClientModule,
NgApexchartsModule,
MatGridListModule,
MatCardModule,
MatMenuModule,
LayoutModule
],
providers: [],
bootstrap: [AppComponent]

View File

@ -0,0 +1,24 @@
<div class="grid-container">
<h1 class="mat-h1">Dashboard</h1>
<mat-grid-list cols="2" rowHeight="350px">
<mat-grid-tile *ngFor="let card of cards | async" [colspan]="card.cols" [rowspan]="card.rows">
<mat-card class="dashboard-card">
<mat-card-header>
<mat-card-title>
{{card.title}}
<button mat-icon-button class="more-button" [matMenuTriggerFor]="menu" aria-label="Toggle menu">
<mat-icon>more_vert</mat-icon>
</button>
<mat-menu #menu="matMenu" xPosition="before">
<button mat-menu-item>Expand</button>
<button mat-menu-item>Remove</button>
</mat-menu>
</mat-card-title>
</mat-card-header>
<mat-card-content class="dashboard-card-content">
<div>Card Content Here</div>
</mat-card-content>
</mat-card>
</mat-grid-tile>
</mat-grid-list>
</div>

View File

@ -0,0 +1,21 @@
.grid-container {
margin: 20px;
}
.dashboard-card {
position: absolute;
top: 15px;
left: 15px;
right: 15px;
bottom: 15px;
}
.more-button {
position: absolute;
top: 5px;
right: 10px;
}
.dashboard-card-content {
text-align: center;
}

View File

@ -0,0 +1,40 @@
import { LayoutModule } from '@angular/cdk/layout';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MatButtonModule } from '@angular/material/button';
import { MatCardModule } from '@angular/material/card';
import { MatGridListModule } from '@angular/material/grid-list';
import { MatIconModule } from '@angular/material/icon';
import { MatMenuModule } from '@angular/material/menu';
import { DashboardComponent } from './dashboard.component';
describe('DashboardComponent', () => {
let component: DashboardComponent;
let fixture: ComponentFixture<DashboardComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DashboardComponent],
imports: [
NoopAnimationsModule,
LayoutModule,
MatButtonModule,
MatCardModule,
MatGridListModule,
MatIconModule,
MatMenuModule,
]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DashboardComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should compile', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,33 @@
import { Component } from '@angular/core';
import { map } from 'rxjs/operators';
import { Breakpoints, BreakpointObserver } from '@angular/cdk/layout';
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent {
/** Based on the screen size, switch from standard to one column per row */
cards = this.breakpointObserver.observe(Breakpoints.Handset).pipe(
map(({ matches }) => {
if (matches) {
return [
{ title: 'Card 1', cols: 1, rows: 1 },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 1 },
{ title: 'Card 4', cols: 1, rows: 1 }
];
}
return [
{ title: 'Card 1', cols: 2, rows: 1 },
{ title: 'Card 2', cols: 1, rows: 1 },
{ title: 'Card 3', cols: 1, rows: 2 },
{ title: 'Card 4', cols: 1, rows: 1 }
];
})
);
constructor(private breakpointObserver: BreakpointObserver) {}
}

View File

@ -0,0 +1,2 @@
<p>{{station.commonName}}</p><br>
<button mat-raised-button color="primary" (click)="route()">ROUTE</button>

View File

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { PopUpComponent } from './pop-up.component';
describe('PopUpComponent', () => {
let component: PopUpComponent;
let fixture: ComponentFixture<PopUpComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PopUpComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(PopUpComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,25 @@
import {Component, OnInit} from '@angular/core';
import {IBikeStation} from '../../service/domain/bike-station';
import {Router} from '@angular/router';
@Component({
selector: 'app-pop-up',
templateUrl: './pop-up.component.html',
styleUrls: ['./pop-up.component.scss']
})
export class PopUpComponent implements OnInit {
text = 'test';
station: IBikeStation;
constructor(private router: Router) {
}
ngOnInit(): void {
this.text = 'test';
}
public route(): void {
this.router.navigate(['/dashboard', this.station.id]);
}
}

View File

@ -0,0 +1,16 @@
import { TestBed } from '@angular/core/testing';
import { PopUpService } from './pop-up.service';
describe('PopUpService', () => {
let service: PopUpService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(PopUpService);
});
it('should be created', () => {
expect(service).toBeTruthy();
});
});

View File

@ -0,0 +1,114 @@
import {ComponentFactoryResolver, Injectable, Injector} from '@angular/core';
import {IBikeStation} from './domain/bike-station';
import {
ApexAxisChartSeries,
ApexChart,
ApexDataLabels,
ApexFill,
ApexLegend,
ApexPlotOptions,
ApexStroke,
ApexTitleSubtitle,
ApexXAxis
} from 'ng-apexcharts';
import {Router} from '@angular/router';
import {PopUpComponent} from '../map/pop-up/pop-up.component';
export type ChartOptions = {
series: ApexAxisChartSeries;
chart: ApexChart;
dataLabels: ApexDataLabels;
plotOptions: ApexPlotOptions;
xaxis: ApexXAxis;
stroke: ApexStroke;
title: ApexTitleSubtitle;
fill: ApexFill;
legend: ApexLegend;
};
@Injectable({
providedIn: 'root'
})
export class PopUpService {
public chartOptions: Partial<ChartOptions>;
constructor(
private router: Router,
private componentFactoryResolver: ComponentFactoryResolver,
private injector: Injector
) {
}
// <apx-chart
// [series]="chartOptions.series"
// [chart]="chartOptions.chart"
// [dataLabels]="chartOptions.dataLabels"
// [plotOptions]="chartOptions.plotOptions"
// [xaxis]="chartOptions.xaxis"
// [stroke]="chartOptions.stroke"
// [fill]="chartOptions.fill"
// [title]="chartOptions.title"
// [legend]="chartOptions.legend"></apx-chart>
makeAvailabilityPopUp(station: IBikeStation): any {
const factory = this.componentFactoryResolver.resolveComponentFactory(PopUpComponent);
const component = factory.create(this.injector);
component.instance.station = station;
component.changeDetectorRef.detectChanges();
return component.location.nativeElement;
}
route(station: IBikeStation): void {
this.router.navigate(['/dashboard', station.id]);
}
bindChartOptionsToGivenStation(station: IBikeStation): void {
this.chartOptions = {
series: [
{
name: 'wenig vorhanden',
data: [44, 55, 41, 37, 22, 43, 21]
},
{
name: 'moderat voll',
data: [53, 32, 33, 52, 13, 43, 32]
},
{
name: 'voll',
data: [12, 17, 11, 9, 15, 11, 20]
}
],
chart: {
type: 'bar',
height: 350,
stacked: true,
stackType: '100%'
},
plotOptions: {
bar: {
horizontal: true
}
},
stroke: {
width: 1,
colors: ['#fff']
},
title: {
text: 'Availability of Station: ' + station.commonName
},
xaxis: {
categories: []
},
fill: {
opacity: 1
},
legend: {
position: 'top',
horizontalAlign: 'left',
offsetX: 40
}
};
}
}