Add map picker
This commit is contained in:
parent
7ed3879d23
commit
1fe6511b0e
|
@ -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 { }
|
|
@ -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>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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 { }
|
|
@ -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>
|
|
@ -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: '© <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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 { }
|
|
@ -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>
|
|
@ -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);
|
||||
|
|
|
@ -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 },
|
||||
|
|
|
@ -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 |
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue