/* eslint-disable no-mixed-spaces-and-tabs */ /* eslint-disable no-unused-vars */ /* eslint-disable no-undef */ import L from "leaflet" import "leaflet/dist/leaflet.css"; import flip from '@turf/flip' import axios from '@/axios-client.js'; import "leaflet.vectorgrid"; import store from '@/store'; import { FillSymbolizer, PointSymbolizer, LineSymbolizer } from "@/assets/js/vector_tile_fix.js"; let map; let dictLayersToLeaflet = {}; var layerMVT; let statusList = [ { name: "Brouillon", value: "draft", }, { name: "Publié", value: "published", }, { name: "Archivé", value: "archived", }, { name: "En attente de publication", value: "pending", }, ]; L.TileLayer.BetterWMS = L.TileLayer.WMS.extend({ onAdd: function (map) { // Triggered when the layer is added to a map. // Register a click listener, then do all the upstream WMS things L.TileLayer.WMS.prototype.onAdd.call(this, map); map.on('click', this.getFeatureInfo, this); }, onRemove: function (map) { // Triggered when the layer is removed from a map. // Unregister a click listener, then do all the upstream WMS things L.TileLayer.WMS.prototype.onRemove.call(this, map); map.off('click', this.getFeatureInfo, this); }, getFeatureInfo: function (evt) { if (this.wmsParams.basemapId != undefined) { const queryableLayerSelected = document.getElementById(`queryable-layers-selector-${this.wmsParams.basemapId}`).getElementsByClassName('selected')[0].textContent; if (queryableLayerSelected.trim() === this.wmsParams.title.trim()) { // Make an AJAX request to the server and hope for the best var params = this.getFeatureInfoUrl(evt.latlng); var showResults = L.Util.bind(this.showGetFeatureInfo, this); axios.get( window.proxy_url, { params: params, //dataType: "json", } ).then(response => { let data = response.data; var err = typeof data === 'object' ? null : data; if (data.features || err) { showResults(err, evt.latlng, data); } }) .catch(error => { throw (error) //xhr.status; //xhr.responseText; } ) } } }, getFeatureInfoUrl: function (latlng) { // Construct a GetFeatureInfo request URL given a point var point = this._map.latLngToContainerPoint(latlng, this._map.getZoom()); var size = this._map.getSize(), params = { url: this._url, request: 'GetFeatureInfo', service: 'WMS', // srs: this.wmsParams.srs, srs: 'EPSG:4326', // styles: this.wmsParams.styles, // transparent: this.wmsParams.transparent, version: this.wmsParams.version, // format: this.wmsParams.format, bbox: this._map.getBounds().toBBoxString(), height: size.y, width: size.x, layers: this.wmsParams.layers, query_layers: this.wmsParams.layers, info_format: 'application/json' }; params[params.version === '1.3.0' ? 'i' : 'x'] = Math.floor(point.x); params[params.version === '1.3.0' ? 'j' : 'y'] = Math.floor(point.y); return params; }, showGetFeatureInfo: function (err, latlng, data) { let content; if (err) { content = ` <h4>${this.options.title}</h4> <p>Données de la couche inaccessibles</p> ` L.popup({ maxWidth: 800 }) .setLatLng(latlng) .setContent(content) .openOn(this._map); } else { // Otherwise show the content in a popup let contentLines = []; let contentTitle; if (data.features.length > 0) { Object.entries(data.features[0].properties).forEach(entry => { const [key, value] = entry; if (key !== 'bbox') { contentLines.push(`<div>${key}: ${value}</div>`); } }) contentTitle = `<h4>${this.options.title}</h4>`; content = contentTitle.concat(contentLines.join('')); L.popup({ maxWidth: 800 }) .setLatLng(latlng) .setContent(content) .openOn(this._map); } } } }); L.tileLayer.betterWms = function (url, options) { return new L.TileLayer.BetterWMS(url, options); }; const mapUtil = { getMap: () => { return map; }, createMap: function (el, options) { const { lat, lng, mapDefaultViewCenter, mapDefaultViewZoom, zoom, zoomControl = true, } = options; map = L.map(el, { maxZoom: 18, minZoom: 1, zoomControl: false, }).setView( [ !lat ? mapDefaultViewCenter[0] : lat, !lng ? mapDefaultViewCenter[1] : lng, ], !zoom ? mapDefaultViewZoom : zoom ); map.setMaxBounds( [[-90,-180], [90,180]] ) if (zoomControl) { L.control .zoom({ zoomInTitle: 'Zoomer', zoomOutTitle: 'Dézoomer', position: 'topright', }) .addTo(map); } L.control.scale().addTo(map); return map; }, addGeocoders: function (configuration) { let geocoder; const geocoderLabel = configuration.SELECTED_GEOCODER.PROVIDER; if (geocoderLabel && L.Control.Geocoder) { const LIMIT_RESULTS = 5; if ( geocoderLabel === configuration.GEOCODER_PROVIDERS.ADDOK ) { geocoder = L.Control.Geocoder.addok({ limit: LIMIT_RESULTS }); } else if ( geocoderLabel === configuration.GEOCODER_PROVIDERS.PHOTON ) { geocoder = L.Control.Geocoder.photon(); } else if ( geocoderLabel === configuration.GEOCODER_PROVIDERS.NOMINATIM ) { geocoder = L.Control.Geocoder.nominatim(); } L.Control.geocoder({ placeholder: "Chercher une adresse...", geocoder: geocoder, }).addTo(map); } }, addLayers: function (layers, serviceMap, optionsMap) { if (layers) { layers.forEach((layer) => { if (layer) { const options = layer.options; options.noWrap=true; if (options) { options.opacity = layer.opacity; if (layer.schema_type === 'wms') { let leafletLayer; if (layer.queryable) { options.title = layer.title; leafletLayer = L.tileLayer .betterWms(layer.service, options) .addTo(map); } else { leafletLayer = L.tileLayer .wms(layer.service, options) .addTo(map); } dictLayersToLeaflet[layer.id] = leafletLayer._leaflet_id; } else if (layer.schema_type === 'tms') { const leafletLayer = L.tileLayer(layer.service, options).addTo(map); dictLayersToLeaflet[layer.id] = leafletLayer._leaflet_id; } } } }); } else { optionsMap.noWrap=true; L.tileLayer(serviceMap, optionsMap).addTo(map); } }, // Remove the base layers (not the features) removeLayers: function () { map.eachLayer((leafLetlayer) => { if ( Object.values(dictLayersToLeaflet).includes(leafLetlayer._leaflet_id) ) { map.removeLayer(leafLetlayer); } }); dictLayersToLeaflet = {}; }, updateOpacity(layerId, opacity) { const internalLeafletLayerId = dictLayersToLeaflet[layerId]; map.eachLayer((layer) => { if (layer._leaflet_id === internalLeafletLayerId) { layer.setOpacity(opacity); } }); }, updateOrder(layers) { // First remove existing layers undefined layers = layers.filter(function (x) { return x !== undefined; }); // First remove existing layers map.eachLayer((leafLetlayer) => { layers.forEach((layerOptions) => { if (dictLayersToLeaflet[layerOptions.id] === leafLetlayer._leaflet_id) { map.removeLayer(leafLetlayer); } }); }); dictLayersToLeaflet = {}; // Redraw the layers this.addLayers(layers); }, retrieveFeatureColor: function (featureType, properties) { const colorsStyle = featureType.colors_style; if (featureType && colorsStyle && colorsStyle.custom_field_name) { const currentValue = properties[colorsStyle.custom_field_name]; const colorStyle = colorsStyle.colors[currentValue]; return colorStyle ? colorStyle : featureType.color } else{ return featureType.color; } }, addVectorTileLayer: function (url, project_slug, featureTypes, form_filters) { layerMVT = L.vectorGrid.protobuf(url, { noWrap:true, vectorTileLayerStyles: { "default": (properties) => { const featureType = featureTypes.find((x) => x.slug.split('-')[0] === '' + properties.feature_type_id); const color = this.retrieveFeatureColor(featureType, properties) const hiddenStyle = ({ radius: 0, fillOpacity: 0.5, weight: 0, fill: false, color: featureType.color, }) // Filtre sur le feature type if (form_filters && form_filters.type.selected) { if (featureType.title !== form_filters.type.selected) { return hiddenStyle; } } // Filtre sur le statut if (form_filters && form_filters.status.selected.value) { if (properties.status !== form_filters.status.selected.value) { return hiddenStyle; } } // Filtre sur le titre if (form_filters && form_filters.title) { if (!properties.title.toLowerCase().includes(form_filters.title.toLowerCase())) { return hiddenStyle; } } return ({ radius: 4, fillOpacity: 0.5, weight: 3, fill: true, color: color, }); }, }, // subdomains: "0123", // key: 'abcdefghi01234567890', interactive: true, maxNativeZoom: 18, getFeatureId: function (f) { return f.properties.id; } }); layerMVT.on('click', (e) => { // The .on method attaches an event handler const popupContent = this._createContentPopup(e.layer, featureTypes, project_slug); L.popup() .setContent(popupContent) .setLatLng(e.latlng) .openOn(map) }); layerMVT.addTo(map); window.layerMVT = layerMVT; }, addFeatures: function (features, filter, addToMap = true, featureTypes) { const featureGroup = new L.FeatureGroup(); features.forEach((feature) => { const featureProperties = feature.properties ? feature.properties : feature; const featureType = featureTypes.find((ft) => ft.slug === (featureProperties.feature_type.slug || featureProperties.feature_type)); let filters = []; if (filter) { const typeCheck = filter.featureType && featureProperties.feature_type.slug === filter.featureType; const statusCheck = filter.featureStatus && featureProperties.status.value === filter.featureStatus; const titleCheck = filter.featureTitle && featureProperties.title.includes(filter.featureTitle); filters = [typeCheck, statusCheck, titleCheck]; } if ( !filter || !Object.values(filter).some(val => val) || Object.values(filter).some(val => val) && filters.length && filters.every(val => val !== false) ) { const geomJSON = flip(feature.geometry || feature.geom); const popupContent = this._createContentPopup(feature); // Look for a custom field let customField; let customFieldOption; if (featureType.customfield_set && Object.keys(featureProperties).some(el => featureType.customfield_set.map(e => e.name).includes(el))) { customField = Object.keys(featureProperties).filter(el => featureType.customfield_set.map(e => e.name).includes(el)); customFieldOption = featureProperties[customField[0]]; } let color = this.retrieveFeatureColor(featureType, featureProperties) || featureProperties.color; if (color == undefined){ color = featureType.color; } const colorValue = color.value ? color.value : color; if (geomJSON.type === 'Point') { if ( customFieldOption && featureType.colors_style && featureType.colors_style.value && featureType.colors_style.value.icons && !!Object.keys(featureType.colors_style.value.icons).length ) { if (featureType.colors_style.value.icons[customFieldOption]) { const iconHTML = ` <i class="fas fa-${featureType.colors_style.value.icons[customFieldOption]} fa-lg" style="color: ${colorValue}" ></i> `; const customMapIcon = L.divIcon({ html: iconHTML, iconSize: [20, 20], className: 'myDivIcon', }); L.marker(geomJSON.coordinates, { icon: customMapIcon, color: colorValue, zIndexOffset: 100 }) .bindPopup(popupContent) .addTo(featureGroup); } else { L.circleMarker(geomJSON.coordinates, { color: color, radius: 4, fillOpacity: 0.5, weight: 3, }) .bindPopup(popupContent) .addTo(featureGroup); } } else { if (featureType.icon) { const iconHTML = ` <i class="fas fa-${featureType.icon} fa-lg" style="color: ${colorValue}" ></i> `; const customMapIcon = L.divIcon({ html: iconHTML, iconSize: [20, 20], className: 'myDivIcon', }); L.marker(geomJSON.coordinates, { icon: customMapIcon, color: colorValue, zIndexOffset: 100 }) .bindPopup(popupContent) .addTo(featureGroup); } else { L.circleMarker(geomJSON.coordinates, { color: color, radius: 4, fillOpacity: 0.5, weight: 3, }) .bindPopup(popupContent) .addTo(featureGroup); } } } else if (geomJSON.type === 'LineString') { L.polyline(geomJSON.coordinates, { color: colorValue, weight: 3, }) .bindPopup(popupContent) .addTo(featureGroup); } else if (geomJSON.type === 'Polygon') { L.polygon(geomJSON.coordinates, { color: colorValue, weight: 3, fillOpacity: 0.5, }) .bindPopup(popupContent) .addTo(featureGroup); } } }); if (map && addToMap) { map.addLayer(featureGroup); } return featureGroup; }, addMapEventListener: function (eventName, callback) { map.on(eventName, callback); }, _createContentPopup: function (feature, featureTypes, project_slug) { const formatDate = (current_datetime) => { let formatted_date = current_datetime.getFullYear() + "-" + ("0" + (current_datetime.getMonth() + 1)).slice(-2) + "-" + ("0" + current_datetime.getDate()).slice(-2) + " " + ("0" + current_datetime.getHours()).slice(-2) + ":" + ("0" + current_datetime.getMinutes()).slice(-2); return formatted_date; } let feature_type; let status; let date_maj; let feature_type_url; let feature_url; if (feature.properties) { status = feature.properties.status; date_maj = feature.properties.updated_on; feature_type_url = feature.properties.feature_type_url; feature_url = feature.properties.feature_url; } else { status = feature.status; date_maj = feature.updated_on; feature_type_url =feature.feature_type_url; feature_url = feature.feature_url; } if (featureTypes) { // => VectorTile feature_type = featureTypes.find((x) => x.slug.split('-')[0] === '' + feature.properties.feature_type_id); status = statusList.find((x) => x.value === feature.properties.status).name; date_maj = formatDate(new Date(feature.properties.updated_on)); feature_type_url = '/geocontrib/projet/' + project_slug + '/type-signalement/' + feature_type.slug + '/'; feature_url = feature_type_url + 'signalement/' + feature.properties.feature_id + '/'; //status=feature.properties.status; } else { feature_type = feature.properties ? feature.properties.feature_type : feature.feature_type; status = feature.properties ? feature.properties.status.label : feature.status.label; } let author = ''; const creator = feature.properties ? feature.properties.creator : feature.creator if (creator) { author = creator.full_name ? `<div> Auteur : ${creator.first_name} ${creator.last_name} </div>` : creator.username ? `<div>Auteur: ${creator.username}</div>` : ''; } const title = feature.properties ? feature.properties.title : feature.title; return ` <h4> <a href="${feature_url}">${title}</a> </h4> <div> Statut : ${status} </div> <div> Type : <a href="${feature_type_url}"> ${feature_type.title} </a> </div> <div> Dernière mise à jour : ${date_maj} </div> ${author} `; }, }; export { mapUtil }