apiplatform 2/2: filtrer les endroits les plus prôches par distance

Objectif
Filtrer à l’aide d’une map des endroits sauvegardés et récupérés à partir de apiplatform
l’idée est de proposer une interface angular capable de positionner un cercle sur une map, de choisir un centre et un rayon de recherche.
cet article et une continuation d’un article précédent intitulé récupérer les endroits les plus proches, prière à le consulter avant de lire celui la
Outils de travail
Pour pouvoir suivre cet article une connaissance préalable des outils suivant est recommandé:
- api-platform
- angular
- mysql
- Les dataproviders
- composant angular
Veuillez créer votre projet Angular, l’exemple suivant est mis dans un projet angular minimaliste
le plugin Gmap
Il existe plusieurs tentations pour mettre google map sous forme d’un plugin, y’on a une tentative dans le core officiel d’angular, et une autre (que je préfère)dont voici la commande pour l’installer
npm install @agm/core
Intégration
import { AgmCoreModule } from '@agm/core';
Générer la clé API Google Maps here
Ajoutez AgmCoreModule à votre tableau d’importations à l’intérieur du fichier app.module.ts.
imports: [ BrowserModule, AgmCoreModule.forRoot({ apiKey: environments.google_map_api_key }) ],
En ajoutant le composant Google Maps à un composant, nous pouvons déjà voir et utiliser la carte Google. La carte se comportera comme une carte par défaut avec la fonctionnalité par défaut, par exemple, vous pouvez zoomer et dézoomer et faire glisser la carte. Il nous reste seulement l’ajout des markeurs des différents endroits
<agm-map></agm-map>
Centrer la map avec votre position géolocalisé
ngOnInit(){ navigator.geolocation.getCurrentPosition(position => { this.location = { lat: position.coords.latitude, lng: position.coords.longitude, } }) }
Variables d’environnement
Configurer vos variables d »environnements dans le fichier environments/environments.ts
export const environment = { production: false, server: 'http://127.0.0.1:8000/', server_api: 'http://127.0.0.1:8000/api/', google_map_api_key: "Votre api ici" };
la requête vers api-platform
Si vous êtes en local et que vous tomber sur cette erreur

Ajouter votre adresse local via ces deux lignes dans le fichiers config/ packages / framework.yaml
trusted_hosts:
- localhost
- 127.0.0.1
Filtrer par distance
La partie intéressante commence, comment récupérer les endroits relative à une distance donnée ?
Bien évidement, la bonne pratique nous encourage de créer un service pour consommer l’api, lancer cette commande angular pour créer rapidement un service
ng g service services/place
Le code de base du service
import { Injectable } from '@angular/core'; import {HttpClient} from "@angular/common/http"; import {environment} from "../../environments/environment"; import {debounceTime, map} from "rxjs/operators"; import {Observable} from "rxjs"; @Injectable({ providedIn: 'root' }) export class PlaceService { constructor(private http: HttpClient) { } fetch(params):Observable<any>{ return this.http.get(environment.server_api + 'places') .pipe(debounceTime(5000), map((res)=>{ return res; })); } }
Le code du composant
import {Component, OnInit} from '@angular/core'; import {PlaceService} from "../services/place.service"; interface Place { id?: number; name: string; description?: string; longitude: number; latitude: number; picture?: number; } interface Filter { longitude?: number; latitude?: number; distance?: number; } @Component({ selector: 'app-api-platform-part2', templateUrl: './api-platform-part2.component.html', styleUrls: ['./api-platform-part2.component.css'] }) export class ApiPlatformPart2Component implements OnInit { mapOptions: any = { radius: 10000, //100km by default, latitude: null, longitude: null }; filter: Filter = { distance: this.mapOptions.radius/1000 }; places: Array<Place> = []; isLoading:boolean = false; constructor(private placeService: PlaceService) { } ngOnInit(){ navigator.geolocation.getCurrentPosition(position => { this.mapOptions.latitude = this.filter.latitude = position.coords.latitude; this.mapOptions.longitude = this.filter.longitude = position.coords.longitude; this.fetchPlaces(); }) } private fetchPlaces(init: Boolean = false) { this.isLoading = true; this.placeService.fetch(this.filter) .subscribe((result)=>{ if (init){ this.places = []; } this.isLoading = false; result["hydra:member"].forEach((place)=>{ this.places.push(place); }); }); } mapCircleDragEndListener(event) { this.fetchPlaces(true); } mapCircleRadiusChangeListener(radius) { this.filter.distance = radius/1000; this.fetchPlaces(true); } mapCircleCenterChangeListener(event) { this.filter.latitude = event.lat; this.filter.longitude = event.lng; } }
Le html du composant
et on fini avec le html (il contient la configuration de la map et l’initialisation du cercle)
<div class="container"> <div class="map-container"> <agm-map *ngIf="mapOptions.latitude && mapOptions.longitude" [latitude]="mapOptions.latitude" [longitude]="mapOptions.longitude"> <agm-circle [latitude]="mapOptions.latitude" [longitude]="mapOptions.longitude" [radius]="mapOptions.radius" [fillColor]="'red'" [circleDraggable]="true" [editable]="true" (centerChange)="mapCircleCenterChangeListener($event)" (dragEnd)="mapCircleDragEndListener($event)" (radiusChange)="mapCircleRadiusChangeListener($event)" > </agm-circle> </agm-map> </div> <div class="result-container"> <ul> <li *ngFor="let place of places"> <img [src]="place.picture" style="margin: 3px; width: 50px; float: left;"/> <p><b>{{place.name}}</b>{{place.description}}</p> </li> </ul> </div> </div>