Mise à jours du dashboard

This commit is contained in:
Julien Gautier
2023-09-14 18:28:02 +02:00
parent 0e6b3ef1c7
commit 92b204c769
41 changed files with 981 additions and 852 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
<div class="container page auth-page">
<div class="container content auth-page">
<div class="row">
<div class="col-md-6 offset-md-3 col-xs-12">
<h1 class="text-xs-center">{{ title }}</h1>
@@ -50,6 +50,7 @@ export class AuthComponent implements OnInit, OnDestroy {
firstname: '',
lastname: '',
phone: '',
licence: '',
password: ['', Validators.required],
confirmPassword: ''
}, { validators: this.checkPasswords });
@@ -98,6 +99,7 @@ export class AuthComponent implements OnInit, OnDestroy {
this._user = user$.subscribe({
next: () => this.router.navigateByUrl('/'),
error: (err) => {
console.log(err);
this.errors = err;
this.isSubmitting = false;
}
@@ -49,7 +49,7 @@
<!-- Numero Column -->
<ng-container matColumnDef="weight">
<th mat-header-cell *matHeaderCellDef mat-sort-header class="{{tableHeader[0].active}}"> {{tableHeader[0].name}} </th>
<th mat-cell *matCellDef="let element;" class="text-right pl-3 pr-3">{{element.weight}}</th>
<th mat-cell *matCellDef="let element;" class="text-end pl-3 pr-3">{{element.weight}}</th>
</ng-container>
<!-- range_ Column -->
<ng-container matColumnDef="range_1">
@@ -3,8 +3,7 @@
<mat-card-title>Aéronefs</mat-card-title>
<mat-card-subtitle>Nombre total de sauts par avions</mat-card-subtitle>
<div class="barchrt">
<x-chartist class="" [data]="barChartAeronef.data" [type]="barChartAeronef.type" [options]="barChartAeronef.options" [responsiveOptions]="barChartAeronef.responsiveOptions"
[events]="barChartAeronef.events"> </x-chartist>
<x-chartist [configuration]="barChartAeronef"></x-chartist>
</div>
</mat-card-content>
<hr>
@@ -13,18 +12,18 @@
<thead>
<tr>
<th></th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-right"> {{name}} </th>
<th class="text-right">Total</th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{name}} </th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody class="text-mono">
<tbody class="font-monospace">
<tr *ngFor='let values of seriesRow; let i=index'>
<th class="{{seriesColor[i]}} text-right"><i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-right">
<th class="{{seriesColor[i]}} text-end"> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</td>
<th class="{{seriesColor[i]}} text-right">
<th class="{{seriesColor[i]}} text-end">
<span *ngIf="seriesValue[i]; else elseBlock" class="pr-1">{{seriesValue[i]}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{seriesValue[i]}}</span></ng-template>
</th>
@@ -1,10 +1,11 @@
import { Component, OnInit} from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { Observable, Subscription } from 'rxjs';
import { BackendService } from 'src/app/core/services';
import { ReduceRow } from 'src/app/core/models';
import { BackendService, AeronefsService } from 'src/app/core/services';
import { chartBar, AeronefByImat, AeronefByYear } from 'src/app/core/models';
@Component({
standalone: true,
@@ -12,117 +13,132 @@ import { ReduceRow } from 'src/app/core/models';
selector: 'huapp-aeronefs-bar',
templateUrl: './aeronefs-bar.component.html'
})
export class AeronefsBarComponent implements OnInit {
rows: Object[] = [] as Array<Object>;
export class AeronefsBarComponent implements OnInit, OnDestroy {
private _aeronefByImat: Subscription = new Subscription();
private _aeronefByYear: Subscription = new Subscription();
aeronefByImat!: Array<AeronefByImat>;
aeronefByYear!: Array<AeronefByYear>;
aeronefByImatCount = 0;
aeronefByYearCount = 0;
seriesName: string[] = [];
seriesValue: any[] = [];
seriesColor: string[] = this._dataService.getChartColors();
seriesHeader: string[] = [];
seriesRow: any[] = [];
barChartAeronef: Configuration = {
type: 'Bar',
data: {
"labels": [],
"series": []
},
options: {},
responsiveOptions: []
};
barChartAeronef: Configuration = chartBar;
constructor(private _dataService: BackendService) { }
loadDataByDate() {
return this._dataService
.getAeronefsByDate(2)
.subscribe((res) => {
this.seriesName.forEach((name: string) => {
this.seriesRow.push([0, 0, 0, 0, 0, 0]);
});
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
res["rows"].forEach((row: ReduceRow) => {
let year = row.key[1].toString();
let avion = row.key[0];
this.seriesRow[this.seriesName.indexOf(avion)][this.seriesHeader.indexOf(year)] = row.value;
});
return true;
});
}
constructor(
private aeronefsService: AeronefsService,
private _dataService: BackendService
) { }
ngOnInit() {
return this._dataService
.getAeronefs()
.subscribe((res) => {
this.rows = res["rows"]
this.rows.forEach((row: ReduceRow) => {
this.seriesName.push(row.key[0] + ' ' + row.key[1]);
this.seriesValue.push([row.value]);
});
this.barChartAeronef = {
type: 'Bar',
data: {
"labels": this.seriesName,
"series": this.seriesValue
this._loadAeronefByImat();
}
ngOnDestroy() {
this._aeronefByImat.unsubscribe();
this._aeronefByYear.unsubscribe();
}
private _loadAeronefByImat(): void {
const aeronefs$: Observable<Array<AeronefByImat>> = this.aeronefsService.getAllByImat();
this._aeronefByImat = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
this.aeronefByImat = aggregate;
this.aeronefByImatCount = aggregate.length;
this.aeronefByImat.forEach((row) => {
this.seriesName.push(`${row._id.aeronef} ${row._id.imat}`);
this.seriesValue.push(row.count);
});
this.barChartAeronef = {
type: 'Bar',
data: {
"labels": this.seriesName,
"series": this.seriesValue
},
options: {
chartPadding: {
top: 15,
right: 20,
bottom: 0,
left: 20
},
options: {
chartPadding: {
top: 15,
right: 20,
bottom: 0,
left: 20
seriesBarDistance: 15,
horizontalBars: true,
axisX: {
onlyInteger: true,
position: 'end',
labelOffset: {
x: 0,
y: 0
},
seriesBarDistance: 15,
horizontalBars: true,
showGrid: true,
offset: 20
},
axisY: {
showGrid: false,
offset: 0,
labelInterpolationFnc: function(): string {
return '';
}
},
height: (this.seriesName.length*20)
},
responsiveOptions: [
['screen and (min-width: 1024px)', {
axisX: {
position: 'end',
labelOffset: {
x: -5,
y: 0
},
showGrid: true,
labelInterpolationFnc: function(value: number, index: number): string {
return index % 1 === 0 ? `${value}` : '';
}
}
}],
['screen and (min-width: 641px) and (max-width: 1024px)', {
seriesBarDistance: 10,
axisY: {
offset: 30
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[2]}${value[3]}` : '';
}
}
}],
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisY: {
offset: 20
},
axisY: {
showGrid: false,
offset: 0,
labelInterpolationFnc: function(): string {
return '';
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[2]}${value[3]}` : '';
}
},
height: (this.seriesName.length*20)
},
responsiveOptions: [
['screen and (min-width: 1024px)', {
axisX: {
labelInterpolationFnc: function(value: number, index: number): string {
return index % 1 === 0 ? `${value}` : '';
}
}
}],
['screen and (min-width: 641px) and (max-width: 1024px)', {
seriesBarDistance: 10,
axisY: {
offset: 30
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[2]}${value[3]}` : '';
}
}
}],
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisY: {
offset: 20
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[2]}${value[3]}` : '';
}
}
}]
]
};
return this.loadDataByDate();
}
}]
]
};
this._loadAeronefByYear();
});
}
private _loadAeronefByYear(): void {
let values: Array<number> = [];
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
this.seriesHeader.forEach(() => {
values.push(0);
});
this.seriesName.forEach(() => {
this.seriesRow.push([...values]);
});
const dropzones$: Observable<Array<AeronefByYear>> = this.aeronefsService.getAllByDate();
this._aeronefByYear = dropzones$.subscribe((aggregate: Array<AeronefByYear>) => {
this.aeronefByYear = aggregate;
this.aeronefByYearCount = aggregate.length;
this.aeronefByYear.forEach((row: AeronefByYear) => {
let aeronef: string = row._id.aeronef;
let imat: string = row._id.imat;
let year: string = row._id.year.toString();
this.seriesRow[this.seriesName.indexOf(`${aeronef} ${imat}`)][this.seriesHeader.indexOf(year)] = row.count;
});
});
}
}
@@ -3,7 +3,7 @@
<mat-card-title>Aéronefs</mat-card-title>
<mat-card-subtitle>Nombre total de sauts par avions</mat-card-subtitle>
<div class="piechart">
<x-chartist [configuration]="donuteChartModel"> </x-chartist>
<x-chartist [configuration]="donuteAeronefs"></x-chartist>
</div>
</mat-card-content>
<hr>
@@ -12,18 +12,18 @@
<thead>
<tr>
<th></th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-right"> {{name}} </th>
<th class="text-right">Total</th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{name}} </th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let values of seriesRow; let i=index'>
<th class="{{seriesColor[i]}} text-right"><i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-mono text-right">
<th class="{{seriesColor[i]}} text-end"> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="font-monospace text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</td>
<th class="{{seriesColor[i]}} text-right">
<th class="{{seriesColor[i]}} text-end">
<span *ngIf="seriesValue[i]; else elseBlock" class="pr-1">{{seriesValue[i]}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{seriesValue[i]}}</span></ng-template>
</th>
@@ -1,11 +1,11 @@
import { Component, OnInit} from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { Observable, Subscription } from 'rxjs';
import { BackendService, AeronefsService, UserService } from 'src/app/core/services';
import { Aeronef, AeronefByImat } from 'src/app/core/models';
import { Aeronef, AeronefByImat, AeronefByYear, chartPieDonute } from 'src/app/core/models';
@Component({
standalone: true,
@@ -13,110 +13,49 @@ import { Aeronef, AeronefByImat } from 'src/app/core/models';
selector: 'huapp-aeronefs',
templateUrl: './aeronefs.component.html'
})
export class AeronefsComponent implements OnInit {
private _aeronefs: Subscription = new Subscription();
aggregate!: Array<AeronefByImat>
aeronefs!: Array<Aeronef>;
aeronefsCount = 0;
export class AeronefsComponent implements OnInit, OnDestroy {
private _aeronefByImat: Subscription = new Subscription();
private _aeronefByYear: Subscription = new Subscription();
aeronefByImat!: Array<AeronefByImat>;
aeronefByYear!: Array<AeronefByYear>;
aeronefByImatCount = 0;
aeronefByYearCount = 0;
rows: Object[] = [] as Array<Object>;
seriesName: string[] = [];//= ["Arcachon", "Béni-Mellal", "La Réole", "Royan", "Pamiers", "Soulac", "Sables d'Olonne", "Rochefort"];
seriesValue: number[] = [];
seriesColor: string[] = this._dataService.getChartColors(); //["blue", "red", "turquoise", "orange", "cyan", "purple-dark", "megna", "raspberry"];
seriesHeader: string[] = [];
seriesRow: any[] = [];
donuteChartModel: Configuration = {
type: 'Pie',
data: {
"labels": [],
"series": []
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 270,
showLabel: true
}
};
donuteAeronefs: Configuration = chartPieDonute;
constructor(
private aeronefsService: AeronefsService,
private _dataService: BackendService
) { }
/*loadDataByDate() {
return this._dataService
.getAeronefsByDate(2)
.subscribe((res) => {
this.seriesName.forEach((name: string) => {
this.seriesRow.push([0, 0, 0, 0, 0, 0]);
});
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
res["rows"].forEach((row: ReduceRow) => {
let year = row.key[1].toString();
let avion = row.key[0];
this.seriesRow[this.seriesName.indexOf(avion)][this.seriesHeader.indexOf(year)] = row.value;
});
return true;
});
}*/
ngOnInit() {
this.loadAeronefs();
return this._dataService
.getAeronefs()
.subscribe((res) => {
console.log(res);
/* this.rows = res["rows"]
var labels: string[] = [];
var series: number[] = [];
this.rows.forEach((row: ReduceRow) => {
this.seriesName.push(row.key[0] + ' ' + row.key[1]);
this.seriesValue.push(row.value);
//console.log(row.key, row.value);
labels.push(row.value.toString());
series.push(row.value);
});
this.donuteChartModel = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 270,
showLabel: true
}
//,
// events: <ChartEvent>{
// draw: (data) => {
// //this.donuteChartModel.data = data;
// console.log(data);
// }
// }
};
return this.loadDataByDate(); */
});
this._loadAeronefByImat();
}
loadAeronefs() {
ngOnDestroy() {
this._aeronefByImat.unsubscribe();
this._aeronefByYear.unsubscribe();
}
private _loadAeronefByImat(): void {
const aeronefs$: Observable<Array<AeronefByImat>> = this.aeronefsService.getAllByImat();
this._aeronefs = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
this.aggregate = aggregate;
this.aeronefsCount = aggregate.length;
this._aeronefByImat = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
this.aeronefByImat = aggregate;
this.aeronefByImatCount = aggregate.length;
var labels: string[] = [];
var series: number[] = [];
this.aggregate.forEach((row) => {
this.seriesName.push(row._id.aeronef + ' ' + row._id.imat);
this.aeronefByImat.forEach((row) => {
this.seriesName.push(`${row._id.aeronef} ${row._id.imat}`);
this.seriesValue.push(row.count);
labels.push(row.count.toString());
//labels.push(row._id.aeronef + ' ' + row._id.imat);
series.push(row.count);
});
this.donuteChartModel = {
this.donuteAeronefs = {
type: 'Pie',
data: {
"labels": labels,
@@ -130,6 +69,29 @@ export class AeronefsComponent implements OnInit {
showLabel: true
}
};
this._loadAeronefByYear();
});
}
private _loadAeronefByYear(): void {
let values: Array<number> = [];
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
this.seriesHeader.forEach(() => {
values.push(0);
});
this.seriesName.forEach(() => {
this.seriesRow.push([...values]);
});
const dropzones$: Observable<Array<AeronefByYear>> = this.aeronefsService.getAllByDate();
this._aeronefByYear = dropzones$.subscribe((aggregate: Array<AeronefByYear>) => {
this.aeronefByYear = aggregate;
this.aeronefByYearCount = aggregate.length;
this.aeronefByYear.forEach((row: AeronefByYear) => {
let aeronef: string = row._id.aeronef;
let imat: string = row._id.imat;
let year: string = row._id.year.toString();
this.seriesRow[this.seriesName.indexOf(`${aeronef} ${imat}`)][this.seriesHeader.indexOf(year)] = row.count;
});
});
}
}
@@ -3,7 +3,7 @@
<mat-card-title>Modèles de voile</mat-card-title>
<mat-card-subtitle>Nombre total de sauts par modèle</mat-card-subtitle>
<div class="piechart">
<x-chartist [configuration]="donuteCanopyModel"> </x-chartist>
<x-chartist [configuration]="donuteCanopies"></x-chartist>
</div>
</mat-card-content>
<hr>
@@ -12,18 +12,18 @@
<thead>
<tr>
<th></th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-right"> {{name}} </th>
<th class="text-right">Total</th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{name}} </th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody class="text-mono">
<tbody class="font-monospace">
<tr *ngFor='let values of seriesRow; let i=index'>
<th class="{{seriesColor[i]}} text-right"><i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-right">
<th class="{{seriesColor[i]}} text-end"> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</td>
<th class="{{seriesColor[i]}} text-right">
<th class="{{seriesColor[i]}} text-end">
<span *ngIf="seriesValue[i]; else elseBlock" class="pr-1">{{seriesValue[i]}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{seriesValue[i]}}</span></ng-template>
</th>
@@ -1,13 +1,12 @@
import { Component, OnInit} from '@angular/core';
import { Component, OnInit, OnDestroy} from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { Observable, Observer, Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { Observable, Subscription } from 'rxjs';
import { BackendService, CanopiesService } from 'src/app/core/services';
import { Canopy, CanopyBySize, ReduceRow } from 'src/app/core/models';
import { Canopy, CanopyModelBySize, CanopyModelByYear, chartPieDonute } from 'src/app/core/models';
@Component({
standalone: true,
@@ -15,106 +14,49 @@ import { Canopy, CanopyBySize, ReduceRow } from 'src/app/core/models';
selector: 'huapp-canopy-models',
templateUrl: './canopy-models.component.html'
})
export class CanopyModelsComponent implements OnInit {
private _canopies: Subscription = new Subscription();
aggregate!: Array<CanopyBySize>
canopies!: Array<Canopy>;
canopiesCount = 0;
export class CanopyModelsComponent implements OnInit, OnDestroy {
private _canopyBySize: Subscription = new Subscription();
private _canopyByYear: Subscription = new Subscription();
canopyBySize!: Array<CanopyModelBySize>;
canopyByYear!: Array<CanopyModelByYear>;
canopyBySizeCount = 0;
canopyByYearCount = 0;
rows: Object[] = [] as Array<Object>;
seriesName: string[] = [];
seriesValue: number[] = [];
seriesColor: string[] = this._dataService.getChartColors();
seriesHeader: string[] = [];
seriesRow: any[] = [];
donuteCanopyModel: Configuration = {
type: 'Pie',
data: {
"labels": [],
"series": []
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 270,
showLabel: true
}
};
donuteCanopies: Configuration = chartPieDonute;
constructor(
private canopiesService: CanopiesService,
private _dataService: BackendService
) { }
/*
loadDataByDate() {
return this._dataService
.getCanopyModelsByDate(2)
.subscribe((res) => {
this.seriesName.forEach((name: string) => {
this.seriesRow.push([0, 0, 0, 0, 0, 0]);
});
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
res["rows"].forEach((row: ReduceRow) => {
let year = row.key[1].toString();
let voile = row.key[0];
this.seriesRow[this.seriesName.indexOf(voile)][this.seriesHeader.indexOf(year)] = row.value;
});
return true;
});
}
*/
ngOnInit() {
this.loadCanopies();
/*
return this._dataService
.getCanopyModels()
.subscribe((res) => {
this.rows = res["rows"]
var labels: string[] = [];
var series: number[] = [];
this.rows.forEach((row: ReduceRow) => {
this.seriesName.push(row.key);
this.seriesValue.push(row.value);
labels.push(row.value.toString());
series.push(row.value);
});
this.donuteCanopyModel = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 40,
donutSolid: true,
startAngle: 270,
showLabel: true
}
};
return this.loadDataByDate();
});
*/
this._loadCanopyModelBySize();
}
loadCanopies() {
const canopies$: Observable<Array<CanopyBySize>> = this.canopiesService.getAllBySize();
this._canopies = canopies$.subscribe((aggregate: Array<CanopyBySize>) => {
this.aggregate = aggregate;
//this.canopies = canopies;
this.canopiesCount = aggregate.length;
ngOnDestroy() {
this._canopyBySize.unsubscribe();
this._canopyByYear.unsubscribe();
}
private _loadCanopyModelBySize(): void {
const canopies$: Observable<Array<CanopyModelBySize>> = this.canopiesService.getAllModelBySize();
this._canopyBySize = canopies$.subscribe((aggregate: Array<CanopyModelBySize>) => {
this.canopyBySize = aggregate;
this.canopyBySizeCount = aggregate.length;
var labels: string[] = [];
var series: number[] = [];
this.aggregate.forEach((row) => {
this.seriesName.push(row._id.canopy + ' ' + row._id.taille);
this.canopyBySize.forEach((row) => {
this.seriesName.push(`${row._id.taille.toString()} - ${row._id.voile}`);
this.seriesValue.push(row.count);
labels.push(row.count.toString());
series.push(row.count);
});
this.donuteCanopyModel = {
this.donuteCanopies = {
type: 'Pie',
data: {
"labels": labels,
@@ -128,6 +70,29 @@ export class CanopyModelsComponent implements OnInit {
showLabel: true
}
};
this._loadCanopyModelByYear();
});
}
private _loadCanopyModelByYear(): void {
let values: Array<number> = [];
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
this.seriesHeader.forEach(() => {
values.push(0);
});
this.seriesName.forEach(() => {
this.seriesRow.push([...values]);
});
const dropzones$: Observable<Array<CanopyModelByYear>> = this.canopiesService.getAllModelByYear();
this._canopyByYear = dropzones$.subscribe((aggregate: Array<CanopyModelByYear>) => {
this.canopyByYear = aggregate;
this.canopyByYearCount = aggregate.length;
this.canopyByYear.forEach((row: CanopyModelByYear) => {
let voile: string = row._id.voile;
let taille: string = row._id.taille.toString();
let year: string = row._id.year.toString();
this.seriesRow[this.seriesName.indexOf(`${taille} - ${voile}`)][this.seriesHeader.indexOf(year)] = row.count;
});
});
}
}
@@ -3,9 +3,7 @@
<mat-card-title>Taille de voile</mat-card-title>
<mat-card-subtitle>Nombre total de sauts par taille</mat-card-subtitle>
<div class="piechart">
<x-chartist class="" [data]="donuteChartSize.data" [type]="donuteChartSize.type"
[options]="donuteChartSize.options" [responsiveOptions]="donuteChartSize.responsiveOptions"
[events]="donuteChartSize.events"> </x-chartist>
<x-chartist [configuration]="donuteCanopiesSize"></x-chartist>
</div>
</mat-card-content>
<hr>
@@ -14,18 +12,18 @@
<thead>
<tr>
<th></th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-right"> {{name}} </th>
<th class="text-right">Total</th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{name}} </th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody class="text-mono">
<tbody class="font-monospace">
<tr *ngFor='let values of seriesRow; let i=index'>
<th class="{{seriesColor[i]}} text-right"><i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-right">
<th class="{{seriesColor[i]}} text-end"> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</td>
<th class="{{seriesColor[i]}} text-right">
<th class="{{seriesColor[i]}} text-end">
<span *ngIf="seriesValue[i]; else elseBlock" class="pr-1">{{seriesValue[i]}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{seriesValue[i]}}</span></ng-template>
</th>
@@ -1,10 +1,12 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { BackendService } from 'src/app/core/services';
import { ReduceRow } from 'src/app/core/models';
import { Observable, Subscription } from 'rxjs';
import { BackendService, CanopiesService } from 'src/app/core/services';
import { chartPieDonute, CanopyBySize, CanopyByYear, ReduceRow } from 'src/app/core/models';
@Component({
standalone: true,
@@ -12,76 +14,84 @@ import { ReduceRow } from 'src/app/core/models';
selector: 'huapp-canopy-sizes',
templateUrl: './canopy-sizes.component.html'
})
export class CanopySizesComponent implements OnInit {
export class CanopySizesComponent implements OnInit, OnDestroy {
private _canopyBySize: Subscription = new Subscription();
private _canopyByYear: Subscription = new Subscription();
canopyBySize!: Array<CanopyBySize>;
canopyByYear!: Array<CanopyByYear>;
canopyBySizeCount = 0;
canopyByYearCount = 0;
rows: Object[] = [] as Array<Object>;
seriesName: string[] = [];
seriesValue: number[] = [];
seriesColor: string[] = this._dataService.getChartColors();
seriesHeader: string[] = [];
seriesRow: any[] = [];
donuteChartSize: Configuration = {
type: 'Pie',
data: {
"labels": [],
"series": []
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 0,
showLabel: true
}
};
donuteCanopiesSize: Configuration = chartPieDonute;
constructor(private _dataService: BackendService) { }
loadDataByDate() {
return this._dataService
.getCanopySizesByDate(2)
.subscribe((res) => {
this.seriesName.forEach((name: string) => {
this.seriesRow.push([0, 0, 0, 0, 0, 0]);
});
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
res["rows"].forEach((row: ReduceRow) => {
let year = row.key[1].toString();
let size = row.key[0];
this.seriesRow[this.seriesName.indexOf(size)][this.seriesHeader.indexOf(year)] = row.value;
});
return true;
});
}
constructor(
private canopiesService: CanopiesService,
private _dataService: BackendService
) { }
ngOnInit() {
return this._dataService
.getCanopySizes()
.subscribe((res) => {
this.rows = res["rows"]
var labels: string[] = [];
var series: number[] = [];
this.rows.forEach((row: ReduceRow) => {
this.seriesName.push(row.key);
this.seriesValue.push(row.value);
labels.push(row.value.toString());
series.push(row.value);
});
this.donuteChartSize = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 40,
donutSolid: true,
startAngle: 330,
showLabel: true
}
};
return this.loadDataByDate();
this._loadCanopyBySize();
}
ngOnDestroy() {
this._canopyBySize.unsubscribe();
this._canopyByYear.unsubscribe();
}
private _loadCanopyBySize(): void {
const canopies$: Observable<Array<CanopyBySize>> = this.canopiesService.getAllBySize();
this._canopyBySize = canopies$.subscribe((aggregate: Array<CanopyBySize>) => {
this.canopyBySize = aggregate;
this.canopyBySizeCount = aggregate.length;
var labels: string[] = [];
var series: number[] = [];
this.canopyBySize.forEach((row) => {
this.seriesName.push(row._id.taille.toString());
this.seriesValue.push(row.count);
labels.push(row.count.toString());
series.push(row.count);
});
this.donuteCanopiesSize = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 330,
showLabel: true
}
};
this._loadCanopyByYear();
});
}
private _loadCanopyByYear(): void {
let values: Array<number> = [];
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
this.seriesHeader.forEach(() => {
values.push(0);
});
this.seriesName.forEach(() => {
this.seriesRow.push([...values]);
});
const dropzones$: Observable<Array<CanopyByYear>> = this.canopiesService.getAllByYear();
this._canopyByYear = dropzones$.subscribe((aggregate: Array<CanopyByYear>) => {
this.canopyByYear = aggregate;
this.canopyByYearCount = aggregate.length;
this.canopyByYear.forEach((row: CanopyByYear) => {
let taille: string = row._id.taille.toString();
let year: string = row._id.year.toString();
this.seriesRow[this.seriesName.indexOf(taille)][this.seriesHeader.indexOf(year)] = row.count;
});
});
}
}
@@ -3,7 +3,7 @@
<mat-card-title>Les drop zones</mat-card-title>
<mat-card-subtitle>Nombre total de sauts par DZ</mat-card-subtitle>
<div class="piechart">
<x-chartist [configuration]="donuteDropZones"> </x-chartist>
<x-chartist [configuration]="donuteDropZones"></x-chartist>
</div>
</mat-card-content>
<hr>
@@ -1,10 +1,12 @@
import { Component, OnInit, Input, Output } from '@angular/core';
import { Component, OnInit, OnDestroy, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { BackendService } from 'src/app/core/services';
import { DropZone, ReduceRow} from 'src/app/core/models';
import { Observable, Subscription } from 'rxjs';
import { BackendService, DropZonesService } from 'src/app/core/services';
import { chartBar, chartPieDonute, DropZone, DropZoneByOaci, DropZoneByYear } from 'src/app/core/models';
@Component({
standalone: true,
@@ -12,63 +14,86 @@ import { DropZone, ReduceRow} from 'src/app/core/models';
selector: 'huapp-drop-zones-bar',
templateUrl: './drop-zones-bar.component.html'
})
export class DropZonesBarComponent implements OnInit {
export class DropZonesBarComponent implements OnInit, OnDestroy {
private _dropzoneByOaci: Subscription = new Subscription();
private _dropzoneByYear: Subscription = new Subscription();
dropzoneByOaci!: Array<DropZoneByOaci>;
dropzoneByYear!: Array<DropZoneByYear>;
dropzoneByOaciCount = 0;
dropzoneByYearCount = 0;
dropzones: Object[] = [] as Array<Object>;
seriesName: string[] = [];//= ["Arcachon", "Béni-Mellal", "La Réole", "Royan", "Pamiers", "Soulac", "Sables d'Olonne", "Rochefort"];
seriesName: string[] = [];
seriesValue: number[] = [];
seriesColor: string[] = this._dataService.getChartColors();
seriesHeader: string[] = [];
seriesRow: any[] = [];
donuteDropZones: Configuration = {
type: 'Pie',
/*
data: {
"labels": ["261", "45", "178", "16", "13", "11", "4", "2"],
"series": [261, 45, 178, 16, 13, 11, 4, 2]
},
*/
data: {
"labels": [],
"series": []
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 270,
showLabel: true
}
};
barChartDropZones: Configuration = {
type: 'Bar',
data: {
"labels": [],
"series": []
},
options: {},
responsiveOptions: []
};
donuteDropZones: Configuration = chartPieDonute;
barChartDropZones: Configuration = chartBar;
constructor(private _dataService: BackendService) { }
constructor(
private dropzonesService: DropZonesService,
private _dataService: BackendService
) { }
loadDataByDate() {
return this._dataService
.getDropZonesByDate(2)
.subscribe((res) => {
console.log(res["rows"]);
this.seriesName.forEach((name: string) => {
this.seriesRow.push([0, 0, 0, 0, 0, 0]);
ngOnInit() {
this._loadDropZoneByOaci();
}
ngOnDestroy() {
this._dropzoneByOaci.unsubscribe();
this._dropzoneByYear.unsubscribe();
}
private _loadDropZoneByOaci(): void {
const dropzones$: Observable<Array<DropZoneByOaci>> = this.dropzonesService.getAllByOaci();
this._dropzoneByOaci = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
this.dropzoneByOaci = aggregate;
this.dropzoneByOaciCount = aggregate.length;
var labels: string[] = [];
var series: number[] = [];
this.dropzoneByOaci.forEach((row) => {
this.seriesName.push(`${row._id.oaci} - ${row._id.lieu}`);
this.seriesValue.push(row.count);
labels.push(row.count.toString());
series.push(row.count);
});
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
res["rows"].forEach((row: ReduceRow) => {
let year = row.key[1].toString();
let lieu = row.key[0];
this.seriesRow[this.seriesName.indexOf(lieu)][this.seriesHeader.indexOf(year)] = row.value;
//console.log(row.key, row.value);
this.donuteDropZones = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 50,
startAngle: 270,
showLabel: true
}
};
this._loadDropZoneByYear();
});
}
private _loadDropZoneByYear(): void {
let values: Array<number> = [];
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
this.seriesHeader.forEach(() => {
values.push(0);
});
this.seriesName.forEach(() => {
this.seriesRow.push([...values]);
});
const dropzones$: Observable<Array<DropZoneByYear>> = this.dropzonesService.getAllByDate();
this._dropzoneByYear = dropzones$.subscribe((aggregate: Array<DropZoneByYear>) => {
this.dropzoneByYear = aggregate;
this.dropzoneByYearCount = aggregate.length;
this.dropzoneByYear.forEach((row: DropZoneByYear) => {
let lieu: string = row._id.lieu;
let oaci: string = row._id.oaci;
let year: string = row._id.year.toString();
this.seriesRow[this.seriesName.indexOf(`${oaci} - ${lieu}`)][this.seriesHeader.indexOf(year)] = row.count;
});
//console.log(this.seriesName);
//console.log(this.seriesHeader);
//console.log(this.seriesRow);
this.barChartDropZones = {
type: 'Bar',
data: {
@@ -121,50 +146,6 @@ export class DropZonesBarComponent implements OnInit {
}]
]
};
return true;
});
}
ngOnInit() {
return this._dataService
.getDropZones()
.subscribe((res) => {
//console.log('ngOnInit');
//console.log(res["rows"]);
this.dropzones = res["rows"]
var labels: string[] = [];
var series: number[] = [];
this.dropzones.forEach((dropzone: DropZone) => {
this.seriesName.push(dropzone.key);
this.seriesValue.push(dropzone.value);
//console.log(dropzone.key, dropzone.value);
labels.push(dropzone.value.toString());
series.push(dropzone.value);
});
this.donuteDropZones = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 40,
donutSolid: true,
startAngle: 270,
showLabel: true
}
/*,
events: <ChartEvent>{
draw: (data) => {
//this.donuteDropZones.data = data;
console.log(data);
}
}
*/
};
return this.loadDataByDate();
});
}
}
@@ -3,7 +3,7 @@
<mat-card-title>Les drop zones</mat-card-title>
<mat-card-subtitle>Nombre total de sauts par DZ</mat-card-subtitle>
<div class="piechart">
<x-chartist [configuration]="donuteDropZones"> </x-chartist>
<x-chartist [configuration]="donuteDropZones"></x-chartist>
</div>
</mat-card-content>
<hr>
@@ -12,18 +12,18 @@
<thead>
<tr>
<th></th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-right"> {{name}} </th>
<th class="text-right">Total</th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{name}} </th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody class="text-mono">
<tbody class="font-monospace">
<tr *ngFor='let values of seriesRow; let i=index'>
<th class="{{seriesColor[i]}} text-right"><i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-right">
<th class="{{seriesColor[i]}} text-end"> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</td>
<th class="{{seriesColor[i]}} text-right">
<th class="{{seriesColor[i]}} text-end">
<span *ngIf="seriesValue[i]; else elseBlock" class="pr-1">{{seriesValue[i]}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{seriesValue[i]}}</span></ng-template>
</th>
@@ -1,12 +1,12 @@
import { Component, OnInit, Input, Output } from '@angular/core';
import { Component, OnInit, OnDestroy, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { Observable, Observer, Subscription } from 'rxjs';
import { Observable, Subscription } from 'rxjs';
import { BackendService, DropZonesService } from 'src/app/core/services';
import { DropZone, DropZoneByOaci, ReduceRow} from 'src/app/core/models';
import { DropZoneByOaci, DropZoneByYear, chartPieDonute} from 'src/app/core/models';
@Component({
standalone: true,
@@ -14,156 +14,43 @@ import { DropZone, DropZoneByOaci, ReduceRow} from 'src/app/core/models';
selector: 'huapp-drop-zones',
templateUrl: './drop-zones.component.html'
})
export class DropZonesComponent implements OnInit {
private _dropzones: Subscription = new Subscription();
aggregate!: Array<DropZoneByOaci>
dropzones!: Array<DropZone>;
dropzonesCount = 0;
seriesName: string[] = [];//= ["Arcachon", "Béni-Mellal", "La Réole", "Royan", "Pamiers", "Soulac", "Sables d'Olonne", "Rochefort"];
export class DropZonesComponent implements OnInit, OnDestroy {
private _dropzoneByOaci: Subscription = new Subscription();
private _dropzoneByYear: Subscription = new Subscription();
dropzoneByOaci!: Array<DropZoneByOaci>;
dropzoneByYear!: Array<DropZoneByYear>;
dropzoneByOaciCount = 0;
dropzoneByYearCount = 0;
seriesName: string[] = [];
seriesValue: number[] = [];
seriesColor: string[] = this._dataService.getChartColors();
seriesHeader: string[] = [];
seriesRow: any[] = [];
donuteDropZones: Configuration = {
type: 'Pie',
/*
data: {
"labels": ["261", "45", "178", "16", "13", "11", "4", "2"],
"series": [261, 45, 178, 16, 13, 11, 4, 2]
},
*/
data: {
"labels": [],
"series": []
},
options: {
donut: true,
height: 260,
donutWidth: 40,
startAngle: 270,
showLabel: true
}
};
barChartDropZones: Configuration = {
type: 'Bar',
data: {
"labels": [],
"series": []
},
options: {
seriesBarDistance: 5,
high: 170,
axisX: {
showGrid: false,
offset: 20
},
axisY: {
showGrid: true,
offset: 40
},
height: 207
},
responsiveOptions: [
['screen and (min-width: 1024px)', {
axisX: {
labelInterpolationFnc: function(value: number, index: number): string {
return index % 1 === 0 ? `${value}` : '';
}
}
}],
['screen and (min-width: 641px) and (max-width: 1024px)', {
seriesBarDistance: 10,
axisY: {
offset: 30
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[2]}${value[3]}` : '';
}
}
}],
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisY: {
offset: 20
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[2]}${value[3]}` : '';
}
}
}]
]
};
donuteDropZones: Configuration = chartPieDonute;
constructor(
private dropzonesService: DropZonesService,
private _dataService: BackendService
) { }
ngOnInit() {
this.loadDropZones();
/*
return this._dataService
.getDropZones()
.subscribe((res) => {
this.dropzones = res["rows"]
var labels: string[] = [];
var series: number[] = [];
this.dropzones.forEach((dropzone: DropZone) => {
this.seriesName.push(dropzone.key);
this.seriesValue.push(dropzone.value);
labels.push(dropzone.value.toString());
series.push(dropzone.value);
});
this.donuteDropZones = {
type: 'Pie',
data: {
"labels": labels,
"series": series
},
options: {
donut: true,
height: 260,
donutWidth: 40,
donutSolid: true,
startAngle: 270,
showLabel: true
}
,
// events: <ChartEvent>{
// draw: (data) => {
// //this.donuteDropZones.data = data;
// console.log(data);
// }
// }
};
return this._dataService
.getDropZonesByDate(2)
.subscribe((res) => {
this.seriesName.forEach((name: string) => {
this.seriesRow.push([0, 0, 0, 0, 0, 0]);
});
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
res["rows"].forEach((row: ReduceRow) => {
let year = row.key[1].toString();
let lieu = row.key[0];
this.seriesRow[this.seriesName.indexOf(lieu)][this.seriesHeader.indexOf(year)] = row.value;
});
return true;
});
});
*/
this._loadDropZoneByOaci();
}
loadDropZones() {
ngOnDestroy() {
this._dropzoneByOaci.unsubscribe();
this._dropzoneByYear.unsubscribe();
}
private _loadDropZoneByOaci(): void {
const dropzones$: Observable<Array<DropZoneByOaci>> = this.dropzonesService.getAllByOaci();
this._dropzones = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
this.aggregate = aggregate;
//this.dropzones = dropzones;
this.dropzonesCount = aggregate.length;
this._dropzoneByOaci = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
this.dropzoneByOaci = aggregate;
this.dropzoneByOaciCount = aggregate.length;
var labels: string[] = [];
var series: number[] = [];
this.aggregate.forEach((row) => {
this.seriesName.push(row._id.lieu + ' ' + row._id.oaci);
this.dropzoneByOaci.forEach((row) => {
this.seriesName.push(`${row._id.oaci} - ${row._id.lieu}`);
this.seriesValue.push(row.count);
labels.push(row.count.toString());
series.push(row.count);
@@ -182,6 +69,29 @@ export class DropZonesComponent implements OnInit {
showLabel: true
}
};
this._loadDropZoneByYear();
});
}
private _loadDropZoneByYear(): void {
let values: Array<number> = [];
this.seriesHeader = ["2018", "2019", "2020", "2021", "2022", "2023"];
this.seriesHeader.forEach(() => {
values.push(0);
});
this.seriesName.forEach(() => {
this.seriesRow.push([...values]);
});
const dropzones$: Observable<Array<DropZoneByYear>> = this.dropzonesService.getAllByDate();
this._dropzoneByYear = dropzones$.subscribe((aggregate: Array<DropZoneByYear>) => {
this.dropzoneByYear = aggregate;
this.dropzoneByYearCount = aggregate.length;
this.dropzoneByYear.forEach((row: DropZoneByYear) => {
let lieu: string = row._id.lieu;
let oaci: string = row._id.oaci;
let year: string = row._id.year.toString();
this.seriesRow[this.seriesName.indexOf(`${oaci} - ${lieu}`)][this.seriesHeader.indexOf(year)] = row.count;
});
});
}
}
@@ -1,7 +1,7 @@
export * from './aeronefs/aeronefs.component';
//export * from './aeronefs-bar/aeronefs-bar.component';
export * from './aeronefs-bar/aeronefs-bar.component';
export * from './canopy-models/canopy-models.component';
//export * from './canopy-sizes/canopy-sizes.component';
export * from './canopy-sizes/canopy-sizes.component';
export * from './drop-zones/drop-zones.component';
//export * from './drop-zones-bar/drop-zones-bar.component';
//export * from './jumps-by-month/jumps-by-month.component';
export * from './drop-zones-bar/drop-zones-bar.component';
export * from './jumps-by-month/jumps-by-month.component';
@@ -7,15 +7,18 @@
</div>
</div>
<div class="barchrt">
<x-chartist class="" [data]="barChartJumps.data" [type]="barChartJumps.type" [options]="barChartJumps.options" [responsiveOptions]="barChartJumps.responsiveOptions"
<x-chartist [configuration]="barChartJumps"></x-chartist>
<!--
<x-chartist class="" [data]="barChartJumps.data" [type]="barChartJumps.type" [options]="barChartJumps.options" [responsiveOptions]="barChartJumps.responsiveOptions"
[events]="barChartJumps.events"> </x-chartist>
-->
</div>
<div class="text-center mt-3 mb-2">
<div class="text-center my-3">
<ul class="list-inline my-0">
<li *ngFor='let name of seriesName; let i=index'>
<h4 class="{{seriesColor[i]}} m-0">
<i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i>{{name}}
</h4>
<li *ngFor='let name of seriesName; let i=index' class="list-inline-item me-lg-3 me-sm-2">
<span class="{{seriesColor[i]}} fs-6 m-0">
{{name}}
</span>
</li>
</ul>
</div>
@@ -25,28 +28,28 @@
<thead>
<tr>
<th></th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-right"> {{name}} </th>
<th class="text-right">Total</th>
<th *ngFor='let name of seriesHeader; let i=index' class="text-end"> {{name}} </th>
<th class="text-end">Total</th>
</tr>
</thead>
<tbody>
<tr *ngFor='let values of seriesRow; let i=index'>
<th class="{{seriesColor[i]}} text-right"><i class="mdi mdi-checkbox-blank-circle font-10 m-r-10 "></i> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="text-mono text-right">
<th class="{{seriesColor[i]}} text-end"> {{seriesName[i]}} </th>
<td *ngFor='let value of values; let i=index' class="font-monospace text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</td>
<th class="text-mono text-right">{{seriesRowTotal[i]}}</th>
<th class="font-monospace text-end">{{seriesRowTotal[i]}}</th>
</tr>
</tbody>
<tfoot>
<tr>
<th class="text-right">Total</th>
<th *ngFor='let value of seriesColTotal; let i=index' class="text-mono text-right">
<th class="text-end">Total</th>
<th *ngFor='let value of seriesColTotal; let i=index' class="font-monospace text-end">
<span *ngIf="value; else elseBlock" class="pr-1">{{value}}</span>
<ng-template #elseBlock><span class="text-empty pr-1">{{value}}</span></ng-template>
</th>
<th class="text-mono text-right">{{grandTotal}}</th>
<th class="font-monospace text-end">{{grandTotal}}</th>
</tr>
</tfoot>
</table>
@@ -1,20 +1,26 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, OnDestroy } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MatCardModule } from '@angular/material/card';
import { ChartistModule, Configuration } from 'ng-chartist';
import { BackendService } from 'src/app/core/services';
import { ReduceRow } from 'src/app/core/models';
import { Observable, Subscription } from 'rxjs';
import { BackendService, JumpsService } from 'src/app/core/services';
import { chartBar, JumpByDate, ReduceRow } from 'src/app/core/models';
declare var require: any;
const data= require('./data.json');
@Component({
standalone: true,
imports: [MatCardModule, ChartistModule],
imports: [CommonModule, MatCardModule, ChartistModule],
selector: 'huapp-jumps-by-month',
templateUrl: './jumps-by-month.component.html'
})
export class JumpsByMonthComponent implements OnInit {
export class JumpsByMonthComponent implements OnInit, OnDestroy {
private _jumpByDate: Subscription = new Subscription();
jumpByDate!: Array<JumpByDate>;
jumpByDateCount = 0;
rows: Object[] = [] as Array<Object>;
min: number = 0;
max: number = 0;
@@ -25,140 +31,104 @@ export class JumpsByMonthComponent implements OnInit {
seriesColTotal: number[] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
seriesName: String[] = []; // ["2018", "2019", "2020", "2021", "2022", "2023"];
seriesColor: String[] = this._dataService.getChartColors();
barChartJumps: Configuration = {
type: 'Bar',
data: {
"labels": [],
"series": []
},
options: {
seriesBarDistance: 5,
high: 70,
axisX: {
showGrid: false,
offset: 20
},
axisY: {
showGrid: true,
offset: 40
},
height: 300
},
responsiveOptions: [
['screen and (min-width: 1024px)', {
axisX: {
labelInterpolationFnc: function(value: number, index: number): string {
return index % 1 === 0 ? `${value}` : '';
}
}
}],
['screen and (min-width: 641px) and (max-width: 1024px)', {
seriesBarDistance: 10,
axisY: {
offset: 30
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[0]}` : '';
}
}
}],
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisY: {
offset: 20
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[0]}` : '';
}
}
}]
]
};
constructor(private _dataService: BackendService) { }
barChartJumps: Configuration = chartBar;
constructor(
private jumpsService: JumpsService,
private _dataService: BackendService
) { }
ngOnInit() {
return this._dataService
.getJumpsByDate(2)
.subscribe((res) => {
//console.log(res["rows"]);
this.rows = res["rows"]
this.rows.forEach((row: ReduceRow) => {
let year = row.key[0].toString();
let month = row.key[1];
if (this.seriesName.indexOf(year) < 0) {
this.seriesName.push(year);
if (row.key[0] < this.min || this.min == 0) {
this.min = row.key[0];
}
if (row.key[0] > this.max) {
this.max = row.key[0];
}
this.seriesRow.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
this._loadJumpByDate();
}
ngOnDestroy() {
this._jumpByDate.unsubscribe();
}
private _loadJumpByDate() {
let values: Array<number> = [];
this.seriesHeader.forEach(() => {
values.push(0);
});
const jumps$: Observable<Array<JumpByDate>> = this.jumpsService.getAllByDate();
this._jumpByDate = jumps$.subscribe((aggregate: Array<JumpByDate>) => {
this.jumpByDate = aggregate;
this.jumpByDateCount = aggregate.length;
console.log(this.jumpByDate);
console.log(this.jumpByDateCount);
this.jumpByDate.forEach((row) => {
let year = row._id.year.toString();
let month = row._id.month;
if (this.seriesName.indexOf(year) < 0) {
this.seriesName.push(year);
if (row._id.year < this.min || this.min == 0) {
this.min = row._id.year;
}
this.seriesRow[(this.seriesRow.length-1)][(month-1)] = row.value;
this.seriesColTotal[(month-1)] += row.value;
//console.log(row.key, row.value);
});
this.seriesRow.forEach((row: number[]) => {
const total = row.reduce((partialSum, a) => partialSum + a, 0);
this.seriesRowTotal.push(total);
});
console.log(this.seriesColTotal);
this.grandTotal = this.seriesColTotal.reduce((partialSum, a) => partialSum + a, 0);
//console.log(this.seriesRow, this.seriesName);
this.barChartJumps = {
type: 'Bar',
data: {
"labels": this.seriesHeader,
"series": this.seriesRow
if (row._id.year > this.max) {
this.max = row._id.year;
}
this.seriesRow.push([...values]);
}
this.seriesRow[(this.seriesRow.length-1)][(month-1)] = row.count;
this.seriesColTotal[(month-1)] += row.count;
});
this.seriesRow.forEach((row: number[]) => {
const total = row.reduce((partialSum, a) => partialSum + a, 0);
this.seriesRowTotal.push(total);
});
this.grandTotal = this.seriesColTotal.reduce((partialSum, a) => partialSum + a, 0);
this.barChartJumps = {
type: 'Bar',
data: {
"labels": this.seriesHeader,
"series": this.seriesRow
},
options: {
seriesBarDistance: 15,
high: 70,
axisX: {
showGrid: false,
offset: 20
},
options: {
seriesBarDistance: 15,
high: 70,
axisY: {
showGrid: true,
offset: 40
},
height: 300
},
responsiveOptions: [
['screen and (min-width: 1024px)', {
axisX: {
showGrid: false,
labelInterpolationFnc: function(value: number, index: number): string {
return index % 1 === 0 ? `${value}` : '';
}
}
}],
['screen and (min-width: 641px) and (max-width: 1024px)', {
seriesBarDistance: 10,
axisY: {
offset: 30
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[0]}` : '';
}
}
}],
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisY: {
offset: 20
},
axisY: {
showGrid: true,
offset: 40
},
height: 300
},
responsiveOptions: [
['screen and (min-width: 1024px)', {
axisX: {
labelInterpolationFnc: function(value: number, index: number): string {
return index % 1 === 0 ? `${value}` : '';
}
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[0]}` : '';
}
}],
['screen and (min-width: 641px) and (max-width: 1024px)', {
seriesBarDistance: 10,
axisY: {
offset: 30
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[0]}` : '';
}
}
}],
['screen and (max-width: 640px)', {
seriesBarDistance: 5,
axisY: {
offset: 20
},
axisX: {
labelInterpolationFnc: function(value: any, index: number): string {
return index % 1 === 0 ? `${value[0]}` : '';
}
}
}]
]
};
return true;
});
}
}]
]
};
});
}
}
+20 -7
View File
@@ -6,14 +6,27 @@
<div *appShowAuthed="false">
Not connected
</div>
<div>
<huapp-aeronefs></huapp-aeronefs>
<div class="row">
<div class="col-md-8 col-sm-12">
<huapp-jumps-by-month></huapp-jumps-by-month>
</div>
<div class="col-md-4 col-sm-12">
<huapp-drop-zones></huapp-drop-zones>
</div>
</div>
<div>
<huapp-drop-zones></huapp-drop-zones>
</div>
<div>
<huapp-canopy-models></huapp-canopy-models>
<div class="row mt-sm-2 mt-lg-3">
<div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
<huapp-canopy-sizes></huapp-canopy-sizes>
</div>
<div class="col-lg-3 col-md-4 col-sm-6 col-xs-12">
<huapp-canopy-models></huapp-canopy-models>
</div>
<div class="col-lg-6 col-md-4 col-sm-6 col-xs-12">
<huapp-aeronefs-bar></huapp-aeronefs-bar>
<!--
<huapp-aeronefs></huapp-aeronefs>
-->
</div>
</div>
<!--
<div fxLayout="row wrap">
+51 -38
View File
@@ -5,18 +5,19 @@ import { ActivatedRoute, Data, Router } from '@angular/router';
import { Observable, Observer, Subscription } from 'rxjs';
import { take } from 'rxjs/operators';
import { User, Errors, Aeronef, AeronefByImat, AeronefList, Canopy, CanopyBySize, DropZone, DropZoneByOaci } from 'src/app/core/models';
import { User, Errors, Aeronef, AeronefByImat, Canopy, CanopyModelBySize, DropZone, DropZoneByYear } from 'src/app/core/models';
import { AeronefsService, CanopiesService, DropZonesService, UserService } from 'src/app/core/services';
import { ShowAuthedDirective } from 'src/app/components/shared/show-authed.directive';
import { AeronefsComponent, DropZonesComponent, CanopyModelsComponent } from './dashboard-components';
import { AeronefsBarComponent, DropZonesComponent, CanopyModelsComponent, CanopySizesComponent, JumpsByMonthComponent } from './dashboard-components';
//import { JumpsByMonthComponent, AeronefsComponent, AeronefsBarComponent, DropZonesComponent, DropZonesBarComponent, CanopySizesComponent, CanopyModelsComponent} from './dashboard-components';
@Component({
standalone: true,
imports: [
ShowAuthedDirective,
AeronefsBarComponent, DropZonesComponent, CanopyModelsComponent, CanopySizesComponent, JumpsByMonthComponent
//AeronefsComponent, AeronefsBarComponent, DropZonesComponent, DropZonesBarComponent,
//CanopySizesComponent, CanopyModelsComponent, JumpsByMonthComponent,
AeronefsComponent, DropZonesComponent, CanopyModelsComponent, ShowAuthedDirective
],
selector: 'huapp-home',
templateUrl: './home.component.html',
@@ -32,13 +33,15 @@ export class HomeComponent implements OnInit, OnDestroy {
errors!: Errors;
isAuthenticated = false;
canModify = false;
aeronefAggregate!: Array<AeronefByImat>
aeronefs!: Array<Aeronef>;
aeronefsCount = 0;
canopyAggregate!: Array<CanopyBySize>
canopyAggregate!: Array<CanopyModelBySize>
canopies!: Array<Canopy>;
canopiesCount = 0;
dropzoneAggregate!: Array<DropZoneByOaci>
//dropzoneAggregate!: Array<DropZoneByOaci>
dropzoneAggregate!: Array<DropZoneByYear>
dropzones!: Array<DropZone>;
dropzonesCount = 0;
@@ -46,10 +49,10 @@ export class HomeComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private router: Router,
private titleService: Title,
private userService: UserService,
private aeronefsService: AeronefsService,
private canopiesService: CanopiesService,
private dropzonesService: DropZonesService,
private userService: UserService
private dropzonesService: DropZonesService
) {
this._resetErrors();
}
@@ -64,51 +67,61 @@ export class HomeComponent implements OnInit, OnDestroy {
this.router.navigateByUrl('/login');
return;
}
const currentUser$: Observable<User> = this.userService.currentUser.pipe(take(1));
const currentUser$: Observable<User> = this.userService.currentUser;
this._currentUser = currentUser$.subscribe((userData: User) => {
this.canModify = userData.role === 'Admin';
});
});
this.loadAeronefs();
this.loadCanopies();
this.loadDropzones();
}
/*
this._loadAeronefs();
this._loadCanopies();
this._loadDropzones();
*/
loadAeronefs() {
const aeronefs$: Observable<Array<AeronefByImat>> = this.aeronefsService.getAllByImat();
this._aeronefs = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
this.aeronefAggregate = aggregate;
this.aeronefsCount = aggregate.length;
console.log(this.aeronefs);
console.log(this.aeronefsCount);
});
}
loadCanopies() {
const canopies$: Observable<Array<CanopyBySize>> = this.canopiesService.getAllBySize();
this._canopies = canopies$.subscribe((aggregate: Array<CanopyBySize>) => {
this.canopyAggregate = aggregate;
this.canopiesCount = aggregate.length;
// console.log(this.canopies);
// console.log(this.canopiesCount);
});
}
loadDropzones() {
const dropzones$: Observable<Array<DropZoneByOaci>> = this.dropzonesService.getAllByOaci();
this._dropzones = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
this.dropzoneAggregate = aggregate;
this.dropzonesCount = aggregate.length;
// console.log(this.dropzones);
// console.log(this.dropzonesCount);
});
}
ngOnDestroy() {
this._currentUser.unsubscribe();
/*
this._aeronefs.unsubscribe();
this._canopies.unsubscribe();
this._dropzones.unsubscribe();
*/
}
private _resetErrors(): void {
this.errors = { errors: {} };
}
private _loadAeronefs(): void {
const aeronefs$: Observable<Array<AeronefByImat>> = this.aeronefsService.getAllByImat();
this._aeronefs = aeronefs$.subscribe((aggregate: Array<AeronefByImat>) => {
this.aeronefAggregate = aggregate;
this.aeronefsCount = aggregate.length;
console.log(this.aeronefAggregate);
console.log(this.aeronefsCount);
});
}
private _loadCanopies(): void {
const canopies$: Observable<Array<CanopyModelBySize>> = this.canopiesService.getAllModelBySize();
this._canopies = canopies$.subscribe((aggregate: Array<CanopyModelBySize>) => {
this.canopyAggregate = aggregate;
this.canopiesCount = aggregate.length;
console.log(this.canopyAggregate);
console.log(this.canopiesCount);
});
}
private _loadDropzones(): void {
//const dropzones$: Observable<Array<DropZoneByOaci>> = this.dropzonesService.getAllByOaci();
//this._dropzones = dropzones$.subscribe((aggregate: Array<DropZoneByOaci>) => {
const dropzones$: Observable<Array<DropZoneByYear>> = this.dropzonesService.getAllByDate();
this._dropzones = dropzones$.subscribe((aggregate: Array<DropZoneByYear>) => {
this.dropzoneAggregate = aggregate;
this.dropzonesCount = aggregate.length;
console.log(this.dropzoneAggregate);
console.log(this.dropzonesCount);
});
}
}
@@ -30,7 +30,7 @@
<!-- Numero Column -->
<ng-container matColumnDef="numero">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Numero </th>
<td class="text-right pl-3 pr-3" mat-cell *matCellDef="let element">
<td class="text-end pl-3 pr-3" mat-cell *matCellDef="let element">
<ng-container *ngIf="element.numero"><a [routerLink]="['/jump', element.slug]">{{element.numero}}</a></ng-container>
<ng-container *ngIf="!element.numero"><ngx-skeleton-loader [theme]="{width: '30px', height: '13px', marginBottom: '0px'}"></ngx-skeleton-loader></ng-container>
</td>
@@ -94,7 +94,7 @@
<!-- Taille Column -->
<ng-container matColumnDef="taille">
<th class="pl-3" mat-header-cell *matHeaderCellDef> Taille </th>
<td class="text-nowrap text-right pl-3 pr-3" mat-cell *matCellDef="let element">
<td class="text-nowrap text-end pl-3 pr-3" mat-cell *matCellDef="let element">
<ng-container *ngIf="element.taille">{{element.taille}}</ng-container>
<ng-container *ngIf="!element.numero"><ngx-skeleton-loader [theme]="{width: '30px', height: '13px', marginBottom: '0px'}"></ngx-skeleton-loader></ng-container>
</td>
@@ -118,7 +118,7 @@
<!-- Participants Column -->
<ng-container matColumnDef="participants">
<th class="pl-3" mat-header-cell *matHeaderCellDef> Participants </th>
<td class="text-right pl-3 pr-3" mat-cell *matCellDef="let element">
<td class="text-end pl-3 pr-3" mat-cell *matCellDef="let element">
<ng-container *ngIf="element.participants">{{element.participants}}</ng-container>
<ng-container *ngIf="!element.numero"><ngx-skeleton-loader [theme]="{width: '30px', height: '13px', marginBottom: '0px'}"></ngx-skeleton-loader></ng-container>
</td>
@@ -1,7 +1,54 @@
<huapp-layout-header></huapp-layout-header>
<mat-toolbar color="primary" class="topbar">
<div class="navbar-header">
<a class="navbar-brand" href="index.html">
<span>
<img src="assets/images/logo-light-icon.svg" alt="homepage" class="light-logo">
</span>
<span>
<img src="assets/images/logo-light-text.svg" alt="homepage" class="light-logo">
</span>
</a>
</div>
<button mat-icon-button (click)="snav.toggle()" value="sidebarclosed">
<mat-icon fontIcon="menu"></mat-icon>
</button>
<span class="flex-spacer"></span>
<ng-container *appShowAuthed="true">
<span class="fw-light me-1">@{{ currentUser.username }}</span>
<div class="position-relative">
<button [matMenuTriggerFor]="profile" mat-icon-button>
<img [src]="currentUser.image" alt="user" class="profile-pic">
</button>
<mat-menu #profile="matMenu">
<button mat-menu-item [routerLink]="['/profile', currentUser.username]" routerLinkActive="active">
<mat-icon fontIcon="account_circle" color="primary"></mat-icon> Mon compte
</button>
<button mat-menu-item routerLink="/settings" routerLinkActive="active">
<mat-icon fontIcon="settings" color="primary"></mat-icon> Paramètres
</button>
<button mat-menu-item (click)="goToGitHub()">
<mat-icon fontIcon="code" color="primary"></mat-icon> GitHub
</button>
<button mat-menu-item>
<mat-icon fontIcon="notifications_off" color="primary"></mat-icon> Désactiver les notifications
</button>
<hr class="my-0" />
<button mat-menu-item (click)="logout()">
<mat-icon fontIcon="logout" color="warn"></mat-icon> Se déconnecter
</button>
</mat-menu>
</div>
</ng-container>
<ng-container *appShowAuthed="false">
<span>
<button mat-button routerLink="/login" routerLinkActive="active">Se connecter</button>
<button mat-button routerLink="/register" routerLinkActive="active">Créer un compte</button>
</span>
</ng-container>
</mat-toolbar>
<mat-sidenav-container class="app-sidenav-container" [style.marginTop.px]="mobileQuery.matches ? 0 : 0">
<mat-sidenav #snav id="snav" class="dark-sidebar pl-xs" [mode]="mobileQuery.matches ? 'side' : 'over'" fixedTopGap="0" [opened]="mobileQuery.matches" [disableClose]="mobileQuery.matches" >
<div *appShowAuthed="true">
<mat-sidenav #snav id="snav" class="dark-sidebar pl-xs" [mode]="mobileQuery.matches ? 'side' : 'over'" fixedTopGap="0" [opened]="mobileQuery.matches" [disableClose]="mobileQuery.matches">
<ng-container *appShowAuthed="true">
<div class="user-profile" style="background-image: url('{{ currentUser.bg_image }}');">
<div class="profile-img"> <img [src]="currentUser.image" alt="user"> </div>
<div class="profile-text">
@@ -48,8 +95,8 @@
</mat-list-item>
</div>
</mat-nav-list>
</div>
<div *appShowAuthed="false">
</ng-container>
<ng-container *appShowAuthed="false">
<div class="user-profile">
<!-- <div class="profile-img"> <img src="/assets/images/users/user.jpg" alt="user"> </div> -->
</div>
@@ -78,7 +125,7 @@
</mat-list-item>
</div>
</mat-nav-list>
</div>
</ng-container>
<huapp-layout-footer></huapp-layout-footer>
</mat-sidenav>
<mat-sidenav-content class="page-wrapper">
@@ -20,10 +20,12 @@ import { UserService } from 'src/app/core/services';
]
})
export class HeaderComponent implements OnInit, OnDestroy {
private _currentUser: Subscription = new Subscription();
private _isAuthenticated: Subscription = new Subscription();
private isAuthenticated = false;
currentUser: User = {} as User;
constructor(
private router: Router,
private userService: UserService