WIP: add dynamic generation of marker if check-box in table is pressed

* fix: both use the same array -> delete if uncheck
This commit is contained in:
tim-herbst 2020-12-29 14:36:59 +01:00
parent a597343b0c
commit bba88ac1aa
14 changed files with 160 additions and 26 deletions

View File

@ -26,6 +26,7 @@ import {MatInputModule} from '@angular/material/input';
import {MatTableModule} from '@angular/material/table';
import {AutoRefreshComponent} from './map/auto-refresh/auto-refresh.component';
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
import {MatCheckboxModule} from '@angular/material/checkbox';
@NgModule({
declarations: [
@ -57,7 +58,8 @@ import {MatSlideToggleModule} from '@angular/material/slide-toggle';
ReactiveFormsModule,
MatInputModule,
MatTableModule,
MatSlideToggleModule
MatSlideToggleModule,
MatCheckboxModule
],
providers: [],
bootstrap: [AppComponent]

View File

@ -75,13 +75,22 @@
</mat-card>
</div>
<div class="container-table" fxFlex fxLayout="row" fxLayoutAlign="center">
<div class="dashboard-table-to" fxFlex>
<table [dataSource]="stationToSource" class="mat-elevation-z8" fxFill mat-table>
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selectRowTo($event, row) : null"
[checked]="selectionTo.isSelected(row)"
[aria-label]="checkboxLabelTo(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="endStationName">
<th *matHeaderCellDef mat-header-cell> station of lend destination</th>
<td *matCellDef="let element" mat-cell><a
<td *matCellDef="let element" mat-cell><a [style.color]="getColorTo(element)"
[routerLink]="['/dashboard/', element.stationId]">{{element.stationName}}</a></td>
</ng-container>
@ -101,9 +110,19 @@
</div>
<div class="dashboard-table-from" fxFlex>
<table [dataSource]="stationFromSource" class="mat-elevation-z9" fxFill mat-table>
<ng-container matColumnDef="select">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let row">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? selectRowFrom($event, row) : null"
[checked]="selectionFrom.isSelected(row)"
[aria-label]="checkboxLabelFrom(row)">
</mat-checkbox>
</td>
</ng-container>
<ng-container matColumnDef="startStationName">
<th *matHeaderCellDef mat-header-cell> station of lend origin</th>
<td *matCellDef="let element" mat-cell><a
<td *matCellDef="let element" mat-cell><a [style.color]="getColorFrom(element)"
[routerLink]="['/dashboard/', element.stationId]"> {{element.stationName}}</a></td>
</ng-container>

View File

@ -6,12 +6,9 @@ mat-sidenav-content {
flex: 1 1 auto;
}
a {
color: #017bfe;
}
.button-back:hover, .button-wiki:hover {
background: #086ed2;
}
.submit-date {
@ -31,7 +28,7 @@ a {
margin-top: 1em;
margin-left: 1em;
margin-bottom: 1em;
background-image: url('../../assets/bike-point.png');
background-image: url('../../assets/bike-point-blue.png');
background-size: cover;
}

View File

@ -24,6 +24,8 @@ import {
ChartComponent
} from 'ng-apexcharts';
import {IMapBikePoint} from '../service/domain/map-bike-point';
import {SelectionModel} from '@angular/cdk/collections';
import {MatCheckboxChange} from '@angular/material/checkbox';
export type ChartOptions = {
title: ApexTitleSubtitle
@ -54,10 +56,12 @@ export class DashboardComponent implements OnInit {
public durationChartOptions: Partial<ChartOptions>;
public timeChartOptions: Partial<ChartOptions>;
public bikePointChartOptions: Partial<ChartOptions>;
displayedColumnsTo: string[] = ['endStationName', 'number', 'avgDuration'];
displayedColumnsFrom: string[] = ['startStationName', 'number', 'avgDuration'];
stationToSource = new MatTableDataSource<any>();
displayedColumnsTo: string[] = ['select', 'endStationName', 'number', 'avgDuration'];
displayedColumnsFrom: string[] = ['select', 'startStationName', 'number', 'avgDuration'];
stationToSource = new MatTableDataSource<IDashboardCommonBikePoint>();
selectionTo = new SelectionModel<any>(true, []);
stationFromSource = new MatTableDataSource<any>();
selectionFrom = new SelectionModel<any>(true, []);
station: IDashboardCommonBikePoint;
maxStartDate: Date;
@ -67,6 +71,7 @@ export class DashboardComponent implements OnInit {
form: FormGroup;
bikePoint: IMapBikePoint;
bikePointWithColor = [];
constructor(
private route: ActivatedRoute,
@ -205,15 +210,15 @@ export class DashboardComponent implements OnInit {
}
initDashboard(): void {
async initDashboard(): Promise<any> {
const initDate = this.maxEndDate.toISOString().substring(0, 10);
this.form.get('daterange').get('start').setValue(initDate);
this.form.get('daterange').get('end').setValue(initDate);
this.service.fetchDashboardStationTo(this.station.id, initDate, initDate).then((source) => {
await this.service.fetchDashboardStationTo(this.station.id, initDate, initDate).then((source) => {
this.stationToSource = source;
this.changeDetectorRefs.detectChanges();
});
this.service.fetchDashboardStationFrom(this.station.id, initDate, initDate).then((source) => {
await this.service.fetchDashboardStationFrom(this.station.id, initDate, initDate).then((source) => {
this.stationFromSource = source;
this.changeDetectorRefs.detectChanges();
});
@ -323,16 +328,16 @@ export class DashboardComponent implements OnInit {
text: 'amount of drives',
},
}, {
opposite: true,
title: {
text: 'average Duration'
},
opposite: true,
title: {
text: 'average Duration'
},
labels: {
formatter: (val: number): string => {
return val + ' min';
}
}
}],
}],
legend: {
horizontalAlign: 'left'
},
@ -495,4 +500,98 @@ export class DashboardComponent implements OnInit {
humanizeAvgDuration(avgDuration: number): string {
return stht(avgDuration);
}
isToAllSelected(): boolean {
const numSelected = this.selectionTo.selected.length;
const numRows = this.stationToSource.data.length;
return numSelected === numRows;
}
isFromAllSelected(): boolean {
const numSelected = this.selectionFrom.selected.length;
const numRows = this.stationFromSource.data.length;
return numSelected === numRows;
}
checkboxLabelTo(row?: any): string {
if (!row) {
return `${this.isToAllSelected() ? 'select' : 'deselect'} all`;
}
return `${this.selectionTo.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;
}
checkboxLabelFrom(row?: any): string {
if (!row) {
return `${this.isFromAllSelected() ? 'select' : 'deselect'} all`;
}
return `${this.selectionFrom.isSelected(row) ? 'deselect' : 'select'} row ${row.position + 1}`;
}
selectRowTo(selection: MatCheckboxChange, row): void {
this.selectionTo.toggle(row);
this.selectionTo.selected.forEach(point => {
if (point.stationId === row.stationId) {
point.color = this.getColorTo(row);
}
this.bikePointWithColor.push(point);
});
this.map.drawTableStationMarker(this.bikePointWithColor);
}
selectRowFrom(selection: MatCheckboxChange, row): void {
this.selectionFrom.toggle(row);
this.selectionFrom.selected.forEach(point => {
if (point.stationId === row.stationId) {
point.color = this.getColorFrom(row);
}
this.bikePointWithColor.push(point);
});
this.map.drawTableStationMarker(this.bikePointWithColor);
}
getColorTo(value): string {
switch (value.stationName) {
case this.stationToSource[0].stationName:
if (this.stationToSource[0].stationName === this.station.commonName) {
return 'blue';
} else {
return 'black';
}
case this.stationToSource[1].stationName:
if (this.stationToSource[1].stationName === this.station.commonName) {
return 'blue';
} else {
return 'red';
}
case this.stationToSource[2].stationName:
if (this.stationToSource[2].stationName === this.station.commonName) {
return 'blue';
} else {
return 'green';
}
}
}
getColorFrom(value): string {
switch (value.stationName) {
case this.stationFromSource[0].stationName:
if (this.stationFromSource[0].stationName === this.station.commonName) {
return 'blue';
} else {
return 'orange';
}
case this.stationFromSource[1].stationName:
if (this.stationFromSource[1].stationName === this.station.commonName) {
return 'blue';
} else {
return 'purple';
}
case this.stationFromSource[2].stationName:
if (this.stationFromSource[2].stationName === this.station.commonName) {
return 'blue';
} else {
return 'gray';
}
}
}
}

View File

@ -1,6 +1,5 @@
import {Component, OnInit} from '@angular/core';
import {MapService} from '../service/map.service';
import {BehaviorSubject, Observable, of, Subject} from 'rxjs';
@Component({
@ -25,7 +24,7 @@ export class MapComponent implements OnInit {
console.log(this.isRefreshActive);
}
async initMapView(): Promise<any> {
async initMapView(): Promise<any> {
this.service.initMap(51.509865, -0.118092, 14);
await this.service.drawStationMarkers();
this.service.drawHeatmap();

View File

@ -1,5 +1,6 @@
export interface IDashboardCommonBikePoint {
id?: string;
color?: string;
commonName?: string;
lat?: number;
lon?: number;
@ -10,6 +11,7 @@ export interface IDashboardCommonBikePoint {
export class DashboardCommonBikePoint implements IDashboardCommonBikePoint {
constructor(
public id?: string,
public color?: string,
public commonName?: string,
public lat?: number,
public lon?: number,

View File

@ -9,8 +9,8 @@ import {IMapBikePoint} from './domain/map-bike-point';
import {Observable, Subject} from 'rxjs';
const createIcon = L.icon({
iconUrl: '../../assets/bike-point.png',
const createIcon = color => L.icon({
iconUrl: `../../assets/bike-point-${color}.png`,
iconSize: [45, 45],
iconAnchor: [21, 40],
popupAnchor: [1, -35]
@ -27,6 +27,9 @@ export class MapService {
public miniMap;
bikePoints: Array<IMapBikePoint> = [];
mapOverlays: any = {};
miniMapMarker: L.layerGroup;
markerLayer = [];
dashBoardMarker = L.marker;
constructor(
private client: HttpClient,
@ -78,7 +81,7 @@ export class MapService {
this.mapOverlays.Bikepoints = markerClusters;
this.map.addLayer(markerClusters);
for (const station of data) {
const marker = L.marker([station.lat, station.lon], {icon: createIcon});
const marker = L.marker([station.lat, station.lon], {icon: createIcon('blue')});
markerClusters.addLayer(marker);
marker.on('click', e => {
e.target.bindPopup(this.popUpService.makeAvailabilityPopUp(station), {maxWidth: 'auto'})
@ -137,7 +140,20 @@ export class MapService {
}
public drawDashboardStationMarker(lat: number, lon: number): void {
L.marker([lat, lon], {icon: createIcon}).addTo(this.miniMap);
this.dashBoardMarker = L.marker([lat, lon], {icon: createIcon('blue')}).addTo(this.miniMap);
}
public drawTableStationMarker(bikePoints: any[]): void {
if (this.markerLayer) {
this.markerLayer.forEach(marker => {
this.miniMap.removeLayer(marker);
});
}
for (const point of bikePoints) {
const marker = L.marker([point.stationLat, point.stationLon], {icon: createIcon(point.color)}).addTo(this.miniMap);
this.markerLayer.push(marker);
this.miniMap.fitBounds(L.featureGroup([...this.markerLayer, this.dashBoardMarker]).getBounds());
}
}
private drawMapControl(): void {

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 76 KiB