Skip to content
Snippets Groups Projects
Geocoder.vue 3.75 KiB
Newer Older
DESPRES Damien's avatar
DESPRES Damien committed
<template>
  <div class="geocoder">
    <Multiselect
      v-model="selection"
      :options="addresses"
      :options-limit="5"
      :allow-empty="true"
      track-by="label"
      label="label"
      :show-labels="false"
      :reset-after="true"
      select-label=""
      selected-label=""
      deselect-label=""
      :searchable="true"
      :placeholder="placeholder"
      :show-no-results="true"
      :loading="loading"
      :clear-on-select="false"
      :preserve-search="true"
      @search-change="search"
      @select="select"
      @close="close"
    >
      <template
        slot="option"
        slot-scope="props"
      >
        <div class="option__desc">
          <span class="option__title">{{ props.option.label }}</span>
        </div>
      </template>
      <template slot="clear">
        <div
          v-if="selection"
          class="multiselect__clear"
          @click.prevent.stop="selection = null"
        >
          <i class="close icon" />
        </div>
      </template>
      <span slot="noResult">
        Aucun résultat.
      </span>
      <span slot="noOptions">
        Saisissez les premiers caractères ...
      </span>
    </Multiselect>
    <div style="display: none;">
      <div
        id="marker"
        title="Marker"
      />
    </div>
  </div>
</template>

<script>
import Multiselect from 'vue-multiselect';
import { Subject } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import axios from 'axios';
import mapService from '@/services/map-service';
const apiAdressAxios = axios.create({
  baseURL: 'https://api-adresse.data.gouv.fr',
  withCredentials: false,
});
export default {
  name: 'Geocoder',
  components: {
    Multiselect
  },
  data() {
    return {
      loading: false,
      selection: null,
      text: null,
      selectedAddress: null,
      addresses: [],
      resultats: [],
      placeholder: 'Rechercher une adresse ...'
    };
  },
  mounted() {
    this.addressTextChange = new Subject();
    this.addressTextChange.pipe(debounceTime(200)).subscribe((res) => this.getAddresses(res));
  },
  methods: {
    getAddresses(query){
      // let self = this;
DESPRES Damien's avatar
DESPRES Damien committed
      const limit = 5;
      apiAdressAxios.get(`https://api-adresse.data.gouv.fr/search/?q=${query}&limit=${limit}`)
        .then((retour) => {
          this.resultats = retour.data.features;
          this.addresses = retour.data.features.map(x=>x.properties);
DESPRES Damien's avatar
DESPRES Damien committed
        });
    },
    selectAddresse(event) {
      this.selectedAddress = event;
      if (this.selectedAddress !== null && this.selectedAddress.geometry) {
        let zoomlevel = 14;
        const { type } = this.selectedAddress.properties;
DESPRES Damien's avatar
DESPRES Damien committed
        if (type === 'housenumber') {
          zoomlevel = 19;
        } else if (type === 'street') {
          zoomlevel = 16;
        } else if (type === 'locality') {
          zoomlevel = 16;
        } else if (type === 'municipality') {
          zoomlevel = 14;
        }
        // On fait le zoom
        mapService.zoomTo(this.selectedAddress.geometry.coordinates, zoomlevel);
        // On ajoute un point pour localiser la ville
        mapService.addOverlay(this.selectedAddress.geometry.coordinates);
      }
    },
    search(text) {
      this.text = text;
      this.addressTextChange.next(this.text);
    },
    select(e) {
      this.selectAddresse(this.resultats.find(x=>x.properties.label === e.label));
DESPRES Damien's avatar
DESPRES Damien committed
      this.$emit('select', e);
    },
    close() {
      this.$emit('close', this.selection);
    }
  }
};
</script>

<style scoped>
.geocoder{
  max-width: 400px;
  right: 500px;
  position: absolute;
  top: 20px;
  pointer-events: auto;
  z-index: 50000;
}
#marker {
    width: 20px;
    height: 20px;
    border: 1px solid rgb(136, 66, 0);
    border-radius: 10px;
    background-color: rgb(201, 114, 15);
    opacity: 0.7;
}
</style>