add popup-component and dashboard-component for futher implementation
* add apex-chart dependency
This commit is contained in:
parent
3eb3570370
commit
6698381f85
92
projects/project-3/frontend/package-lock.json
generated
92
projects/project-3/frontend/package-lock.json
generated
@ -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",
|
||||
|
@ -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"
|
||||
|
@ -1 +1 @@
|
||||
<app-map></app-map>
|
||||
<router-outlet></router-outlet>
|
||||
|
@ -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]
|
||||
|
@ -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>
|
@ -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;
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
@ -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) {}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
<p>{{station.commonName}}</p><br>
|
||||
<button mat-raised-button color="primary" (click)="route()">ROUTE</button>
|
@ -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();
|
||||
});
|
||||
});
|
@ -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]);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
});
|
||||
});
|
114
projects/project-3/frontend/src/app/service/pop-up.service.ts
Normal file
114
projects/project-3/frontend/src/app/service/pop-up.service.ts
Normal 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
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user