diff --git a/projects/arlas-components/assets/i18n/en.json b/projects/arlas-components/assets/i18n/en.json
index d3915041..198bf919 100644
--- a/projects/arlas-components/assets/i18n/en.json
+++ b/projects/arlas-components/assets/i18n/en.json
@@ -75,5 +75,14 @@
"None": "None",
"Fit the whole thumbnail to the tile": "Fit the whole thumbnail to the tile",
"Fit the thumbnail's width to the tile": "Fit the thumbnail's width to the tile",
- "Fit the thumbnail's height to the tile": "Fit the thumbnail's height to the tile"
+ "Fit the thumbnail's height to the tile": "Fit the thumbnail's height to the tile",
+ "Enter coordinates in decimal or sexagesimal degrees": "Enter coordinates in decimal or sexagesimal degrees.",
+ "BBox generator": "Generate a bbox",
+ "First corner": "First corner",
+ "Second corner": "Second corner",
+ "You must enter a coordinate": "Enter a coordinate",
+ "Enter a coordinate in decimal (1.1) or sexagesimal (1° 6' 3\")": "Enter a coordinate in decimal (1.1) or sexagesimal (1° 6' 3\")",
+ "Decimal: 1.1 or Sexagesimal 1°6'3\" coordinate": "Decimal: 1.1 or Sexagesimal: 1°6'3\" coordinate",
+ "Both corners have the same latitudes, change one of them.": "Both corners have the same latitudes, modify one of them.",
+ "Generate AOI": "Generate the bbox"
}
\ No newline at end of file
diff --git a/projects/arlas-components/assets/i18n/fr.json b/projects/arlas-components/assets/i18n/fr.json
index e83d0a06..9be8fda0 100644
--- a/projects/arlas-components/assets/i18n/fr.json
+++ b/projects/arlas-components/assets/i18n/fr.json
@@ -75,5 +75,14 @@
"None": "Aucune",
"Fit the whole thumbnail to the tile": "Ajuster la taille de la vignette à la tuile",
"Fit the thumbnail's width to the tile": "Ajuster la largeur de la vignette à la tuile",
- "Fit the thumbnail's height to the tile": "Ajuster la hauteur de la vignette à la tuile"
+ "Fit the thumbnail's height to the tile": "Ajuster la hauteur de la vignette à la tuile",
+ "Enter coordinates in decimal or sexagesimal degrees": "Saisir les coordonnées en degrés décimaux ou sexagésimaux.",
+ "BBox generator": "Générer une bbox",
+ "First corner": "Premier coin",
+ "Second corner": "Deuxième coin",
+ "You must enter a coordinate": "Saisir une coordonnée",
+ "Enter a coordinate in decimal (1.1) or sexagesimal (1° 6' 3\")": "Saisir une coordonnée en décimal (1.1) ou en sexagésimal (1° 6' 3\")",
+ "Decimal: 1.1 or Sexagesimal 1°6'3\" coordinate": "Coordonnée en décimal: 1.1 or sexagésimal: 1°6'3\"",
+ "Both corners have the same latitudes, modify one of them.": "Les deux coins ont les mêmes latitudes, modifiez l'un d'entre eux.",
+ "Generate AOI": "Générer la bbox"
}
\ No newline at end of file
diff --git a/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.html b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.html
new file mode 100644
index 00000000..e8763a9b
--- /dev/null
+++ b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.html
@@ -0,0 +1,60 @@
+
+
+ {{'BBox generator' | translate}}
+ clear
+
+
+
+ info
+ {{DESCRIPTION | translate}}
+
+
+
{{'First corner' | translate}}
+
+
+ {{'Latitude'}}
+
+ {{getErrorMessage(bboxForm.firstCorner.latitude) | translate}}
+
+
+
+
+ {{'Longitude'}}
+
+ {{getErrorMessage(bboxForm.firstCorner.longitude) | translate}}
+
+
+
+
+
{{'Second corner' | translate}}
+
+
+ {{'Latitude'}}
+
+ {{getErrorMessage(bboxForm.secondCorner.latitude) | translate}}
+
+
+
+
+ {{'Longitude'}}
+
+ {{getErrorMessage(bboxForm.secondCorner.longitude) | translate}}
+
+
+
+
+
+
+ report
+ {{getErrorMessage(bboxForm) | translate}}
+
+
+
+ {{'Close' | translate}}
+
+
+ {{'Generate AOI' | translate}}
+
+
+
\ No newline at end of file
diff --git a/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.scss b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.scss
new file mode 100644
index 00000000..e838714c
--- /dev/null
+++ b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.scss
@@ -0,0 +1,68 @@
+.wrapper {
+ padding: 5px;
+ border-radius: 3px;
+ background-color: white;
+ font-size: 16px;
+ min-width: 365px;
+ .title-wrapper {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ font-weight: 600;
+ }
+ .content {
+ display: flex;
+ flex-direction: column;
+ .description {
+ margin: 5px 0;
+ display: flex;
+ align-items: center;
+ font-size: 14px;
+ color: rgb(146, 146, 146);
+ mat-icon {
+ font-size: 18px;
+ height: 18px;
+ width: 18px;
+ margin-right: 5px;
+ }
+ }
+ .section {
+ .title {
+ margin-bottom: 5px;
+ }
+ display: flex;
+ flex-direction: column;
+ .coordinate {
+ width: 100%;
+ mat-form-field {
+ width: 100%;
+ }
+ .input {
+ font-size: 14px;
+ }
+ }
+ }
+
+ .errors {
+ mat-icon {
+ font-size: 16px;
+ height: 16px;
+ width: 16px;
+ margin-right: 5px;
+ color: #f44336;
+ }
+ margin-bottom: 10px;
+ display: flex;
+ align-items: center;
+ font-size: 12px;
+ }
+ }
+
+ .actions {
+ display: flex;
+ justify-content: end;
+ .create-action {
+ margin-left: 5px;
+ }
+ }
+}
\ No newline at end of file
diff --git a/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.ts b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.ts
new file mode 100644
index 00000000..c6c3362f
--- /dev/null
+++ b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.component.ts
@@ -0,0 +1,191 @@
+/*
+ * Licensed to Gisaïa under one or more contributor
+ * license agreements. See the NOTICE.txt file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Gisaïa licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { AfterViewInit, ChangeDetectorRef, Component, Inject, OnInit } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { Observable, merge, mergeMap, of } from 'rxjs';
+import { MapboxAoiDrawService } from '../mapgl/draw/draw.service';
+import { Corner } from '../mapgl/draw/draw.models';
+
+@Component({
+ selector: 'arlas-bbox-generator',
+ templateUrl: './bbox-generator.component.html',
+ styleUrls: ['./bbox-generator.component.scss']
+})
+export class BboxGeneratorComponent implements OnInit, AfterViewInit {
+ public DESCRIPTION = 'Enter coordinates in decimal or sexagesimal degrees';
+ public bboxForm: BboxFormGroup;
+ public placeHolder = 'Decimal: 1.1 or Sexagesimal 1°6\'3" coordinate';
+ public constructor(
+ private drawService: MapboxAoiDrawService,
+ private cdr: ChangeDetectorRef,
+ @Inject(MAT_DIALOG_DATA) public data: {
+ initCorner: Corner;
+ },
+ public dialogRef: MatDialogRef,) {
+ }
+
+ public ngOnInit(): void {
+ if (!!this.data && !this.data.initCorner) {
+ this.data.initCorner = {
+ lat: 32,
+ lng: -8
+ };
+ }
+ this.bboxForm = new BboxFormGroup(this.data.initCorner);
+ }
+ public ngAfterViewInit(): void {
+ this.cdr.detectChanges();
+ }
+
+ public getErrorMessage(formControl: FormControl | FormGroup) {
+ if (formControl.hasError('required')) {
+ return 'You must enter a coordinate';
+ } else if ((formControl as BboxFormGroup).latitudeErrors) {
+ return 'Both corners have the same latitudes, change one of them.';
+ }
+ return formControl.hasError('pattern') ? 'Enter a coordinate in decimal (1.1) or sexagesimal (1° 6\' 3")' : '';
+ }
+
+ public generateBbox() {
+ this.drawService.drawBbox(this.bboxForm.getFirstCorner(), this.bboxForm.getSecondCorner());
+ this.dialogRef.close();
+ }
+
+}
+
+export class BboxFormGroup extends FormGroup {
+
+ private firstCornerLatitude;
+ private secondCornerLatitude;
+ public firstCorner: PointFormGroup;
+ public secondCorner: PointFormGroup;
+ public latitudeErrors = false;
+ public constructor(corner: Corner) {
+ const firstCorner = new PointFormGroup(corner.lat - 0.5, corner.lng - 0.5);
+ const secondCorner = new PointFormGroup(corner.lat + 0.5, corner.lng + 0.5);
+ super({
+ firstCorner,
+ secondCorner
+ });
+ this.firstCorner = firstCorner;
+ this.secondCorner = secondCorner;
+
+ this.firstCorner.latitude.valueChanges.subscribe(v => {
+ this.firstCornerLatitude = v;
+ this.secondCornerLatitude = this.secondCorner.latitude.value;
+ if (this.secondCornerLatitude !== undefined) {
+ if (this.parse(this.firstCornerLatitude) === this.parse(this.secondCornerLatitude)) {
+ this.latitudeErrors = true;
+ } else {
+ this.latitudeErrors = false;
+ }
+ }
+ });
+
+ this.secondCorner.latitude.valueChanges.subscribe(v => {
+ this.secondCornerLatitude = v;
+ this.firstCornerLatitude = this.firstCorner.latitude.value;
+ if (this.firstCornerLatitude !== undefined) {
+ if (this.parse(this.firstCornerLatitude) === this.parse(this.secondCornerLatitude)) {
+ this.latitudeErrors = true;
+ } else {
+ this.latitudeErrors = false;
+ }
+ }
+ });
+ }
+
+ public getFirstCorner(): Corner {
+ this.parse(this.firstCorner.latitude.value);
+ this.parse(this.firstCorner.longitude.value);
+ return {
+ lat: this.parse(this.firstCorner.latitude.value),
+ lng: this.parse(this.firstCorner.longitude.value)
+ };
+ }
+
+ public getSecondCorner(): Corner {
+ return {
+ lat: this.parse(this.secondCorner.latitude.value),
+ lng: this.parse(this.secondCorner.longitude.value)
+ };
+ }
+
+ private parse(value: string) {
+ // eslint-disable-next-line max-len
+ const coordinatesRegex = '^(?[+-]?([0-9]*[.])?[0-9]+)$|^(?(-?)[0-9]+)°[ ]*((?[0-9]+)\'[ ]*((?[0-9]+)\")?)?$';
+ const parsedCoordinates = (String(value)).match(coordinatesRegex);
+ if (parsedCoordinates && parsedCoordinates.groups) {
+ const groups = parsedCoordinates.groups;
+ if (groups.decimal) {
+ return +groups.decimal;
+ } else {
+ const degrees = +groups.degrees;
+ const minutes = +groups.minutes;
+ const seconds = +groups.seconds;
+ return this.dmsToDd(degrees, minutes, seconds);
+ }
+ }
+ }
+
+ private dmsToDd(degrees: number, minutes: number, seconds: number) {
+ const isNegative = (degrees < 0);
+ if (!minutes) {
+ minutes = 0;
+ }
+ if (!seconds) {
+ seconds = 0;
+ }
+ const dd = Math.abs(degrees) + minutes / 60 + seconds / 3600;
+ return isNegative ? -dd : dd;
+ }
+}
+
+export class PointFormGroup extends FormGroup {
+
+ public latitude: FormControl;
+ public longitude: FormControl;
+
+ public latitudeChanges$: Observable;
+ public longitudesChanges$: Observable;
+
+ public constructor(initLat: number, initLng: number) {
+ // eslint-disable-next-line max-len
+ const coordinatesRegex = '^(?[+-]?([0-9]*[.])?[0-9]+)$|^(?(-?)[0-9]+)°[ ]*((?[0-9]+)\'[ ]*((?[0-9]+)\")?)?$';
+ const latitude = new FormControl(String(initLat), [
+ Validators.required,
+ Validators.pattern(coordinatesRegex)
+ ]);
+ const longitude = new FormControl(String(initLng), [
+ Validators.required,
+ Validators.pattern(coordinatesRegex),
+ ]);
+ super({
+ latitude,
+ longitude
+ });
+ this.latitude = latitude;
+ this.longitude = longitude;
+ }
+
+}
+
+
diff --git a/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.module.ts b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.module.ts
new file mode 100644
index 00000000..0e4703bf
--- /dev/null
+++ b/projects/arlas-components/src/lib/components/bbox-generator/bbox-generator.module.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to Gisaïa under one or more contributor
+ * license agreements. See the NOTICE.txt file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Gisaïa licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { CommonModule } from '@angular/common';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatDialogModule } from '@angular/material/dialog';
+import { MatFormFieldModule } from '@angular/material/form-field';
+import { MatIconModule } from '@angular/material/icon';
+import { BrowserModule } from '@angular/platform-browser';
+import { TranslateModule } from '@ngx-translate/core';
+import { BboxGeneratorComponent } from './bbox-generator.component';
+import { NgModule } from '@angular/core';
+import { MatInputModule } from '@angular/material/input';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ BrowserModule,
+ FormsModule,
+ MatDialogModule,
+ MatFormFieldModule,
+ MatIconModule,
+ MatButtonModule,
+ MatInputModule,
+ ReactiveFormsModule,
+ TranslateModule
+ ],
+ declarations: [BboxGeneratorComponent],
+ exports: [BboxGeneratorComponent]
+})
+export class BboxGeneratorModule {
+
+}
diff --git a/projects/arlas-components/src/lib/components/mapgl/draw/draw.models.ts b/projects/arlas-components/src/lib/components/mapgl/draw/draw.models.ts
index e9f1a750..5b8a81b0 100644
--- a/projects/arlas-components/src/lib/components/mapgl/draw/draw.models.ts
+++ b/projects/arlas-components/src/lib/components/mapgl/draw/draw.models.ts
@@ -32,3 +32,15 @@ export interface EditionState {
isDrawing: boolean;
isEditing: boolean;
}
+
+export interface Corner {
+ lat: number;
+ lng: number;
+}
+
+export interface BboxDrawCommand {
+ east: number;
+ west: number;
+ north: number;
+ south: number;
+}
diff --git a/projects/arlas-components/src/lib/components/mapgl/draw/draw.service.ts b/projects/arlas-components/src/lib/components/mapgl/draw/draw.service.ts
index bf9b5a39..ff9b40d4 100644
--- a/projects/arlas-components/src/lib/components/mapgl/draw/draw.service.ts
+++ b/projects/arlas-components/src/lib/components/mapgl/draw/draw.service.ts
@@ -25,7 +25,7 @@ import { Feature, FeatureCollection, lineString } from '@turf/helpers';
import bbox from '@turf/bbox';
import length from '@turf/length';
import { Subject } from 'rxjs';
-import { AoiDimensions, EditionState } from './draw.models';
+import { AoiDimensions, BboxDrawCommand, Corner, EditionState } from './draw.models';
@Injectable()
export class MapboxAoiDrawService {
@@ -38,6 +38,9 @@ export class MapboxAoiDrawService {
private editAoiSource = new Subject();
public editAoi$ = this.editAoiSource.asObservable();
+ private drawBboxSource = new Subject();
+ public drawBbox$ = this.drawBboxSource.asObservable();
+
public bboxEditionState: EditionState;
public polygonEditionState: EditionState;
@@ -54,6 +57,19 @@ export class MapboxAoiDrawService {
};
}
+ public drawBbox(fCorner: Corner, sCorner: Corner) {
+ const west = Math.min(fCorner.lng, sCorner.lng);
+ const east = Math.max(fCorner.lng, sCorner.lng);
+ const south = Math.min(fCorner.lat, sCorner.lat);
+ const north = Math.max(fCorner.lat, sCorner.lat);
+ this.drawBboxSource.next({
+ west,
+ east,
+ south,
+ north
+ });
+ }
+
public enableBboxEdition() {
this.bboxEditionState.enabled = true;
this.bboxEditionState.isDrawing = false;
diff --git a/projects/arlas-components/src/lib/components/mapgl/mapgl.component.ts b/projects/arlas-components/src/lib/components/mapgl/mapgl.component.ts
index 55763b4e..72fcc423 100644
--- a/projects/arlas-components/src/lib/components/mapgl/mapgl.component.ts
+++ b/projects/arlas-components/src/lib/components/mapgl/mapgl.component.ts
@@ -49,7 +49,7 @@ import StaticMode from '@mapbox/mapbox-gl-draw-static-mode';
import * as styles from './model/theme';
import { getLayerName } from '../componentsUtils';
import { MapboxAoiDrawService } from './draw/draw.service';
-import { AoiDimensions } from './draw/draw.models';
+import { AoiDimensions, BboxDrawCommand } from './draw/draw.models';
import { BasemapStyle } from './basemaps/basemap.config';
import { MapboxBasemapService } from './basemaps/basemap.service';
import { ArlasBasemaps } from './basemaps/basemaps';
@@ -443,11 +443,17 @@ export class MapglComponent implements OnInit, AfterViewInit, OnChanges, OnDestr
private drawSelectionChanged = false;
private finishDrawTooltip: HTMLElement;
private aoiEditSubscription: Subscription;
+ private drawBboxSubscription: Subscription;
public constructor(private http: HttpClient, private drawService: MapboxAoiDrawService,
private basemapService: MapboxBasemapService,
private _snackBar: MatSnackBar, private translate: TranslateService) {
this.aoiEditSubscription = this.drawService.editAoi$.subscribe(ae => this.onAoiEdit.emit(ae));
+ this.drawBboxSubscription = this.drawService.drawBbox$.subscribe({
+ next: (bboxDC: BboxDrawCommand) => {
+ this.drawBbox(bboxDC.east, bboxDC.south, bboxDC.west, bboxDC.north);
+ }
+ });
}
@@ -1389,6 +1395,9 @@ export class MapglComponent implements OnInit, AfterViewInit, OnChanges, OnDestr
if (!!this.offlineBasemapChangeSubscription) {
this.offlineBasemapChangeSubscription.unsubscribe();
}
+ if (!!this.drawBboxSubscription) {
+ this.drawBboxSubscription.unsubscribe();
+ }
}
public selectFeaturesByCollection(features: Array, collection: string) {
@@ -1668,35 +1677,7 @@ export class MapglComponent implements OnInit, AfterViewInit, OnChanges, OnDestr
const north = Math.max(startlat, endlat);
const east = Math.max(startlng, endlng);
const south = Math.min(startlat, endlat);
- const coordinates = [[
- [east, south],
- [east, north],
- [west, north],
- [west, south],
- [east, south],
- ]];
- const polygonGeojson = {
- type: 'Feature',
- properties: {
- source: 'bbox'
- },
- geometry: {
- type: 'Polygon',
- coordinates: coordinates
- }
- };
- const geoboxdata = Object.assign({}, this.emptyData);
- geoboxdata.features = [];
- if (this.drawData && this.drawData.features && this.drawData.features.length > 0) {
- this.drawData.features.forEach(df => geoboxdata.features.push(df));
- }
- geoboxdata.features.push(polygonGeojson);
- /** This allows to keep the drawn box on the map. It will be overriden in ngOnChanges `changes['drawData']` */
- this.drawService.addFeatures(geoboxdata, /** deleteOld */ true);
- this.onAoiChanged.next(geoboxdata);
- this.isDrawingBbox = false;
- this.drawService.disableBboxEdition();
- this.drawService.endDimensionsEmission();
+ this.drawBbox(east, south, west, north);
if (this.box) {
this.box.parentNode.removeChild(this.box);
this.box = undefined;
@@ -1704,6 +1685,39 @@ export class MapglComponent implements OnInit, AfterViewInit, OnChanges, OnDestr
}
}
+
+ private drawBbox(east, south, west, north) {
+ const coordinates = [[
+ [east, south],
+ [east, north],
+ [west, north],
+ [west, south],
+ [east, south],
+ ]];
+ const polygonGeojson = {
+ type: 'Feature',
+ properties: {
+ source: 'bbox'
+ },
+ geometry: {
+ type: 'Polygon',
+ coordinates: coordinates
+ }
+ };
+ const geoboxdata = Object.assign({}, this.emptyData);
+ geoboxdata.features = [];
+ if (this.drawData && this.drawData.features && this.drawData.features.length > 0) {
+ this.drawData.features.forEach(df => geoboxdata.features.push(df));
+ }
+ geoboxdata.features.push(polygonGeojson);
+ /** This allows to keep the drawn box on the map. It will be overriden in ngOnChanges `changes['drawData']` */
+ this.drawService.addFeatures(geoboxdata, /** deleteOld */ true);
+ this.onAoiChanged.next(geoboxdata);
+ this.isDrawingBbox = false;
+ this.drawService.disableBboxEdition();
+ this.drawService.endDimensionsEmission();
+ }
+
private setStrokeLayoutVisibility(layerId: string, visibility: string): void {
const layer = this.layersMap.get(layerId);
if (layer.type === 'fill') {
diff --git a/projects/arlas-components/src/public-api.ts b/projects/arlas-components/src/public-api.ts
index 674adb2e..2b20a308 100644
--- a/projects/arlas-components/src/public-api.ts
+++ b/projects/arlas-components/src/public-api.ts
@@ -47,6 +47,8 @@ export { MapglLegendModule } from './lib/components/mapgl-legend/mapgl-legend.mo
export { MapglSettingsModule } from './lib/components/mapgl-settings/mapgl-settings.module';
export { MetricComponent } from './lib/components/metric/metric.component';
export { MetricModule } from './lib/components/metric/metric.module';
+export { BboxGeneratorComponent } from './lib/components/bbox-generator/bbox-generator.component';
+export { BboxGeneratorModule } from './lib/components/bbox-generator/bbox-generator.module';
export { PowerbarsComponent } from './lib/components/powerbars/powerbars.component';
export { PowerbarsModule } from './lib/components/powerbars/powerbars.module';
export {