working on dashboard

* borrow-duration is fix
* to and from is fix
* map-load with marker is fix

missing: dashboard-chart-borrow-time
This commit is contained in:
Tim Herbst 2020-12-22 22:49:26 +01:00
parent 8dd31f3703
commit 678272ef8a
7 changed files with 308 additions and 76 deletions

View File

@ -18,23 +18,40 @@
</mat-toolbar>
<mat-sidenav-container class="sidenav-container">
<mat-sidenav #sidenav class="sidenav" mode="side" opened role="region">
<mat-form-field appearance="fill" class="datepicker-start" fxLayout="column" fxLayoutAlign="center center">
<mat-label>Start der Zeitmessung</mat-label>
<input (dateChange)="addStartDate('input', $event)"
[matDatepicker]="picker" [max]="maxEndDate"
[min]="maxStartDate" matInput>
<mat-datepicker-toggle [for]="picker" matSuffix></mat-datepicker-toggle>
<mat-datepicker #picker></mat-datepicker>
</mat-form-field>
<mat-form-field appearance="fill" class="datepicker-end" fxLayout="column" fxLayoutAlign="center center">
<mat-label>Ende der Zeitmessung</mat-label>
<input (dateChange)="addEndDate('input', $event)"
[matDatepicker]="picker1" [max]="maxEndDate" [min]="maxStartDate" matInput>
<mat-datepicker-toggle [for]="picker1" matSuffix></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
<form [formGroup]="form">
<mat-form-field appearance="fill" class="datepicker" fxLayout="column" fxLayoutAlign="center center">
<mat-label>Enter a range</mat-label>
<mat-date-range-input [max]="maxEndDate" [min]="maxStartDate" [rangePicker]="picker" formGroupName="daterange">
<input formControlName="start" matStartDate placeholder="Start date">
<input formControlName="end" matEndDate placeholder="End date">
</mat-date-range-input>
<mat-datepicker-toggle [for]="picker" matSuffix></mat-datepicker-toggle>
<mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field>
</form>
<div class="submit-date" fxLayout="row" fxLayoutAlign="center">
<button (click)="onSubmit()" color="primary" mat-raised-button>
<mat-icon>dashboard</mat-icon>
<span id="submit-date-span"> reload dashboard</span>
</button>
</div>
</mat-sidenav>
<mat-sidenav-content>
<div class="container containter-map"
fxLayout
fxLayout.xs="column"
fxLayoutAlign="center"
fxLayoutGap="10px"
fxLayoutGap.xs="0"
>
<div class="mini-map"
fxFlex
>
<div class="map-frame" fxFlex>
<div fxFill id="map"></div>
</div>
</div>
</div>
<div class="container container-top"
fxLayout
fxLayout.xs="column"
@ -43,32 +60,76 @@
fxLayoutGap.xs="0"
>
<div class="dashboard-table-to"
fxFlex="35%"
fxFlex="40%"
>
<table [dataSource]="stationToSource" class="mat-elevation-z8" fxFill mat-table>
<ng-container matColumnDef="endStationName">
<th *matHeaderCellDef mat-header-cell> station of lend destination</th>
<td *matCellDef="let element" mat-cell> {{element.endStationName}} </td>
</ng-container>
<ng-container matColumnDef="number">
<th *matHeaderCellDef mat-header-cell> number of drives</th>
<td *matCellDef="let element" mat-cell> {{element.number}} </td>
</ng-container>
<ng-container matColumnDef="avgDuration">
<th *matHeaderCellDef mat-header-cell> average Lend duration</th>
<td *matCellDef="let element" mat-cell> {{element.avgDuration}} </td>
</ng-container>
<tr *matHeaderRowDef="displayedColumnsTo" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumnsTo;" mat-row></tr>
</table>
</div>
<div class="dashboard-table-from"
fxFlex="35%"
fxFlex="40%"
>
dashboard-table-from
</div>
<div class="mini-map"
fxFlex
>
mini-map
<table [dataSource]="stationFromSource" class="mat-elevation-z9" fxFill mat-table>
<ng-container matColumnDef="startStationName">
<th *matHeaderCellDef mat-header-cell> station of lend origin</th>
<td *matCellDef="let element" mat-cell> {{element.startStationName}} </td>
</ng-container>
<ng-container matColumnDef="number">
<th *matHeaderCellDef mat-header-cell> number of drives</th>
<td *matCellDef="let element" mat-cell> {{element.number}} </td>
</ng-container>
<ng-container matColumnDef="avgDuration">
<th *matHeaderCellDef mat-header-cell> average lend duration</th>
<td *matCellDef="let element" mat-cell> {{element.avgDuration}} </td>
</ng-container>
<tr *matHeaderRowDef="displayedColumnsFrom" mat-header-row></tr>
<tr *matRowDef="let row; columns: displayedColumnsFrom;" mat-row></tr>
</table>
</div>
</div>
<div class="container container-middle"
fxLayout
fxLayout.xs="column"
fxLayoutAlign="center"
fxLayoutAlign="center center"
fxLayoutGap="10px"
fxLayoutGap.xs="0"
>
<div class="dashboard-chart-borrow-duration"
fxFlex
fxFlex="80%"
>
dashboard-chart-borrow-duration
<div id="Station-Dashboard-Borrow-Duration">
<apx-chart
[chart]="durationChartOptions.chart"
[dataLabels]="durationChartOptions.dataLabels"
[fill]="durationChartOptions.fill"
[legend]="durationChartOptions.legend"
[plotOptions]="durationChartOptions.plotOptions"
[series]="durationChartOptions.series"
[stroke]="durationChartOptions.stroke"
[xaxis]="durationChartOptions.xaxis"
[yaxis]="durationChartOptions.yaxis"
></apx-chart>
</div>
</div>
</div>
<div class="container container-bottom"

View File

@ -16,26 +16,28 @@ mat-sidenav-container, mat-sidenav-content, mat-sidenav {
background: #5a34a0;
}
#submit-date-span {
padding: 10px;
}
.button-wiki:hover {
background: #5a34a0;
}
.datepicker-start {
margin: 5px;
margin-top: 50px;
.datepicker {
margin-top: 100px;
}
.datepicker-end {
margin: 5px;
margin-top: 20px;
.containter-map {
height: 40vh;
}
.container-top {
height: 30vh;
height: 20vh;
}
.container-middle {
height: 30vh
height: 40vh
}
.container-bottom {
@ -44,22 +46,18 @@ mat-sidenav-container, mat-sidenav-content, mat-sidenav {
.dashboard-table-to {
margin: 5px;
background: gray;
}
.dashboard-table-from {
margin: 5px;
background: aquamarine;
}
.mini-map {
margin: 5px;
background: blueviolet;
}
.dashboard-chart-borrow-duration {
margin: 5px;
background: blue;
}
.dashboard-chart-borrow-time {

View File

@ -1,45 +1,218 @@
import {Component, OnInit} from '@angular/core';
import {ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, ViewChild} from '@angular/core';
import {ActivatedRoute} from '@angular/router';
import {DashboardService} from '../service/dashboard.service';
import {IDashboardCommonBikePoint} from '../service/domain/dashboard-common-bike-point';
import {MatDatepickerInputEvent} from '@angular/material/datepicker';
import {MatTableDataSource} from '@angular/material/table';
import {FormBuilder, FormControl, FormGroup} from '@angular/forms';
import {MapService} from '../service/map.service';
import {
ApexAxisChartSeries,
ApexChart,
ApexDataLabels,
ApexFill,
ApexLegend,
ApexNoData,
ApexPlotOptions,
ApexStroke,
ApexTooltip,
ApexXAxis,
ApexYAxis,
ChartComponent
} from 'ng-apexcharts';
export type ChartOptions = {
series: ApexAxisChartSeries;
chart: ApexChart;
dataLabels: ApexDataLabels;
plotOptions: ApexPlotOptions;
yaxis: ApexYAxis;
xaxis: ApexXAxis;
fill: ApexFill;
tooltip: ApexTooltip;
stroke: ApexStroke;
legend: ApexLegend;
noData: ApexNoData;
};
@Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.scss']
styleUrls: ['./dashboard.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class DashboardComponent implements OnInit {
@ViewChild('Station-Dashboard-Borrow-Duration') chart: ChartComponent;
public durationChartOptions: Partial<ChartOptions>;
displayedColumnsTo: string[] = ['endStationName', 'number', 'avgDuration'];
displayedColumnsFrom: string[] = ['startStationName', 'number', 'avgDuration'];
stationToSource = new MatTableDataSource<any>();
stationFromSource = new MatTableDataSource<any>();
station: IDashboardCommonBikePoint;
maxStartDate: Date;
maxEndDate: Date;
actualStartDate: Date;
actualEndDate: Date;
form: FormGroup;
constructor(
private route: ActivatedRoute,
public service: DashboardService
private service: DashboardService,
private map: MapService,
private changeDetectorRefs: ChangeDetectorRef,
private fb: FormBuilder
) {
this.durationChartOptions = {
series: [],
chart: {
type: 'bar'
},
dataLabels: {
enabled: false
},
noData: {
text: 'Loading...'
}
};
}
ngOnInit(): void {
this.service.initialDashboardStationFetch(this.route.snapshot.paramMap.get('id')).then(data => {
this.service.fetch_dashboard_init(this.route.snapshot.paramMap.get('id')).then(data => {
this.station = data;
this.maxStartDate = new Date(data.maxStartDate);
this.maxEndDate = new Date(data.maxEndDate);
console.log(data);
this.init_dashboard();
});
this.form = this.fb.group({
daterange: new FormGroup({
start: new FormControl(),
end: new FormControl()
})
});
}
addStartDate(type: string, event: MatDatepickerInputEvent<Date>): void {
this.actualStartDate = event.value;
console.log(this.actualStartDate);
init_dashboard(): void {
const initDate = this.maxEndDate.toISOString().substring(0, 10);
this.service.fetch_dashboard_station_to(this.station.id, initDate, initDate).then((source) => {
this.stationToSource = source;
this.changeDetectorRefs.detectChanges();
});
this.service.fetch_dashboard_station_from(this.station.id, initDate, initDate).then((source) => {
this.stationFromSource = source;
this.changeDetectorRefs.detectChanges();
});
this.service.fetch_dashboard_station_duration(this.station.id, initDate, initDate).then((source) => {
const numbers = [];
const minutesGroup = [];
source.forEach(value => {
numbers.push(value.number);
minutesGroup.push(value.minutesGroup);
});
this.durationChartOptions = {
series: [
{
name: 'borrow-duration',
data: [...numbers]
}
],
chart: {
type: 'bar',
height: 450
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '55%',
endingShape: 'rounded'
}
},
dataLabels: {
enabled: false
},
stroke: {
show: true,
width: 2,
colors: ['transparent']
},
xaxis: {
categories: [...minutesGroup]
},
yaxis: {
title: {
text: 'minutes'
}
},
fill: {
opacity: 1
}
};
});
this.map.init_map(this.station.lat, this.station.lon, 17);
this.map.draw_dashboard_station_marker(this.station.lat, this.station.lon);
}
addEndDate(type: string, event: MatDatepickerInputEvent<Date>): void {
this.actualEndDate = event.value;
console.log(this.actualEndDate);
}
onSubmit(): void {
this.actualStartDate = this.form.get('daterange').value.start;
this.actualEndDate = this.form.get('daterange').value.end;
this.service.fetch_dashboard_station_to(this.station.id, this.actualStartDate.toISOString().substring(0, 10), this.actualEndDate.toISOString().substring(0, 10)).then((source) => {
this.stationToSource = source;
this.changeDetectorRefs.detectChanges();
});
this.service.fetch_dashboard_station_from(this.station.id, this.actualStartDate.toISOString().substring(0, 10), this.actualStartDate.toISOString().substring(0, 10)).then((source) => {
this.stationFromSource = source;
this.changeDetectorRefs.detectChanges();
});
this.service.fetch_dashboard_station_duration(this.station.id, this.actualStartDate.toISOString().substring(0, 10), this.actualStartDate.toISOString().substring(0, 10)).then((source) => {
const numbers = [];
const minutesGroup = [];
source.forEach(value => {
numbers.push(value.number);
minutesGroup.push(value.minutesGroup);
});
this.durationChartOptions = {
series: [
{
name: 'borrow-duration',
data: [...numbers]
}
],
chart: {
type: 'bar',
height: 450
},
plotOptions: {
bar: {
horizontal: false,
columnWidth: '55%',
endingShape: 'rounded'
}
},
dataLabels: {
enabled: false
},
stroke: {
show: true,
width: 2,
colors: ['transparent']
},
xaxis: {
categories: [...minutesGroup]
},
yaxis: {
title: {
text: 'minutes'
}
},
fill: {
opacity: 1
}
};
});
}
}

View File

@ -13,8 +13,8 @@ export class MapComponent implements AfterViewInit {
}
ngAfterViewInit(): void {
this.service.initMap();
this.service.makeStationMarkers();
this.service.init_map(51.509865, -0.118092, 14);
this.service.make_station_markers();
}

View File

@ -10,7 +10,19 @@ export class DashboardService {
constructor(private client: HttpClient) {
}
public async initialDashboardStationFetch(id: string): Promise<any> {
return await this.client.get(environment.apiUrl + 'latest/dashboard/' + id + '/').toPromise();
public async fetch_dashboard_init(id: string): Promise<any> {
return await this.client.get(environment.apiUrl + `latest/dashboard/${id}/`).toPromise();
}
public async fetch_dashboard_station_to(id: string, startDate: string, endDate: string): Promise<any> {
return await this.client.get(environment.apiUrl + `latest/dashboard/${id}/to?start_date=${startDate}&end_date=${endDate}`).toPromise();
}
public async fetch_dashboard_station_from(id: string, startDate: string, endDate: string): Promise<any> {
return await this.client.get(environment.apiUrl + `latest/dashboard/${id}/from?start_date=${startDate}&end_date=${endDate}`).toPromise();
}
public async fetch_dashboard_station_duration(id: string, startDate: string, endDate: string): Promise<any> {
return await this.client.get(environment.apiUrl + `latest/dashboard/${id}/duration?start_date=${startDate}&end_date=${endDate}`).toPromise();
}
}

View File

@ -1,16 +0,0 @@
export interface IDashboardStationTo {
startStationName?: string;
endStationName?: string;
stationNumber?: number;
avgDuration?: number;
}
export class DashboardStationTo implements IDashboardStationTo {
constructor(
public startStationName?: string,
public endStationName?: string,
public stationNumber?: number,
public avgDuration?: number
) {
}
}

View File

@ -25,8 +25,8 @@ export class MapService {
) {
}
public initMap(): void {
this.map = L.map('map').setView([51.509865, -0.118092], 14);
public init_map(lat: number, lon: number, zoom: number): void {
this.map = L.map('map').setView([lat, lon], zoom);
this.map.addLayer(new L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: 'Map data <a href="https://openstreetmap.org">OpenStreetMap</a> contributors',
minZoom: 0,
@ -34,8 +34,8 @@ export class MapService {
}));
}
public makeStationMarkers(): void {
this.fetchStationGeoData().then((data) => {
public make_station_markers(): void {
this.fetch_station_geo_data().then((data) => {
const markerClusters = L.markerClusterGroup({
spiderflyOnMaxZoom: true,
showCoverageOnHover: true,
@ -56,8 +56,12 @@ export class MapService {
});
}
public draw_dashboard_station_marker(lat: number, lon: number): void {
L.marker([lat, lon], {icon: createIcon}).addTo(this.map);
}
private async fetchStationGeoData(): Promise<any> {
private async fetch_station_geo_data(): Promise<any> {
return await this.client.get(environment.apiUrl + 'latest/bikepoints/').toPromise();
}
}