Rev 3867 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed
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 pointericonSize: 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.initMapCoordinates();this.initSearchLocality();};Geoloc.prototype.initMap = function() {this.map = this.createLocationMap();// interactions with mapthis.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.initMapCoordinates = function() {if (!!this.latitudeEl.value && !!this.longitudeEl.value) {this.setMapCoordinates({'lat': this.latitudeEl.value,'lng': this.longitudeEl.value});}this.onCoordinates();};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() {if(this.map) {const lthis = this;// move marker on click$(this.map).off('click').on('click', function(evt) {lthis.handleNewLocation(evt.originalEvent.latlng);});// move marker on drag$(this.map.marker).off('dragend').on('dragend', function() {lthis.handleNewLocation(lthis.map.marker.getLatLng());});}};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 removablethis.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.zoom = 20;this.setMapCoordinates(coordinates);if('point' === this.geometryFilter) {this.createDraggableMarker();this.handleMarkerEvents();}if (('rue' === this.geometryFilter && 0 < polyline.length) ||('point' === this.geometryFilter && 0 === polyline.length)) {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).reverse()));return polyline;};Geoloc.prototype.setMapCoordinates = function (coordinates) {this.coordinates = coordinates;// updates mapthis.map.setView(coordinates,this.zoom);};Geoloc.prototype.createDraggableMarker = function() {if (undefined === this.map.marker) {// after many attempts, did not manage// to make marker from draw control draggable// solution: replace itif(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(this.coordinates, {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) {locationData.centroid = lthis.formatPointTypeCoordinates(coordinates);locationData.geojson = 'rue' === lthis.geometryFilter ? {type: 'LineString', coordinates: polyline} : locationData.centroid;lthis.loadGeolocation(coordinates,locationData);},error: (err) => {console.warn(err);lthis.geolocLabel.classList.remove('loading');}});};Geoloc.prototype.formatPointTypeCoordinates = function(coordinates) {return {type : 'Point', coordinates: Object.values(coordinates).reverse()};};Geoloc.prototype.loadGeolocation = function(coordinates,locationData) {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(locationData,geoLocationData));lthis.geolocLabel.classList.remove('loading');},error: (err) => {console.warn(err);lthis.geolocLabel.classList.remove('loading');}});};Geoloc.prototype.triggerLocationEvent = function(locationDataObject) {const locationEvent = new CustomEvent('location', {detail: locationDataObject});this.mapEl.dispatchEvent(locationEvent);};Geoloc.prototype.formatLocationEventObject = function(locationData,geoLocationData) {const detail = {centroid: locationData.centroid,geometry: locationData.geojson,elevation: geoLocationData.altitude,inseeData: {code: 'FR' === geoLocationData.code_pays ? 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};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 = this.formatCoordinates({'lat' : localityData.lat,'lng' : localityData.lon});if(!!coordinates && !!coordinates.lat && !!coordinates.lng) {this.zoom = 20;this.setMapCoordinates(coordinates);if('point' === this.geometryFilter) {this.map.removeControl(this.drawControl);this.createDraggableMarker();this.handleMarkerEvents();}localityData.centroid = this.formatPointTypeCoordinates(coordinates);if('rue' !== this.geometryFilter && 'Polygon' === localityData.geojson.type ) {localityData.geojson = localityData.centroid;}this.loadGeolocation(coordinates,localityData);}}};Geoloc.prototype.getLocalityFromData = function(localityData) {const addressData = localityData.address,locationNameType = ['village', 'city', 'locality', 'municipality', 'county', 'state'].find(locationNameType => addressData[locationNameType] !== undefined);if (!locationNameType) {return;}return addressData[locationNameType];};Geoloc.prototype.closeMap = function () {// reset mapthis.map = L.DomUtil.get(this.mapIdAttr);if (this.map != null) {this.map._leaflet_id = null;}};