Skip to content
Snippets Groups Projects
SidebarLayers.vue 11.8 KiB
Newer Older
<template>
  <div :class="['sidebar-container', { expanded }]">
    <!-- <div class="sidebar-layers"></div> -->
    <div @click="expanded = !expanded" class="layers-icon">
      <!-- // ! svg point d'interrogation pas accepté par linter -->
      <!-- <?xml version="1.0" encoding="iso-8859-1"?> -->
      <svg
        version="1.1"
        id="Capa_1"
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        x="0px"
        y="0px"
        viewBox="0 0 491.203 491.203"
        style="enable-background: new 0 0 491.203 491.203"
        xml:space="preserve"
      >
        <g>
          <g>
            <path
              d="M487.298,326.733l-62.304-37.128l62.304-37.128c2.421-1.443,3.904-4.054,3.904-6.872s-1.483-5.429-3.904-6.872
                    l-62.304-37.128l62.304-37.128c3.795-2.262,5.038-7.172,2.776-10.968c-0.68-1.142-1.635-2.096-2.776-2.776l-237.6-141.6
                    c-2.524-1.504-5.669-1.504-8.192,0l-237.6,141.6c-3.795,2.262-5.038,7.172-2.776,10.968c0.68,1.142,1.635,2.096,2.776,2.776
                    l62.304,37.128L3.905,238.733c-3.795,2.262-5.038,7.172-2.776,10.968c0.68,1.142,1.635,2.096,2.776,2.776l62.304,37.128
                    L3.905,326.733c-3.795,2.262-5.038,7.172-2.776,10.968c0.68,1.142,1.635,2.096,2.776,2.776l237.6,141.6
                    c2.526,1.494,5.666,1.494,8.192,0l237.6-141.6c3.795-2.262,5.038-7.172,2.776-10.968
                    C489.393,328.368,488.439,327.414,487.298,326.733z M23.625,157.605L245.601,25.317l221.976,132.288L245.601,289.893
                    L23.625,157.605z M23.625,245.605l58.208-34.68l159.672,95.2c2.524,1.504,5.668,1.504,8.192,0l159.672-95.2l58.208,34.68
                    L245.601,377.893L23.625,245.605z M245.601,465.893L23.625,333.605l58.208-34.68l159.672,95.2c2.524,1.504,5.668,1.504,8.192,0
                    l159.672-95.2l58.208,34.68L245.601,465.893z"
            />
          </g>
        </g>
      </svg>
    </div>

    <div class="basemaps-title">
      <h4>
        Fonds cartographiques

        <!-- <span data-tooltip="Il est possible pour chaque fond cartographique de modifier l'ordre des couches"
            data-position="bottom left">
                <i class="question circle outline icon"></i>
            </span> -->
      </h4>
    </div>

    <div
      v-for="basemap in baseMaps"
      :key="`list-${basemap.id}`"
      class="basemaps-items ui accordion styled"
    >
      <div
        :class="{ active: isActive(basemap) }"
        class="basemap-item title"
        @click="activateGroup(basemap)"
      >
        {{ basemap.title }}
      </div>
      <div :id="`queryable-layers-selector-${basemap.id}`" v-if="isQueryable(basemap)">
        <b>Couche requêtable</b>
        <Dropdown 
          @update:selection="onQueryLayerChange($event)"
          :options="getQueryableLayers(basemap)"
          :selected="selectedQueryLayer"
          :search="true"
        />

      </div>
      <div
        :class="{ active: isActive(basemap) }"
        class="content"
        :id="`list-${basemap.id}`"
        :data-basemap-index="basemap.id"
          :key="basemap.id + '-' + layer.id + '-' + index"
          class="layer-item transition visible item list-group-item" :data-id="layer.id"
          <p class="layer-handle-sort">
            <i class="th icon"></i>{{ layer.title }}
          </p>
          <label>Opacité &nbsp;<span>(%)</span></label>
          <div class="range-container">
            <!-- // todo : rendre réactif les valeurs et connectés avec store/Map -->
            <input
              @change="updateOpacity($event, layer)"
              type="range"
              min="0"
              max="1"
              :value="layer.opacity"
              step="0.01"
            /><output class="range-output-bubble">{{
              getOpacity(layer.opacity)
            }}</output>
          </div>
          <div class="ui divider"></div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import { mapUtil } from "@/assets/js/map-util.js";
import Dropdown from "@/components/Dropdown.vue";
import Sortable from 'sortablejs';
  components: {
    Dropdown,
  },
      selectedQueryLayer:null,
      activeBasemap:null,
      baseMaps: [],
      layers: [],
    isActive(basemap) {
Timothee P's avatar
Timothee P committed
      return basemap.active !== undefined && basemap.active;
    activateGroup(basemap) {
      this.baseMaps.forEach((basemap) => (basemap.active = false));
      basemap.active = true;
      this.activeBasemap=basemap;
      basemap.title += " "; //weird!! Force refresh

      let mapOptions = localStorage.getItem('geocontrib-map-options') || {};
        mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {};
      let project=this.$route.params.slug;
        mapOptions[project] = {
          ...mapOptions[project],
          'current-basemap-index': basemap.id
        };
        localStorage.setItem('geocontrib-map-options', JSON.stringify(mapOptions));


    updateOpacity(event, layer) {
      console.log(event.target.value, layer);
      mapUtil.updateOpacity(layer.id, event.target.value);
      layer.opacity = event.target.value;
    getOpacity(opacity) {
      return Math.round(parseFloat(opacity) * 100);
    onQueryLayerChange(layer){
      console.log(layer);
      this.selectedQueryLayer=layer.name;
    },
    isQueryable(baseMap){
      let queryableLayer=baseMap.layers.filter(l => l.queryable === true);
      return queryableLayer.length>0;
    },
    onlayerMove(event){
      console.log(event)
      // Get the names of the current layers in order.
      const currentLayersNamesInOrder = Array.from(document.getElementsByClassName('layer-item transition visible')).map(el => el.children[0].innerText);

      // Create an array to put the layers in order.
      let movedLayers = [];
             
      for (const layerName of currentLayersNamesInOrder) {
        movedLayers.push(this.activeBasemap.layers.filter(el => el.title === layerName)[0]);
      }

      // Remove existing layers undefined
      movedLayers = movedLayers.filter(function(x) {
        return x !== undefined;
      });
      const eventOrder = new CustomEvent('change-layers-order', {
        detail: {
          layers: movedLayers
        }
      })
      document.dispatchEvent(eventOrder);
      // Save the basemaps options into the localstorage
      console.log(this.baseMaps)
      this.setLocalstorageMapOptions(this.baseMaps)
    },
    setLocalstorageMapOptions(basemaps) {
      let mapOptions = localStorage.getItem('geocontrib-map-options') || {};
      mapOptions = mapOptions.length ? JSON.parse(mapOptions) : {};
      let project=this.$route.params.slug;
      mapOptions[project] = {
        ...mapOptions[project],
        'basemaps': basemaps
      };
      localStorage.setItem('geocontrib-map-options', JSON.stringify(mapOptions));
    },

    initSortable(){
      this.baseMaps.forEach((basemap) => {
         new Sortable(document.getElementById(`list-${basemap.id}`), {
            animation: 150,
            handle: '.layer-handle-sort', // The element that is active to drag
            ghostClass: 'blue-background-class',
            dragClass: 'white-opacity-background-class',
            onEnd: this.onlayerMove.bind(this)
          });
      });
    },

    // Check if there are changes in the basemaps settings. Changes are detected if:
  // - one basemap has been added or deleted
  // - one layer has been added or deleted to a basemap
  areChangesInBasemaps(basemapFromServer, basemapFromLocalstorage={}) {
    let isSameBasemaps = false;
    let isSameLayers = true;
    let isSameTitles = true;

    // Compare the length and the id values of the basemaps
    const idBasemapsServer = basemapFromServer.map(b => b.id).sort();
    const idBasemapsLocalstorage = basemapFromLocalstorage.length ? basemapFromLocalstorage.map(b => b.id).sort() : {};
    isSameBasemaps = (idBasemapsServer.length === idBasemapsLocalstorage.length
      && idBasemapsServer.every((value, index) => value === idBasemapsLocalstorage[index]))

    // For each basemap, compare the length and id values of the layers
    outer_block: {
      for(let basemapServer of basemapFromServer) {
        let idLayersServer = basemapServer.layers.map(b => b.id).sort();
        if (basemapFromLocalstorage.length){
          for (let basemapLocalstorage of basemapFromLocalstorage) {
            if (basemapServer.id === basemapLocalstorage.id) {
              let idLayersLocalstorage = basemapLocalstorage.layers.map(b => b.id).sort();
              isSameLayers = (idLayersServer.length === idLayersLocalstorage.length
                && idLayersServer.every((value, index) => value === idLayersLocalstorage[index]));
              if (!isSameLayers) {
                break outer_block;
              }
            }
          }
        }
      }

      // Compare basemaps titles
      const titlesBasemapsServer = basemapFromServer.map(b => b.title).sort();
      const titlesBasemapsLocalstorage = basemapFromLocalstorage.length ? basemapFromLocalstorage.map(b => b.title).sort() : {};

      isSameTitles = titlesBasemapsServer.every((title, index) => title === titlesBasemapsLocalstorage[index]);

      if (!isSameTitles) {
        break outer_block;
      }
    }
    return !(isSameBasemaps && isSameLayers && isSameTitles);
  },
    getQueryableLayers(baseMap){
      let queryableLayer=baseMap.layers.filter(l => l.queryable === true);
      return queryableLayer.map(x=>{
        return {
          name:x.title,
          value:x
        }
      });
    },
    addLayers(baseMap) {
      baseMap.layers.forEach((layer) => {
Timothee P's avatar
Timothee P committed
        var layerOptions = this.layers.find((l) => l.id === layer.id);
        console.log(layerOptions);
        layer = Object.assign(layer, layerOptions);
        layer.options.basemapId = baseMap.id;
      });
      mapUtil.removeLayers(mapUtil.getMap());
      // Reverse is done because the first layer in order has to be added in the map in last.
      // Slice is done because reverse() changes the original array, so we make a copy first
      mapUtil.addLayers(baseMap.layers.slice().reverse(), null, null);
  mounted() {
    this.baseMaps = this.$store.state.map.basemaps;
    let project=this.$route.params.slug;
    const mapOptions = JSON.parse(localStorage.getItem('geocontrib-map-options')) || {};
    if (mapOptions 
        && mapOptions[project]) {

      // If already in the storage, we need to check if the admin did some 
      // modification in the basemaps on the server side. The rule is: if one layer has been added
      // or deleted in the server, then we reset the localstorage.
      const baseMapsFromLocalstorage = mapOptions[project]['basemaps'];
      const areChanges = this.areChangesInBasemaps(this.baseMaps, baseMapsFromLocalstorage);

      if (areChanges) {
        mapOptions[project] = {
          'map-options': this.baseMaps,
          'current-basemap-index': 0,
        };
        localStorage.setItem('geocontrib-map-options', JSON.stringify(mapOptions));
      } else {
        this.baseMaps = baseMapsFromLocalstorage;
      }
    }

    
    this.layers = this.$store.state.map.layers;
    if (this.baseMaps.length > 0) {
      this.baseMaps[0].active = true;
       this.activeBasemap=this.baseMaps[0];
    } else {
      mapUtil.addLayers(
        null,
        this.$store.state.configuration.DEFAULT_BASE_MAP.SERVICE,
        this.$store.state.configuration.DEFAULT_BASE_MAP.OPTIONS
      );
    setTimeout(this.initSortable.bind(this),1000)
    
   


};
</script>

<style>
@import "../../assets/styles/sidebar-layers.css";
.queryable-layers-dropdown {
  margin-bottom: 1em;
}
.queryable-layers-dropdown > label {
  font-weight: bold;
}
</style>