Skip to content
Snippets Groups Projects
LayerSelector.vue 6.01 KiB
Newer Older
<template>
  <div class="basemaps-items ui accordion styled">
    <div
      :class="['basemap-item title', { active }]"
      @click="activateGroup(basemap)"
    >
      {{ basemap.title }}
    </div>
    <div
      v-if="isQueryable(basemap)"
      :id="`queryable-layers-selector-${basemap.id}`"
    >
      <strong>Couche requêtable</strong>
      <Dropdown
        :options="getQueryableLayers(basemap)"
        :selected="selectedQueryLayer"
        :search="true"
        @update:selection="onQueryLayerChange($event)"
      />
    </div>
    <div
      :id="`list-${basemap.id}`"
      :class="['content', { active }]"
      :data-basemap-index="basemap.id"
    >
      <div
        v-for="(layer, index) in basemap.layers"
        :key="basemap.id + '-' + layer.id + '-' + index"
        class="layer-item transition visible item list-group-item"
        :data-id="layer.id"
      >
        <!-- layer id is used for retrieving layer when changing order -->
        <p class="layer-handle-sort">
          <i
            class="th icon"
            aria-hidden="true"
          />
          {{ layer.title }}
        </p>
        <label>Opacité &nbsp;<span>(%)</span></label>
        <div class="range-container">
          <input
            type="range"
            min="0"
            max="1"
            :value="layer.opacity"
            step="0.01"
            @change="updateOpacity($event, layer)"
          ><output class="range-output-bubble">{{
            getOpacity(layer.opacity)
          }}</output>
        </div>
        <div class="ui divider" />
      </div>
    </div>
  </div>
</template>

<script>
import Sortable from 'sortablejs';

import Dropdown from '@/components/Dropdown.vue';
import mapService from '@/services/map-service';


export default {
  name: 'LayerSelector',

  components: {
    Dropdown,
  },

  props: {
    basemap: {
      type: Object,
      default: null,
    },
    baseMaps: {
      type: Array,
      default: () => [],
    },
    activeBasemap: {
      type: Object,
      default: () => {},
    },
  },

  data() {
    return {
      selectedQueryLayer: null,
    };
  },

  computed: {
    active() {
      return this.basemap.active !== undefined && this.basemap.active;
    },
  },

  mounted() {
    setTimeout(this.initSortable.bind(this), 1000);
  },

  methods: {
    isQueryable(baseMap) {
      const queryableLayer = baseMap.layers.filter((l) => l.queryable === true);
      return queryableLayer.length > 0;
    },

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

    onlayerMove() {
      // Get the names of the current layers in order.
      const currentLayersNamesInOrder = Array.from(
        document.getElementsByClassName('layer-item transition visible')
      ).map((el) => parseInt(el.attributes['data-id'].value));
      // Create an array to put the layers in order.
      let movedLayers = [];

      for (const layerName of currentLayersNamesInOrder) {
        movedLayers.push(
          this.activeBasemap.layers.filter((el) => el.id === 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
      this.setLocalstorageMapOptions(this.baseMaps);
    },

    initSortable() {
      this.baseMaps.forEach((basemap) => {
        const element = document.getElementById(`list-${basemap.id}`);
        if (element) {
          this. sortable = new Sortable(element, {
            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),
          });
        } else {
          console.error(`list-${basemap.id} not found in dom`);
        }
      });
    },

    onQueryLayerChange(layer) {
      this.selectedQueryLayer = layer.name;
      const baseMap = this.baseMaps[0].layers.find((l) => l.title === layer.name);
      if (baseMap) {
        baseMap.query = true;
      } else {
        console.error('No such param \'query\' found among basemap[0].layers');
      }
      layer.query = true;
    },

    getQueryableLayers(baseMap) {
      const queryableLayer = baseMap.layers.filter((l) => l.queryable === true);
      return queryableLayer.map((x) => {
        return {
          name: x.title,
          value: x,
        };
      });
    },
    
    activateGroup(basemap) {
      this.baseMaps.forEach((basemap) => (basemap.active = false));
      basemap.active = true;
      this.$emit('setActiveBasemap', basemap);
      basemap.title += ' '; //weird!! Force refresh
      this.$emit('addLayers', basemap);

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


    getOpacity(opacity) {
      return Math.round(parseFloat(opacity) * 100);
    },

    updateOpacity(event, layer) {
      mapService.updateOpacity(layer.id, event.target.value);
      layer.opacity = event.target.value;
    },
  }
};
</script>

<style>
.queryable-layers-dropdown {
  margin-bottom: 1em;
}
.queryable-layers-dropdown > label {
  font-weight: bold;
}
</style>