New file |
0,0 → 1,529 |
import {NOMINATIM_OSM_URL,TbPlaces} from "./modules/Locality.js"; |
|
const tileLayers = { |
googleHybrid: [ |
'https://{s}.google.com/vt/lyrs=s,h&x={x}&y={y}&z={z}', |
{ |
attribution: '<a href="https://www.google.com" target="_blank">\xa9 Google Maps</a>', |
subdomains: ["mt0","mt1","mt2","mt3"], |
maxZoom: 20 |
} |
], |
osm: [ |
'https://osm.tela-botanica.org/tuiles/osmfr/{z}/{x}/{y}.png', |
{ |
attribution: 'Data © <a href="http://osm.org/copyright">OpenStreetMap</a>', |
maxZoom: 18 |
} |
] |
}; |
const defaultPosition = { |
lat: 47.0504, |
lng: 2.2347 |
}; |
const defaultCityZoom = 12; |
const defaultZoom = 4; |
const geometryFilterDefault = 'point'; |
const defaultMapIdAttr = 'tb-geolocation'; |
const markerImgBaseUrl = URL_BASE +'js/tb-geoloc/img/'; |
const markerIcon = L.Icon.extend({ |
options: { |
shadowUrl: markerImgBaseUrl +'marker-shadow.png', |
iconAnchor: new L.Point(12, 40),//correctly replaces the dot of the pointer |
iconSize: new L.Point(24,40), |
iconUrl: markerImgBaseUrl +'marker-icon.png', |
} |
}); |
const defaultPolylineOptions = { |
shapeOptions: { |
weight: 5 |
}, |
showLength: true, |
repeatMode: false |
}; |
|
const drawLocale = { |
edit: { |
handlers: { |
edit: { |
tooltip: { |
subtext: 'Cliquer sur annuler pour supprimer les changements', |
text: 'Déplacez les marqueurs pour modifier leur position' |
} |
}, |
remove: { |
tooltip: { |
text: 'cliquer sur une ligne pour supprimer' |
} |
} |
}, |
toolbar: { |
actions: { |
cancel: { |
text: 'Annuler', |
title: 'Annuler' |
}, |
clearAll: { |
text: 'Effacer', |
title: 'Tout effacer' |
}, |
save: { |
text: 'Sauvegarder', |
title: 'Sauvegarder les changements' |
} |
}, |
buttons: { |
edit: 'Editer', |
editDisabled: 'Rien à editer', |
remove: 'Supprimer', |
removeDisabled: 'Rien à supprimer' |
} |
} |
}, |
draw : { |
toolbar: { |
actions: { |
text: 'Annuler', |
title: 'Annuler' |
}, |
buttons: { |
polyline: 'Dessiner une ligne', |
marker: 'Pointer une position' |
}, |
finish: { |
text: 'Terminer', |
title: 'Terminer' |
}, |
undo: { |
text: 'Supprimer', |
title: 'Supprimer le dernier point' |
} |
}, |
handlers: { |
polyline: { |
tooltip: { |
start: 'Cliquer sur la carte pour placer le début de la ligne', |
cont: 'Positionner le prochain point et cliquer', |
end: 'Re-cliquer sur le dernier point pour finir la ligne' |
} |
}, |
marker: { |
tooltip: { |
start: 'Cliquer sur la carte pour placer le marqueur' |
} |
}, |
rectangle: {tooltip: {}}, |
simpleshape: {tooltip: {}}, |
circle: {tooltip: {}}, |
circlemarker: {tooltip: {}} |
} |
} |
}; |
|
/***************************************************/ |
|
export function Geoloc() { |
this.map = {}; |
this.coordinates = defaultPosition; |
this.geojson = {}; |
this.editableLayers = {}; |
this.defaultDrawControlOptions = {}; |
this.drawControl = {}; |
this.defaultEditOptions = false; |
this.layer = {}; |
}; |
|
Geoloc.prototype.init = function(suffix = '') { |
this.mapIdAttr = defaultMapIdAttr + suffix; |
this.geolocLabel = document.getElementById('geoloc-label' + suffix); |
this.initForm(); |
this.initEvts(); |
}; |
|
Geoloc.prototype.initForm = function() { |
this.mapEl = document.getElementById(this.mapIdAttr); |
this.zoom = this.mapEl.dataset.zoom || defaultZoom; |
this.geometryFilter = this.mapEl.dataset.typeLocalisation || geometryFilterDefault; |
|
const formSuffix = this.mapEl.dataset.formSuffix; |
|
this.latitudeEl = document.getElementById('latitude' + formSuffix); |
this.longitudeEl = document.getElementById('longitude' + formSuffix); |
}; |
|
Geoloc.prototype.initEvts = function() { |
this.initMap(); |
this.handleCoordinates(); |
this.onCoordinates(); |
if('point' === this.geometryFilter) { |
this.initSearchLocality(); |
} |
}; |
|
Geoloc.prototype.initMap = function() { |
this.map = this.createLocationMap(); |
|
// interactions with map |
this.map.on(L.Draw.Event.CREATED, evt => { |
this.layer = evt.layer; |
|
// created marker or polyline with drawControl |
// no more need this drawcontrol: remove |
// (polyline: another one will be added with only edit toolbar) |
this.map.removeControl(this.drawControl); |
|
if ('marker' === evt.layerType) { |
this.onMarkerCreated(); |
} else if ('polyline' === evt.layerType) { |
this.handlePolylineEvents(); |
} |
}); |
|
this.map.on(L.Draw.Event.EDITED, evt => { |
const layers = evt.layers; |
|
this.map.removeLayer(this.layer); |
|
layers.eachLayer(layer => { |
this.layer = layer; |
this.handlePolylineEvents(false); |
}); |
}); |
|
this.map.on(L.Draw.Event.DELETED, evt => { |
this.reSetDrawControl(); |
}); |
}; |
|
|
Geoloc.prototype.reSetDrawControl = function() { |
this.map.removeLayer(this.layer); |
this.map.removeControl(this.drawControl); |
this.setDrawControl(this.map); |
}; |
|
Geoloc.prototype.createLocationMap = function() { |
const lthis = this, |
map = L.map(this.mapIdAttr, {zoomControl: true, gestureHandling: true}).setView([this.coordinates.lat, this.coordinates.lng], this.zoom), |
tileLayer = this.mapEl.dataset.layer || 'osm'; |
|
L.tileLayer(...tileLayers[tileLayer]).addTo(map); |
|
this.editableLayers = new L.FeatureGroup(); |
map.addLayer(this.editableLayers); |
|
this.setDrawControl(map); |
|
return map; |
}; |
|
Geoloc.prototype.setDrawControl = function(map) { |
this.defaultDrawControlOptions = this.generateDrawControlOptions(); |
this.drawControl = this.generateDrawControl(...Object.values(this.defaultDrawControlOptions)); |
map.addControl(this.drawControl); |
}; |
|
Geoloc.prototype.generateDrawControlOptions = function() { |
const options = { |
editOptions: false, |
markerOptions: false, |
polylineOptions: false |
}; |
|
this.defaultEditOptions = { |
featureGroup: this.editableLayers,// REQUIRED!! |
remove: true |
} |
|
switch (this.geometryFilter) { |
case 'point': |
options.markerOptions = { |
icon: new markerIcon(), |
repeatMode: false |
}; |
break; |
case 'rue': |
options.polylineOptions = defaultPolylineOptions; |
break; |
default: |
break; |
} |
|
return options; |
}; |
|
Geoloc.prototype.generateDrawControl = function( |
editOptions, |
markerOptions = false, |
polylineOptions = false |
) { |
L.drawLocal = drawLocale; |
|
return new L.Control.Draw({ |
position: 'topleft', |
draw: { |
polyline: polylineOptions, |
polygon: false, |
circle: false, |
rectangle: false, |
marker: markerOptions, |
circlemarker: false |
}, |
edit: editOptions |
}); |
}; |
|
Geoloc.prototype.onMarkerCreated = function() { |
const coordinates = this.layer.getLatLng(); |
|
this.handleNewLocation(coordinates); |
}; |
|
Geoloc.prototype.handleMarkerEvents = function() { |
// move marker on click |
$(this.map).off('click').on('click', evt => this.handleNewLocation(evt.latlng).bind(this)); |
// move marker on drag |
$(this.map.marker).off('dragend').on('dragend', () => this.handleNewLocation(this.map.marker.getLatLng()).bind(this)); |
}; |
|
Geoloc.prototype.handlePolylineEvents = function(requiresNewEditDrawControl = true) { |
const latLngs = this.layer.getLatLngs(), |
polyline = this.formatPolyline(latLngs), |
coordinates = this.layer.getBounds().getCenter(); |
|
|
if (requiresNewEditDrawControl) { |
this.drawControl = this.generateDrawControl(this.defaultEditOptions); |
this.map.addControl(this.drawControl); |
} |
|
// make polyline removable |
this.editableLayers.addLayer(L.polyline(latLngs)); |
|
this.map.addLayer(this.layer); |
this.handleNewLocation(coordinates, polyline); |
}; |
|
/** |
* triggers location event |
* @param coordinates. |
* @param coordinates.lat latitude. |
* @param coordinates.lng longitude. |
* @param {array||null} polyline array of coordinates object |
*/ |
Geoloc.prototype.handleNewLocation = function (coordinates, polyline = []) { |
coordinates = this.formatCoordinates(coordinates); |
|
if(!!coordinates && !!coordinates.lat && coordinates.lng) { |
this.setMapPosition(coordinates); |
this.getLocationInfo(coordinates, polyline); |
} |
}; |
|
Geoloc.prototype.formatCoordinates = function (coordinates) { |
coordinates.lat = Number.parseFloat(coordinates.lat); |
coordinates.lng = Number.parseFloat(coordinates.lng); |
|
if(Number.isNaN(coordinates.lat) || Number.isNaN(coordinates.lng)) { |
return null; |
} |
|
return coordinates; |
}; |
|
Geoloc.prototype.formatPolyline = function (latLngs) { |
const polyline = []; |
|
latLngs.forEach(coordinates => polyline.push(Object.values(coordinates))); |
|
return polyline; |
}; |
|
Geoloc.prototype.setMapPosition = function (coordinates) { |
const latLng = new L.LatLng(coordinates.lat, coordinates.lng); |
|
|
this.coordinates = coordinates; |
if('point' === this.geometryFilter) { |
this.createDraggableMarker(latLng); |
this.handleMarkerEvents(); |
} |
// updates map |
this.map.setView(latLng); |
}; |
|
Geoloc.prototype.createDraggableMarker = function(latLng) { |
if (undefined === latLng) { |
latLng = new L.LatLng(this.coordinates.lat, this.coordinates.lng); |
} |
|
if (undefined === this.map.marker) { |
// after many attempts, did not manage |
// to make marker from draw control draggable |
// solution: replace it |
if(this.layer) { |
this.map.removeLayer(this.layer); |
} |
this.map.marker = new L.Marker(this.coordinates, { |
draggable: true, |
icon: new markerIcon() |
}); |
this.layer = this.map.marker; |
this.map.addLayer(this.map.marker); |
if(this.drawControl) { |
this.map.removeControl(this.drawControl); |
} |
} |
|
this.map.marker.setLatLng(latLng, {draggable: 'true'}); |
}; |
|
Geoloc.prototype.getLocationInfo = function(coordinates, polyline) { |
const lthis = this, |
url = NOMINATIM_OSM_URL+'reverse', |
params = { |
'format': 'json', |
'lat': coordinates.lat, |
'lon': coordinates.lng |
}; |
|
this.geolocLabel.classList.add('loading'); |
|
$.ajax({ |
method: "GET", |
url: url, |
data: params, |
success: function(locationData) { |
lthis.loadGeolocation(coordinates,locationData,polyline); |
}, |
error: (err) => { |
console.warn(err); |
lthis.geolocLabel.classList.remove('loading'); |
} |
}); |
}; |
|
Geoloc.prototype.loadGeolocation = function(coordinates,locationData,polyline) { |
const lthis = this, |
query = { |
'lat': coordinates.lat, |
'lon': coordinates.lng |
}; |
|
$.ajax({ |
method: "GET", |
url: URL_GEOLOC_SERVICE, |
data: query, |
success: function (geoLocationData) { |
lthis.triggerLocationEvent( |
lthis.formatLocationEventObject(coordinates,geoLocationData,locationData,polyline) |
); |
lthis.geolocLabel.classList.remove('loading'); |
}, |
error: (err) => { |
console.warn(err); |
lthis.geolocLabel.classList.remove('loading'); |
} |
}); |
}; |
|
Geoloc.prototype.triggerLocationEvent = function (locationDataObject) { |
const location = new CustomEvent('location', {detail: locationDataObject}); |
|
this.mapEl.dispatchEvent(location); |
}; |
|
Geoloc.prototype.formatLocationEventObject = function(coordinates,geoLocationData,locationData,polyline) { |
const detail = { |
centroid: { |
type: 'Point', |
coordinates: Object.values(coordinates) |
}, |
elevation: geoLocationData.altitude, |
inseeData: { |
code: geoLocationData.code_zone, |
nom: geoLocationData.nom |
}, |
osmCountry: locationData.address.country, |
osmCountryCode: geoLocationData.code_pays, |
osmCounty: locationData.address.county, |
osmPostcode:locationData.address.postcode, |
locality: this.getLocalityFromData(locationData), |
locality: geoLocationData.nom, |
osmRoad: locationData.address.road, |
osmState: locationData.address.state, |
osmId: locationData.osm_id, |
osmPlaceId: locationData.place_id |
}; |
|
if (0 < polyline.length) { |
detail.geometry = { |
type: 'LineString', |
coordinates: polyline |
}; |
} else { |
detail.geometry = detail.centroid; |
} |
|
return detail; |
} |
|
Geoloc.prototype.handleCoordinates = function() { |
if (!!this.latitudeEl.value && !!this.longitudeEl.value) { |
this.handleNewLocation({ |
'lat': this.latitudeEl.value, |
'lng': this.longitudeEl.value |
}); |
} |
}; |
|
Geoloc.prototype.onCoordinates = function() { |
[this.latitudeEl,this.longitudeEl].forEach(coordinate => |
coordinate.addEventListener('blur', function() { |
this.handleCoordinates(); |
}.bind(this)) |
); |
}; |
|
Geoloc.prototype.initSearchLocality = function() { |
const placesZone = document.getElementById('tb-places-zone'); |
|
if(placesZone) { |
placesZone.classList.remove('hidden'); |
this.tbPlaces = new TbPlaces(this.tbPlacesCallback.bind(this)); |
this.tbPlaces.init(); |
} |
}; |
|
Geoloc.prototype.tbPlacesCallback = function(localityData) { |
const locality = this.getLocalityFromData(localityData); |
|
if(!!locality) { |
const coordinates = { |
'lat' : localityData.lat, |
'lng' : localityData.lon |
}; |
|
this.map.removeControl(this.drawControl); |
this.handleNewLocation(coordinates); |
} |
}; |
|
Geoloc.prototype.getLocalityFromData = function(localityData) { |
const addressData = localityData.address, |
locationNameType = ['village', 'city', 'locality', 'municipality', 'county'].find(locationNameType => addressData[locationNameType] !== undefined); |
|
if (!locationNameType) { |
return; |
} |
|
return addressData[locationNameType]; |
}; |
|
Geoloc.prototype.closeMap = function () { |
// reset map |
this.map = L.DomUtil.get(this.mapIdAttr); |
if (this.map != null) { |
this.map._leaflet_id = null; |
} |
}; |