diff --git a/projects/project-3/frontend/src/app/dashboard/dashboard.component.scss b/projects/project-3/frontend/src/app/dashboard/dashboard.component.scss
index ffb5e9f..6a0acba 100644
--- a/projects/project-3/frontend/src/app/dashboard/dashboard.component.scss
+++ b/projects/project-3/frontend/src/app/dashboard/dashboard.component.scss
@@ -6,14 +6,6 @@ mat-sidenav-content {
flex: 1 1 auto;
}
-a {
- color: black;
-}
-
-img {
- width: 60px;
-}
-
.button-back:hover, .button-wiki:hover {
background: #086ed2;
}
@@ -53,7 +45,6 @@ img {
margin-left: 39px;
}
-
.container-map {
height: 40em;
margin: 1em 2em;
@@ -64,14 +55,6 @@ img {
margin: 1em 3em;
}
-.dashboard-table-to {
- margin-right: 1em;
-}
-
-.dashboard-table-from {
- margin-left: 1em;
-}
-
.container-borrow-duration {
height: 41em;
margin: 1em 2em;
diff --git a/projects/project-3/frontend/src/app/dashboard/dashboard.component.ts b/projects/project-3/frontend/src/app/dashboard/dashboard.component.ts
index fd838da..e7344df 100644
--- a/projects/project-3/frontend/src/app/dashboard/dashboard.component.ts
+++ b/projects/project-3/frontend/src/app/dashboard/dashboard.component.ts
@@ -2,10 +2,8 @@ import {ChangeDetectionStrategy, ChangeDetectorRef, Component, Injectable, OnIni
import {ActivatedRoute, Router} from '@angular/router';
import {DashboardService} from '../service/dashboard.service';
import {IDashboardCommonBikePoint} from '../service/domain/dashboard-common-bike-point';
-import {MatTableDataSource} from '@angular/material/table';
import {FormBuilder, FormControl, FormGroup} from '@angular/forms';
import {MapService} from '../service/map.service';
-import stht from 'seconds-to-human-time';
import {
@@ -20,14 +18,13 @@ import {
ApexTitleSubtitle,
ApexTooltip,
ApexXAxis,
- ApexYAxis,
- ChartComponent
+ ApexYAxis
} from 'ng-apexcharts';
import {IMapBikePoint} from '../service/domain/map-bike-point';
-import {SelectionModel} from '@angular/cdk/collections';
-import {MatCheckboxChange} from '@angular/material/checkbox';
import {DateAdapter, MAT_DATE_FORMATS, NativeDateAdapter} from '@angular/material/core';
import {formatDate} from '@angular/common';
+import {TableComponent} from './table/table.component';
+import {RentDurationChartComponent} from "./rent-duration-chart/rent-duration-chart.component";
export type ChartOptions = {
title: ApexTitleSubtitle;
@@ -80,19 +77,12 @@ const chartHeight = 460;
]
})
export class DashboardComponent implements OnInit {
- @ViewChild('Station-Dashboard-Borrow-Duration') chart: ChartComponent;
+ @ViewChild(TableComponent) table: TableComponent;
+ @ViewChild(RentDurationChartComponent) durationChart: RentDurationChartComponent;
+
public durationChartOptions: Partial
;
public timeChartOptions: Partial;
public bikePointChartOptions: Partial;
- displayedColumnsTo: string[] = ['select', 'endStationName', 'number', 'avgDuration', 'marker'];
- displayedColumnsFrom: string[] = ['select', 'startStationName', 'number', 'avgDuration', 'marker'];
- stationToSource = new MatTableDataSource();
- iterableToSource: any[];
- stationFromSource = new MatTableDataSource();
- iterableFromSource: any[];
- selectionModel = new SelectionModel(true, []);
- colors = ['black', 'gray', 'green', 'orange', 'purple', 'red'];
- isLoading: boolean;
station: IDashboardCommonBikePoint;
maxStartDate: Date;
@@ -138,7 +128,6 @@ export class DashboardComponent implements OnInit {
text: 'Loading...'
}
};
- this.isLoading = true;
}
ngOnInit(): void {
@@ -151,8 +140,6 @@ export class DashboardComponent implements OnInit {
this.changeDetectorRefs.detectChanges();
this.map.removeTableStationMarkerOnReload();
this.route.params.subscribe(params => {
- this.selectionModel.clear();
- this.colors = ['black', 'gray', 'green', 'orange', 'purple', 'red'];
this.service.fetchDashboardInit(params.id).then(data => {
this.station = data;
this.maxStartDate = new Date(data.maxStartDate);
@@ -254,18 +241,6 @@ export class DashboardComponent implements OnInit {
const initDate = this.maxEndDate.toISOString().substring(0, 10);
this.form.get('daterange').get('start').setValue(initDate);
this.form.get('daterange').get('end').setValue(initDate);
- await this.service.fetchDashboardStationTo(this.station.id, initDate, initDate).then((source) => {
- this.stationToSource = this.setBikePointColorToSource(source);
- this.iterableToSource = source;
- this.isLoading = false;
- this.changeDetectorRefs.detectChanges();
- });
- await this.service.fetchDashboardStationFrom(this.station.id, initDate, initDate).then((source) => {
- this.stationFromSource = this.setBikePointColorFromSource(source);
- this.iterableFromSource = source;
- this.isLoading = false;
- this.changeDetectorRefs.detectChanges();
- });
this.service.fetchDashboardStationCharts(this.station.id, initDate, initDate, 'duration').then((source) => {
const numbers = [];
const minutesGroup = [];
@@ -404,232 +379,17 @@ export class DashboardComponent implements OnInit {
}
async onSubmit(): Promise {
- this.isLoading = false;
this.actualStartDate = this.form.get('daterange').value.start;
this.actualEndDate = this.form.get('daterange').value.end;
- this.map.removeTableStationMarkerOnReload();
- this.selectionModel.clear();
- await this.service.fetchDashboardStationTo(
- this.station.id,
+ this.table.onSubmit(
this.actualStartDate.toISOString().substring(0, 10),
this.actualEndDate.toISOString().substring(0, 10)
- ).then((source) => {
- this.colors = ['black', 'gray', 'green', 'orange', 'purple', 'red'];
- this.stationToSource = this.setBikePointColorToSource(source);
- this.iterableToSource = source;
- this.isLoading = false;
- this.changeDetectorRefs.detectChanges();
- });
- await this.service.fetchDashboardStationFrom(
- this.station.id,
+ );
+ this.durationChart.onSubmit(
this.actualStartDate.toISOString().substring(0, 10),
this.actualEndDate.toISOString().substring(0, 10)
- ).then((source) => {
- this.stationFromSource = this.setBikePointColorFromSource(source);
- this.iterableFromSource = source;
- this.isLoading = false;
- this.changeDetectorRefs.detectChanges();
- });
- this.service.fetchDashboardStationCharts(
- this.station.id,
- this.actualStartDate.toISOString().substring(0, 10),
- this.actualEndDate.toISOString().substring(0, 10),
- 'duration'
- ).then((source) => {
- const numbers = [];
- const minutesGroup = [];
- source.forEach(value => {
- numbers.push(value.number);
- minutesGroup.push(value.minutesGroup);
- });
- this.durationChartOptions = {
- series: [
- {
- name: 'amount of drives for given borrow duration',
- data: numbers
- }
- ],
- chart: {
- type: 'bar',
- height: chartHeight
- },
- colors: ['#017bfe'],
- plotOptions: {
- bar: {
- horizontal: false,
- columnWidth: '55%',
- endingShape: 'flat'
- }
- },
- dataLabels: {
- enabled: false
- },
- stroke: {
- show: true,
- width: 2,
- colors: ['transparent']
- },
- xaxis: {
- title: {
- text: 'average rental duration'
- },
- categories: minutesGroup,
- labels: {
- formatter: value => {
- return value + ' min';
- }
- }
- },
- yaxis: {
- title: {
- text: 'amount of drives'
- }
- },
- fill: {
- opacity: 1
- }
- };
- });
- this.service.fetchDashboardStationCharts(
- this.station.id,
- this.actualStartDate.toISOString().substring(0, 10),
- this.actualEndDate.toISOString().substring(0, 10),
- 'time'
- ).then((source) => {
- const timeFrame = [];
- const numbers = [];
- const avgDuration = [];
- source.forEach(value => {
- timeFrame.push(value.timeFrame);
- numbers.push(value.number);
- avgDuration.push(Math.round(value.avgDuration / 60));
- });
- this.timeChartOptions = {
- series: [
- {
- name: 'amount of drives',
- type: 'bar',
- data: numbers
- },
- {
- name: 'average rental duration',
- type: 'line',
- data: avgDuration
- }
- ],
- chart: {
- toolbar: {
- show: false
- },
- type: 'line',
- height: chartHeight,
- zoom: {
- enabled: true,
- }
- },
- colors: ['#017bfe', '#51ca49'],
- dataLabels: {
- enabled: false
- },
- stroke: {
- curve: 'straight'
- },
- xaxis: {
- title: {
- text: 'time of the day'
- },
- categories: timeFrame,
- tickAmount: 24,
- tickPlacement: 'between'
- },
- yaxis: [{
- title: {
- text: 'amount of drives',
- },
- }, {
- opposite: true,
- title: {
- text: 'average rental duration'
- },
- labels: {
- formatter: (val: number): string => {
- return val + ' min';
- }
- }
- }],
- legend: {
- horizontalAlign: 'left'
- },
- fill: {
- opacity: 1
- }
- };
- });
+ );
}
- humanizeAvgDuration(avgDuration: number): string {
- return stht(avgDuration);
- }
- selectRow(selection: MatCheckboxChange, row): void {
- const markerToDisplay = [];
- this.iterableToSource.forEach(point => {
- if (point.stationId === row.stationId) {
- this.selectionModel.toggle(point);
- }
- });
- this.iterableFromSource.forEach(point => {
- if (point.stationId === row.stationId) {
- this.selectionModel.toggle(point);
- }
- });
- this.selectionModel.selected.forEach(point => {
- markerToDisplay.push(point);
- });
- this.map.drawTableStationMarker(markerToDisplay);
- }
-
- public drawIconInTable(bikePoint: any): string {
- return `../../assets/bike-point-${bikePoint.color}.png`;
- }
-
- setBikePointColorToSource(source): any {
- for (const station of source) {
- if (station.stationId === this.station.id) {
- station.color = 'blue';
- continue;
- }
- station.color = this.getRandomColor();
- }
- return source;
- }
-
- setBikePointColorFromSource(source): any {
- for (const station of source) {
- if (station.stationId === this.station.id) {
- station.color = 'blue';
- continue;
- }
- for (const to of this.iterableToSource) {
- if (station.stationId === to.stationId) {
- station.color = to.color;
- break;
- }
- }
- if (!station.color) {
- station.color = this.getRandomColor();
- }
- }
- return source;
- }
-
- getRandomColor(): string {
- const color = this.colors[Math.floor(Math.random() * this.colors.length)];
- this.colors = this.colors.filter(c => c !== color);
- return color;
- }
-
- isCheckBoxDisable(row): boolean {
- return row.stationId === this.station.id;
- }
}
diff --git a/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.html b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.html
new file mode 100644
index 0000000..2141b1d
--- /dev/null
+++ b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.html
@@ -0,0 +1,24 @@
+
+
+ Rental Duration
+
+ This chart shows the rent duration based on the currently selected station.
+ The time it takes for a rent which has the current station as origin is displayed here.
+
+
+
+
+
+
diff --git a/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.scss b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.scss
new file mode 100644
index 0000000..dd9f823
--- /dev/null
+++ b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.scss
@@ -0,0 +1,17 @@
+.station-dashboard-borrow-duration {
+ margin: 1em;
+}
+
+.mat-card {
+ padding: 1px 1px 1px;
+ margin: 10px;
+}
+
+.mat-card-title {
+ margin-top: 1em;
+ margin-left: 2em;
+}
+
+.mat-card-subtitle {
+ margin-left: 39px;
+}
diff --git a/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.spec.ts b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.spec.ts
new file mode 100644
index 0000000..9bdd08a
--- /dev/null
+++ b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.spec.ts
@@ -0,0 +1,25 @@
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RentDurationChartComponent } from './rent-duration-chart.component';
+
+describe('RentDurationChartComponent', () => {
+ let component: RentDurationChartComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [ RentDurationChartComponent ]
+ })
+ .compileComponents();
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RentDurationChartComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.ts b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.ts
new file mode 100644
index 0000000..041a59b
--- /dev/null
+++ b/projects/project-3/frontend/src/app/dashboard/rent-duration-chart/rent-duration-chart.component.ts
@@ -0,0 +1,149 @@
+import {Component, OnInit, ViewChild} from '@angular/core';
+import {
+ ApexAxisChartSeries,
+ ApexChart,
+ ApexDataLabels,
+ ApexFill,
+ ApexLegend,
+ ApexNoData,
+ ApexPlotOptions,
+ ApexStroke,
+ ApexTitleSubtitle,
+ ApexTooltip,
+ ApexXAxis,
+ ApexYAxis,
+ ChartComponent
+} from 'ng-apexcharts';
+import {ActivatedRoute} from '@angular/router';
+import {DashboardService} from '../../service/dashboard.service';
+import {IDashboardCommonBikePoint} from '../../service/domain/dashboard-common-bike-point';
+
+export type ChartOptions = {
+ title: ApexTitleSubtitle;
+ subtitle: ApexTitleSubtitle;
+ series: ApexAxisChartSeries;
+ chart: ApexChart;
+ colors: string[];
+ dataLabels: ApexDataLabels;
+ plotOptions: ApexPlotOptions;
+ yaxis: ApexYAxis;
+ xaxis: ApexXAxis;
+ fill: ApexFill;
+ tooltip: ApexTooltip;
+ stroke: ApexStroke;
+ legend: ApexLegend;
+ noData: ApexNoData;
+};
+
+const chartType = 'duration';
+
+@Component({
+ selector: 'app-rent-duration-chart',
+ templateUrl: './rent-duration-chart.component.html',
+ styleUrls: ['./rent-duration-chart.component.scss']
+})
+export class RentDurationChartComponent implements OnInit {
+ @ViewChild(ChartComponent) chart: ChartComponent;
+ chartOptions: Partial;
+
+ bikePoint: IDashboardCommonBikePoint;
+ maxStartDate: Date;
+ maxEndDate: Date;
+
+ constructor(
+ private route: ActivatedRoute,
+ private service: DashboardService,
+ ) {
+ this.chartOptions = {
+ series: [],
+ chart: {
+ type: 'bar'
+ },
+ noData: {
+ text: 'Loading...'
+ }
+ };
+ }
+
+ ngOnInit(): void {
+ this.route.params.subscribe(params => {
+ this.service.fetchDashboardInit(params.id).then(data => {
+ this.bikePoint = data;
+ this.maxStartDate = new Date(data.maxStartDate);
+ this.maxEndDate = new Date(data.maxEndDate);
+ this.initChart();
+ });
+ });
+ }
+
+ async initChart(): Promise {
+ const initDate = this.maxEndDate.toISOString().substring(0, 10);
+ await this.service.fetchDashboardStationCharts(this.bikePoint.id, initDate, initDate, chartType).then(source => {
+ this.chartOptions = {
+ series: [
+ {
+ name: 'amount of drives',
+ data: source.map(value => value.number)
+ }
+ ],
+ chart: {
+ type: 'bar',
+ height: '460'
+ },
+ colors: ['#017bfe'],
+ plotOptions: {
+ bar: {
+ horizontal: false,
+ columnWidth: '55%',
+ endingShape: 'flat'
+ }
+ },
+ dataLabels: {
+ enabled: false
+ },
+ stroke: {
+ show: true,
+ width: 2,
+ colors: ['transparent']
+ },
+ xaxis: {
+ title: {
+ text: 'average rental duration'
+ },
+ categories: source.map(value => value.minutesGroup),
+ labels: {
+ formatter: value => {
+ return value + ' min';
+ }
+ }
+ },
+ yaxis: {
+ title: {
+ text: 'amount of drives'
+ }
+ },
+ noData: {
+ text: 'loading'
+ },
+ fill: {
+ opacity: 1
+ }
+ };
+ this.chart.updateOptions(this.chartOptions);
+ });
+ }
+
+ async onSubmit(actualStartDate: string, actualEndDate: string): Promise {
+ await this.service.fetchDashboardStationCharts(
+ this.bikePoint.id,
+ actualStartDate,
+ actualEndDate,
+ chartType
+ ).then(source => {
+ this.chart.updateSeries([{
+ data: source.map(value => value.number)
+ }]);
+ });
+ }
+
+}