Add map picker

This commit is contained in:
Matteo Gheza 2022-01-07 16:41:09 +01:00
parent 7ed3879d23
commit 1fe6511b0e
18 changed files with 191 additions and 37 deletions

View File

@ -0,0 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { EditServiceComponent } from './edit-service.component';
const routes: Routes = [{ path: '', component: EditServiceComponent }];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class EditServiceRoutingModule { }

View File

@ -53,14 +53,7 @@
</ng-container>
</div>
<label>Luogo dell'intervento</label>
<div id="map" style="height: 300px;" leaflet [leafletOptions]="options" (leafletMapReady)="mapReady($event)"></div>
<div id="search" class="mt-2">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Luogo">
<button class="btn btn-outline-secondary" type="button">Cerca</button>
</div>
<div id="results"></div>
</div>
<map-picker></map-picker>
<div class="form-group">
<label for="notes">Note (es. altre informazioni)</label><br>
<textarea class="form-control" id="notes"></textarea>

View File

@ -2,8 +2,6 @@ import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { ApiClientService } from 'src/app/_services/api-client.service';
import { ToastrService } from 'ngx-toastr';
import { latLng, tileLayer } from 'leaflet';
import "leaflet.locatecontrol";
@Component({
selector: 'app-edit-service',
@ -16,13 +14,6 @@ export class EditServiceComponent implements OnInit {
public types: any[] = [];
public addingType = false;
public newType = "";
public options = {
layers: [
tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '...' })
],
zoom: 5,
center: latLng(46.879966, -121.726909)
};
constructor(
private route: ActivatedRoute,
@ -68,10 +59,4 @@ export class EditServiceComponent implements OnInit {
this.loadTypes();
});
}
mapReady(map: any) {
console.log(map);
(window as any).L.control.locate().addTo(map);
}
}

View File

@ -0,0 +1,23 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { MapPickerModule } from '../map-picker/map-picker.module';
import { EditServiceRoutingModule } from './edit-service-routing.module';
import { EditServiceComponent } from './edit-service.component';
@NgModule({
declarations: [
EditServiceComponent
],
imports: [
CommonModule,
EditServiceRoutingModule,
FormsModule,
BsDatepickerModule.forRoot(),
MapPickerModule
]
})
export class EditServiceModule { }

View File

@ -0,0 +1,12 @@
<div id="map" style="height: 300px;" leaflet [leafletOptions]="options" (leafletMapReady)="mapReady($event)" (leafletClick)="mapClick($event)">
<div *ngIf="isMarkerSet" [leafletLayer]="marker"></div>
</div>
<div id="search" class="mt-2 mb-3">
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Luogo" [(ngModel)]="placeName" (keyup.enter)="searchPlace()">
<button class="btn btn-outline-secondary" type="button" (click)="searchPlace()">Cerca</button>
</div>
<div id="results" *ngIf="isPlaceSearchResultsOpen">
<li *ngFor="let result of placeSearchResults" (click)="selectPlace(result)">{{ result.display_name }}</li>
</div>
</div>

View File

@ -0,0 +1,103 @@
import { Component, OnInit } from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { ApiClientService } from 'src/app/_services/api-client.service';
import { LatLng, latLng, tileLayer, Marker, Map } from 'leaflet';
import "leaflet.locatecontrol";
@Component({
selector: 'map-picker',
templateUrl: './map-picker.component.html',
styleUrls: ['./map-picker.component.scss']
})
export class MapPickerComponent implements OnInit {
options = {
layers: [
tileLayer('http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors' })
],
zoom: 10,
center: latLng(45.88283872530, 10.18226623535)
};
isMarkerSet = false;
marker: Marker;
map: Map;
lc: any;
placeName = "";
isPlaceSearchResultsOpen = false;
placeSearchResults: any[] = [];
constructor(private toastr: ToastrService, private api: ApiClientService) {
this.marker = (window as any).L.marker(latLng(0,0));
this.map = undefined as unknown as Map;
}
ngOnInit(): void { }
setMarker(LatLng: LatLng) {
const iconRetinaUrl = "./assets/icons/marker-icon-2x.png";
const iconUrl = "./assets/icons/marker-icon.png";
const shadowUrl = "./assets/icons/marker-shadow.png";
const iconDefault = new (window as any).L.Icon({
iconRetinaUrl,
iconUrl,
shadowUrl,
iconSize: [25, 41],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
tooltipAnchor: [16, -28],
shadowSize: [41, 41]
});
this.marker.remove();
this.marker = (window as any).L.marker(LatLng, { icon: iconDefault });
this.isMarkerSet = true;
}
mapReady(map: any) {
this.map = map;
const this_class = this;
(window as any).L.Control.CustomLocate = (window as any).L.Control.Locate.extend({
_drawMarker: function () {
this_class.setMarker(this._event.latlng);
},
_onDrag: function () {},
_onZoom: function () {},
_onZoomEnd: function () {}
});
this.lc = new (window as any).L.Control.CustomLocate({
cacheLocation: false, // disabled for privacy reasons
initialZoomLevel: 16
}).addTo(map);
}
mapClick(e: any) {
console.log(e);
this.setMarker(e.latlng);
}
searchPlace() {
if(this.placeName.length < 3) {
this.toastr.error("Il nome della località deve essere di almeno 3 caratteri");
return;
}
this.api.get("https://nominatim.openstreetmap.org/search", {
format: "json",
limit: 5,
q: this.placeName
}).then((places) => {
this.isPlaceSearchResultsOpen = true;
this.placeSearchResults = places;
}).catch((err) => {
console.error(err);
this.toastr.error("Errore di caricamento dei risultati della ricerca. Riprovare più tardi");
});
}
selectPlace(place: any) {
console.log(place);
let latlng = latLng(place.lat, place.lon);
this.setMarker(latlng);
this.map.setView(latlng, 16);
}
}

View File

@ -0,0 +1,22 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { LeafletModule } from '@asymmetrik/ngx-leaflet';
import { MapPickerComponent } from './map-picker.component';
@NgModule({
declarations: [
MapPickerComponent
],
imports: [
CommonModule,
FormsModule,
LeafletModule
],
exports: [
MapPickerComponent
]
})
export class MapPickerModule { }

View File

@ -1,5 +1,5 @@
<owner-image></owner-image>
<div class="text-center mb-4">
<button type="button" class="btn btn-primary" (click)="addService()" disabled>Aggiungi intervento</button>
<button type="button" class="btn btn-primary" (click)="addService()">Aggiungi intervento</button>
</div>
<app-table [sourceType]="'services'"></app-table>

View File

@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
@Injectable({
providedIn: 'root'
@ -26,6 +26,9 @@ export class ApiClientService {
}
public apiEndpoint(endpoint: string): string {
if(endpoint.startsWith('https')) {
return endpoint;
}
return this.apiRoot + endpoint;
}
@ -39,9 +42,12 @@ export class ApiClientService {
}, new URLSearchParams()).toString();
}
public get(endpoint: string) {
public get(endpoint: string, data: any = {}) {
return new Promise<any>((resolve, reject) => {
this.http.get(this.apiEndpoint(endpoint), this.requestOptions).subscribe((data: any) => {
this.http.get(this.apiEndpoint(endpoint), {
...this.requestOptions,
params: new HttpParams({ fromObject: data })
}).subscribe((data: any) => {
resolve(data);
}, (err) => {
reject(err);

View File

@ -4,7 +4,6 @@ import { RouterModule, Routes } from '@angular/router';
import { ListComponent } from './_components/list/list.component';
import { LogsComponent } from './_components/logs/logs.component';
import { ServicesComponent } from './_components/services/services.component';
//import { EditServiceComponent } from './_components/edit-service/edit-service.component';
import { TrainingsComponent } from './_components/trainings/trainings.component';
import { AuthorizeGuard } from './_guards/authorize.guard';
@ -14,7 +13,11 @@ const routes: Routes = [
{ path: 'list', component: ListComponent, canActivate: [AuthorizeGuard] },
{ path: 'logs', component: LogsComponent, canActivate: [AuthorizeGuard] },
{ path: 'services', component: ServicesComponent, canActivate: [AuthorizeGuard] },
//{ path: 'services/:id', component: EditServiceComponent, canActivate: [AuthorizeGuard] },
{
path: 'services/:id',
loadChildren: () => import('./_components/edit-service/edit-service.module').then(m => m.EditServiceModule),
canActivate: [AuthorizeGuard]
},
{ path: 'trainings', component: TrainingsComponent, canActivate: [AuthorizeGuard] },
{ path: "login/:redirect/:extraParam", component: LoginComponent },
{ path: "login/:redirect", component: LoginComponent },

View File

@ -6,8 +6,6 @@ import { FormsModule } from '@angular/forms';
import { ToastrModule } from 'ngx-toastr';
import { ModalModule } from 'ngx-bootstrap/modal';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { BsDatepickerModule } from 'ngx-bootstrap/datepicker';
import { LeafletModule } from '@asymmetrik/ngx-leaflet';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
@ -23,7 +21,6 @@ import { LoginComponent } from './_components/login/login.component';
import { ListComponent } from './_components/list/list.component';
import { LogsComponent } from './_components/logs/logs.component';
import { ServicesComponent } from './_components/services/services.component';
//import { EditServiceComponent } from './_components/edit-service/edit-service.component';
import { TrainingsComponent } from './_components/trainings/trainings.component';
import { UnauthorizedInterceptor } from './_providers/unauthorized-interceptor.provider';
@ -41,7 +38,6 @@ import { UnauthorizedInterceptor } from './_providers/unauthorized-interceptor.p
ListComponent,
LogsComponent,
ServicesComponent,
//EditServiceComponent,
TrainingsComponent
],
imports: [
@ -58,8 +54,6 @@ import { UnauthorizedInterceptor } from './_providers/unauthorized-interceptor.p
}),
ModalModule.forRoot(),
TooltipModule.forRoot(),
BsDatepickerModule.forRoot(),
//LeafletModule,
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: false && environment.production,
// Register the ServiceWorker as soon as the app is stable

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 696 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 618 B

View File

@ -3,9 +3,11 @@
@import "~bootstrap/scss/bootstrap.scss";
@import "~@fortawesome/fontawesome-free/css/all.css";
@import '~ngx-toastr/toastr';
//Leaving this here because in component.scss it doesn't work really well
@import '~ngx-bootstrap/datepicker/bs-datepicker.scss';
//@import '~leaflet/dist/leaflet.css';
//@import '~leaflet.locatecontrol/dist/L.Control.Locate.min.css';
@import '~leaflet/dist/leaflet.css';
@import '~leaflet.locatecontrol/dist/L.Control.Locate.min.css';
.fa {
vertical-align: middle;