Some final touches Issue #4

* Wrap tables in mat cards
* Add accidents legend
* Adjust table column names
* Some CSS adjustments
This commit is contained in:
Marcel Schwarz 2021-01-11 22:21:56 +01:00
parent 47d53ecc54
commit 1545ce1a78
9 changed files with 178 additions and 104 deletions

View File

@ -9,6 +9,9 @@
</mat-card-header> </mat-card-header>
<mat-card-content> <mat-card-content>
<div *ngIf="isLoading" class="col d-flex align-items-center justify-content-center">
<mat-progress-spinner color="primary" mode="indeterminate" [diameter]="300"></mat-progress-spinner>
</div>
<div *ngIf="!isLoading" class="station-dashboard-borrow-time"> <div *ngIf="!isLoading" class="station-dashboard-borrow-time">
<apx-chart <apx-chart
[chart]="chartOptions.chart" [chart]="chartOptions.chart"
@ -20,10 +23,8 @@
[stroke]="chartOptions.stroke" [stroke]="chartOptions.stroke"
[tooltip]="chartOptions.tooltip" [tooltip]="chartOptions.tooltip"
[xaxis]="chartOptions.xaxis" [xaxis]="chartOptions.xaxis"
[yaxis]="chartOptions.yaxis"></apx-chart> [yaxis]="chartOptions.yaxis">
</div> </apx-chart>
<div *ngIf="isLoading" class="col d-flex align-items-center justify-content-center">
<mat-progress-spinner color="primary" mode="indeterminate" [diameter]="300"></mat-progress-spinner>
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

View File

@ -151,12 +151,11 @@ export class RentTimeChartComponent implements OnInit {
} }
}; };
}); });
} }
async onSubmit(actualStartDate: string, actualEndDate: string): Promise<void> { async onSubmit(actualStartDate: string, actualEndDate: string): Promise<void> {
this.isLoading = true; this.isLoading = true;
await this.service.fetchDashboardStationCharts( this.service.fetchDashboardStationCharts(
this.bikePoint.id, this.bikePoint.id,
actualStartDate, actualStartDate,
actualEndDate, actualEndDate,

View File

@ -1,5 +1,14 @@
<div class="row"> <div class="row">
<div class="col-lg-6 col-md-12 mb-md-3 mb-sm-3 mb-3"> <div class="col-lg-6 col-md-12 mb-md-3 mb-sm-3 mb-3">
<mat-card>
<mat-card-header>
<mat-card-title>Top-3 rental destination</mat-card-title>
<mat-card-subtitle>
This table shows the top-3 destinations of rentals from this station by number of drives.
The Station can be sent to the map with the checkbox.
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<table [dataSource]="stationToSource" class="mat-elevation-z0 w-100" mat-table> <table [dataSource]="stationToSource" class="mat-elevation-z0 w-100" mat-table>
<ng-container matColumnDef="select"> <ng-container matColumnDef="select">
<th *matHeaderCellDef mat-header-cell></th> <th *matHeaderCellDef mat-header-cell></th>
@ -14,24 +23,24 @@
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="endStationName"> <ng-container matColumnDef="endStationName">
<th *matHeaderCellDef mat-header-cell> station of rental destination</th> <th *matHeaderCellDef mat-header-cell>Destination</th>
<td *matCellDef="let element" mat-cell> <td *matCellDef="let element" mat-cell>
<a [routerLink]="['/dashboard/', element.stationId]">{{element.stationName}}</a> <a [routerLink]="['/dashboard/', element.stationId]">{{element.stationName}}</a>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="number"> <ng-container matColumnDef="number">
<th *matHeaderCellDef mat-header-cell> number of drives</th> <th *matHeaderCellDef mat-header-cell>Count</th>
<td *matCellDef="let element" mat-cell> {{element.number}} </td> <td *matCellDef="let element" mat-cell> {{element.number}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="avgDuration"> <ng-container matColumnDef="avgDuration">
<th *matHeaderCellDef mat-header-cell> average rental duration</th> <th *matHeaderCellDef mat-header-cell>Average duration</th>
<td *matCellDef="let element" mat-cell> {{humanizeAvgDuration(element.avgDuration)}} </td> <td *matCellDef="let element" mat-cell> {{humanizeAvgDuration(element.avgDuration)}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="marker"> <ng-container matColumnDef="marker">
<th *matHeaderCellDef mat-header-cell> icon on map</th> <th *matHeaderCellDef mat-header-cell>Icon</th>
<td *matCellDef="let element" mat-cell><img [src]="drawIconInTable(element)" alt="marker"></td> <td *matCellDef="let element" mat-cell><img [src]="drawIconInTable(element)" alt="marker"></td>
</ng-container> </ng-container>
@ -41,8 +50,19 @@
<div *ngIf="isLoadingToSource" class="col d-flex align-items-center justify-content-center"> <div *ngIf="isLoadingToSource" class="col d-flex align-items-center justify-content-center">
<mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner> <mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner>
</div> </div>
</mat-card-content>
</mat-card>
</div> </div>
<div class="col-lg-6 col-md-12"> <div class="col-lg-6 col-md-12">
<mat-card>
<mat-card-header>
<mat-card-title>Top-3 rental origin</mat-card-title>
<mat-card-subtitle>
This table shows the top-3 origins of rentals to this station by number of drives.
The Station can be sent to the map with the checkbox.
</mat-card-subtitle>
</mat-card-header>
<mat-card-content>
<table [dataSource]="stationFromSource" class="mat-elevation-z0 w-100" mat-table> <table [dataSource]="stationFromSource" class="mat-elevation-z0 w-100" mat-table>
<ng-container matColumnDef="select"> <ng-container matColumnDef="select">
<th *matHeaderCellDef mat-header-cell></th> <th *matHeaderCellDef mat-header-cell></th>
@ -57,24 +77,24 @@
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="startStationName"> <ng-container matColumnDef="startStationName">
<th *matHeaderCellDef mat-header-cell> station of rental origin</th> <th *matHeaderCellDef mat-header-cell>Origin</th>
<td *matCellDef="let element" mat-cell> <td *matCellDef="let element" mat-cell>
<a [routerLink]="['/dashboard/', element.stationId]"> {{element.stationName}}</a> <a [routerLink]="['/dashboard/', element.stationId]"> {{element.stationName}}</a>
</td> </td>
</ng-container> </ng-container>
<ng-container matColumnDef="number"> <ng-container matColumnDef="number">
<th *matHeaderCellDef mat-header-cell> number of drives</th> <th *matHeaderCellDef mat-header-cell>Count</th>
<td *matCellDef="let element" mat-cell> {{element.number}} </td> <td *matCellDef="let element" mat-cell> {{element.number}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="avgDuration"> <ng-container matColumnDef="avgDuration">
<th *matHeaderCellDef mat-header-cell> average rental duration</th> <th *matHeaderCellDef mat-header-cell>Average duration</th>
<td *matCellDef="let element" mat-cell> {{humanizeAvgDuration(element.avgDuration)}} </td> <td *matCellDef="let element" mat-cell> {{humanizeAvgDuration(element.avgDuration)}} </td>
</ng-container> </ng-container>
<ng-container matColumnDef="marker"> <ng-container matColumnDef="marker">
<th *matHeaderCellDef mat-header-cell> icon on map</th> <th *matHeaderCellDef mat-header-cell>Icon</th>
<td *matCellDef="let element" mat-cell><img [src]="drawIconInTable(element)" alt="marker"></td> <td *matCellDef="let element" mat-cell><img [src]="drawIconInTable(element)" alt="marker"></td>
</ng-container> </ng-container>
@ -84,5 +104,7 @@
<div *ngIf="isLoadingFromSource" class="col d-flex align-items-center justify-content-center"> <div *ngIf="isLoadingFromSource" class="col d-flex align-items-center justify-content-center">
<mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner> <mat-progress-spinner color="primary" mode="indeterminate"></mat-progress-spinner>
</div> </div>
</mat-card-content>
</mat-card>
</div> </div>
</div> </div>

View File

@ -10,3 +10,8 @@ a {
.mat-checkbox-layout label { .mat-checkbox-layout label {
margin: 0 !important; margin: 0 !important;
} }
.mat-cell, .mat-header-cell {
padding-left: 8px;
padding-right: 8px;
}

View File

@ -8,7 +8,7 @@
<mat-card-content class="p-4 d-flex flex-column justify-content-center"> <mat-card-content class="p-4 d-flex flex-column justify-content-center">
<div> <div>
<p>Select a range to analyze data</p> <p>Select a range to analyze data</p>
<form [formGroup]="form" class="d-flex flex-row align-items-center justify-content-between"> <form [formGroup]="form" class="d-flex flex-row justify-content-between">
<mat-form-field appearance="fill"> <mat-form-field appearance="fill">
<mat-label>Enter a range</mat-label> <mat-label>Enter a range</mat-label>
<mat-date-range-input [max]="maxEndDate" [min]="maxStartDate" [rangePicker]="picker" <mat-date-range-input [max]="maxEndDate" [min]="maxStartDate" [rangePicker]="picker"
@ -20,7 +20,7 @@
<mat-date-range-picker #picker></mat-date-range-picker> <mat-date-range-picker #picker></mat-date-range-picker>
</mat-form-field> </mat-form-field>
<button (click)="onSubmit()" class="mt-n3" color="primary" mat-raised-button> <button (click)="onSubmit()" class="mt-n3" color="primary" mat-raised-button>
<mat-icon>dashboard</mat-icon> <mat-icon>cached</mat-icon>
reload reload
</button> </button>
</form> </form>

View File

@ -52,7 +52,7 @@ export const PICK_FORMATS = {
class PickDateAdapter extends NativeDateAdapter { class PickDateAdapter extends NativeDateAdapter {
format(date: Date, displayFormat: Object): string { format(date: Date, displayFormat: Object): string {
if (displayFormat === 'input') { if (displayFormat === 'input') {
return formatDate(date, 'dd-MM-yyyy', this.locale); return formatDate(date, 'dd.MM.yyyy', this.locale);
} else { } else {
return date.toDateString(); return date.toDateString();
} }

View File

@ -7,7 +7,6 @@ import {environment} from '../../environments/environment';
import {PopUpService} from './pop-up.service'; import {PopUpService} from './pop-up.service';
import {IMapBikePoint} from './domain/map-bike-point'; import {IMapBikePoint} from './domain/map-bike-point';
import {IDashboardCommonBikePoint} from './domain/dashboard-common-bike-point'; import {IDashboardCommonBikePoint} from './domain/dashboard-common-bike-point';
import {writeErrorToLogFile} from "@angular/cli/utilities/log-file";
const createIcon = color => L.icon({ const createIcon = color => L.icon({
@ -34,6 +33,7 @@ export class MapService {
dashBoardBikePoint: IDashboardCommonBikePoint; dashBoardBikePoint: IDashboardCommonBikePoint;
layerControl = L.control(null); layerControl = L.control(null);
legend = L.control({position: 'bottomleft'}); legend = L.control({position: 'bottomleft'});
accidentLegend = L.control({position: 'bottomleft'});
constructor( constructor(
private client: HttpClient, private client: HttpClient,
@ -66,6 +66,32 @@ export class MapService {
maxZoom: 19, maxZoom: 19,
preferCanvas: true preferCanvas: true
})); }));
this.accidentLegend.onAdd = () => {
const getCircle = (color) => {
return `
<svg height="16" width="16">
<circle cx="8" cy="8" r="8" stroke="black" stroke-width="1" fill=${color} />
</svg>`;
};
const div = L.DomUtil.create('div', 'legend legend-accidents');
div.innerHTML = `
<h4>Accident severities</h4>
<div>
${getCircle('yellow')}<span>Slight accident</span>
</div>
<div>
${getCircle('orange')}<span>Severe accident</span>
</div>
<div>
${getCircle('red')}<span>Fatal accident</span>
</div>
`;
return div;
};
this.map.on('overlayadd', e => e.name === 'Accidents' ? this.accidentLegend.addTo(this.map) : null);
this.map.on('overlayremove', e => e.name === 'Accidents' ? this.accidentLegend.remove() : null);
} }
public initDashboardMap(lat: number, lon: number, zoom: number): void { public initDashboardMap(lat: number, lon: number, zoom: number): void {

View File

@ -1,3 +1,4 @@
.button-wiki:hover { .button-wiki:hover {
background: #086ed2; background: #086ed2;
text-decoration: none;
} }

View File

@ -29,28 +29,48 @@ label.mat-checkbox-layout {
background: rgba(255, 255, 255, 0.8); background: rgba(255, 255, 255, 0.8);
line-height: 24px; line-height: 24px;
color: #555; color: #555;
}
.legend h4 { h4 {
text-align: center; text-align: center;
font-size: 16px; font-size: 16px;
margin: 2px 12px 8px; margin: 2px 12px 8px;
color: #777; color: #777;
} }
.legend span { span {
position: relative; position: relative;
bottom: 3px; bottom: 3px;
} }
.legend i { i {
width: 18px; width: 18px;
height: 3px; height: 3px;
float: left; float: left;
margin: 7px 8px 0 0; margin: 7px 8px 0 0;
opacity: 0.7; opacity: 0.7;
}
.legend i.icon { .icon {
background-size: 18px; background-size: 18px;
background-color: rgba(255, 255, 255, 1); background-color: rgba(255, 255, 255, 1);
} }
}
}
.legend-accidents {
background: rgb(57, 57, 57);
color: white;
h4 {
color: white;
}
div {
display: flex;
justify-content: left;
align-items: baseline;
svg {
margin-right: 8px;
}
}
}