Skip to content
Snippets Groups Projects
map-util.js 14.9 KiB
Newer Older
DESPRES Damien's avatar
DESPRES Damien committed
/* 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"
DESPRES Damien's avatar
DESPRES Damien committed
import "leaflet.vectorgrid";
leandro's avatar
leandro committed
axios.defaults.headers.common['X-CSRFToken'] = (name => {
  var re = new RegExp(name + "=([^;]+)");
  var value = re.exec(document.cookie);
  return (value != null) ? unescape(value[1]) : null;
})('csrftoken');

DESPRES Damien's avatar
DESPRES Damien committed
import { FillSymbolizer, PointSymbolizer, LineSymbolizer } from "@/assets/js/vector_tile_fix.js";
DESPRES Damien's avatar
DESPRES Damien committed
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].innerHTML;
      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(
            params: params,
            ).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;
              //console.log(status)
            }

      }
    }
  },

  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) {
      //console.log(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);
      } /* else {
        console.log('Pas de features trouvées pour cette couche');
      } */
    }
  }

});

L.tileLayer.betterWms = function (url, options) {
  return new L.TileLayer.BetterWMS(url, options);
};

const mapUtil = {
  getMap: () => {
    return map;
  },

  createMap: function (options) {
    const {
      lat,
      lng,
      mapDefaultViewCenter,
      mapDefaultViewZoom,
      zoom,
      zoomControl = true,
    } = options;

    map = L.map('map', {
      maxZoom: 18,
      zoomControl: false,
    }).setView(
      [
        !lat ? mapDefaultViewCenter[0] : lat,
        !lng ? mapDefaultViewCenter[1] : lng,
      ],
      !zoom ? mapDefaultViewZoom : zoom
    );

    if (zoomControl) {
      L.control
        .zoom({
          zoomInTitle: 'Zoomer',
          zoomOutTitle: 'Dézoomer',
          position: 'topright',
        })
        .addTo(map);
    }

    L.control.scale().addTo(map);

    return map;
  },
DESPRES Damien's avatar
DESPRES Damien committed
  addGeocoders: function(configuration){
    let geocoder;
    const geocoderLabel = configuration.SELECTED_GEOCODER.PROVIDER;
    if (geocoderLabel) {
      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();
      }
DESPRES Damien's avatar
DESPRES Damien committed
      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;
          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 {
      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);
  },
DESPRES Damien's avatar
DESPRES Damien committed
  // eslint-disable-next-line no-unused-vars
DESPRES Damien's avatar
DESPRES Damien committed
  addVectorTileLayer: function (url,project_slug,featureTypes,form_filters) {
    layerMVT = L.vectorGrid.protobuf(url, {
DESPRES Damien's avatar
DESPRES Damien committed
      vectorTileLayerStyles: {
        "default": function(properties, zoom) {
           // console.log(properties);
           
           let featureType=featureTypes.find((x)=>x.slug.split('-')[0]===''+properties.feature_type_id);
           let color=featureType.color;
           if(featureType.colors_style && featureType.colors_style.custom_field_name){
            let currentValue=properties[featureType.colors_style.custom_field_name];
            let colorValue=featureType.colors_style.colors[currentValue];
            if(colorValue) {
              color=colorValue;
            }
DESPRES Damien's avatar
DESPRES Damien committed

           }
           console.log(featureType);
DESPRES Damien's avatar
DESPRES Damien committed
           let 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: 14,
      getFeatureId: function(f) {
				return f.properties.id;
			}
    });
    let self=this;
    layerMVT.on('click', function(e) {    // The .on method attaches an event handler
      console.log(e);
      const popupContent = self._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) {
    let featureGroup = new L.FeatureGroup();
    features.forEach((feature) => {
DESPRES Damien's avatar
DESPRES Damien committed
      
      let featureType=featureTypes.find((x)=>x.slug.split('-')[0]===''+feature.properties.feature_type_id);
      if(feature.properties.feature_type != undefined){
        featureType=featureTypes.find((x)=>x.slug===''+feature.properties.feature_type);
      }
DESPRES Damien's avatar
DESPRES Damien committed
 
      if (filter) {
        const typeCheck = filter.featureType && feature.properties.feature_type.slug === filter.featureType;
        const statusCheck = filter.featureStatus && feature.properties.status.value === filter.featureStatus;
        const titleCheck = filter.featureTitle && feature.properties.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);

        const popupContent = this._createContentPopup(feature);
DESPRES Damien's avatar
DESPRES Damien committed
        let color=feature.properties.color;
        if(color==undefined){
          color=featureType.color;
        }
        if (geomJSON.type === 'Point') {
          L.circleMarker(geomJSON.coordinates, {
DESPRES Damien's avatar
DESPRES Damien committed
            color: color,
            radius: 4,
            fillOpacity: 0.5,
            weight: 3,
          })
            .bindPopup(popupContent)
            .addTo(featureGroup);
        } else if (geomJSON.type === 'LineString') {
          L.polyline(geomJSON.coordinates, {
DESPRES Damien's avatar
DESPRES Damien committed
            color: color,
            weight: 3,
          })
            .bindPopup(popupContent)
            .addTo(featureGroup);
        } else if (geomJSON.type === 'Polygon') {
          L.polygon(geomJSON.coordinates, {
DESPRES Damien's avatar
DESPRES Damien committed
            color: color,
            weight: 3,
            fillOpacity: 0.5,
          })
            .bindPopup(popupContent)
            .addTo(featureGroup);
        }
      }
    });
DESPRES Damien's avatar
DESPRES Damien committed
    if(addToMap){
      map.addLayer(featureGroup);
    }
    
    return featureGroup;
  },
  addMapEventListener: function (eventName, callback) {
    map.on(eventName, callback);
  },

DESPRES Damien's avatar
DESPRES Damien committed
  _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=feature.properties.status;
    let date_maj=feature.properties.updated_on;
    let feature_type_url=feature.properties.feature_type_url;
    let feature_url=feature.properties.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_type;
      status=feature.properties.status.label;
    }
     
    let author = "";
    if (feature.properties.creator) {
      author = feature.properties.creator.full_name
					Auteur : ${feature.properties.creator.first_name} ${feature.properties.creator.last_name}
				</div>`
        : feature.properties.creator.username ? `<div>Auteur: ${feature.properties.creator.username}</div>` : '';
DESPRES Damien's avatar
DESPRES Damien committed
						<a href="${feature_url}">${feature.properties.title}</a>
DESPRES Damien's avatar
DESPRES Damien committed
						Statut : ${status}
DESPRES Damien's avatar
DESPRES Damien committed
						Type : <a href="${feature_type_url}"> ${feature_type.title} </a>
DESPRES Damien's avatar
DESPRES Damien committed
						Dernière mise à jour : ${date_maj}