From df39c4bfba714c7d50558900d45b929933652ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Poussard?= <tpoussard@neogeo.fr> Date: Thu, 24 Aug 2023 16:11:18 +0200 Subject: [PATCH] geocoder increase limit, add coordinates, improve behavior & style --- src/components/Map/Geocoder.vue | 143 +++++++++++++++++++++++------ src/components/Map/Geolocation.vue | 2 +- src/services/map-service.js | 8 ++ 3 files changed, 126 insertions(+), 27 deletions(-) diff --git a/src/components/Map/Geocoder.vue b/src/components/Map/Geocoder.vue index 028a6a75..bced9885 100644 --- a/src/components/Map/Geocoder.vue +++ b/src/components/Map/Geocoder.vue @@ -1,20 +1,21 @@ <template> <div - :class="{ expanded: isExpanded }" - class="geocoder-container" + id="geocoder-container" + :class="{ isExpanded }" > <button class="button-geocoder" - @click="isExpanded = !isExpanded" + @click="toggleGeocoder" > <i class="search icon" /> </button> <Multiselect v-if="isExpanded" + ref="multiselect" v-model="selection" class="expanded-geocoder" :options="addresses" - :options-limit="5" + :options-limit="limit" :allow-empty="true" track-by="label" label="label" @@ -31,6 +32,7 @@ :preserve-search="true" @search-change="search" @select="select" + @open="retrievePreviousPlaces" @close="close" > <template @@ -76,14 +78,18 @@ const apiAdressAxios = axios.create({ baseURL: 'https://api-adresse.data.gouv.fr', withCredentials: false, }); + export default { name: 'Geocoder', + components: { Multiselect }, + data() { return { loading: false, + limit: 10, selection: null, text: null, selectedAddress: null, @@ -93,19 +99,36 @@ export default { isExpanded: false }; }, + mounted() { this.addressTextChange = new Subject(); this.addressTextChange.pipe(debounceTime(200)).subscribe((res) => this.getAddresses(res)); }, + methods: { + toggleGeocoder() { + this.isExpanded = !this.isExpanded; + if (this.isExpanded) { + this.retrievePreviousPlaces(); + this.$nextTick(()=> this.$refs.multiselect.activate()); + } + }, + getAddresses(query){ - const limit = 5; - apiAdressAxios.get(`https://api-adresse.data.gouv.fr/search/?q=${query}&limit=${limit}`) + if (query.length < 3) { + this.addresses = []; + return; + } + const coords = mapService.getMapCenter(); + let url = `https://api-adresse.data.gouv.fr/search/?q=${query}&limit=${this.limit}`; + if (coords) url += `&lon=${coords[0]}&lat=${coords[1]}`; + apiAdressAxios.get(url) .then((retour) => { this.resultats = retour.data.features; this.addresses = retour.data.features.map(x=>x.properties); }); }, + selectAddresse(event) { this.selectedAddress = event; if (this.selectedAddress !== null && this.selectedAddress.geometry) { @@ -122,27 +145,59 @@ export default { mapService.zoomTo(this.selectedAddress.geometry.coordinates, zoomlevel); // On ajoute un point pour localiser la ville mapService.addOverlay(this.selectedAddress.geometry.coordinates); + this.setLocalstorageSelectedAdress(this.selectedAddress); } }, + search(text) { this.text = text; this.addressTextChange.next(this.text); }, + select(e) { this.selectAddresse(this.resultats.find(x=>x.properties.label === e.label)); this.$emit('select', e); }, + close() { this.$emit('close', this.selection); - } + }, + + setLocalstorageSelectedAdress(newAdress) { + let selectedAdresses = JSON.parse(localStorage.getItem('geocontrib-selected-adresses')); + selectedAdresses = Array.isArray(selectedAdresses) ? selectedAdresses : []; + selectedAdresses = [ newAdress, ...selectedAdresses ]; + + const uniqueLabels = [...new Set(selectedAdresses.map(el => el.properties.label))]; + const uniqueAdresses = uniqueLabels.map((label) => { + return selectedAdresses.find(adress => adress.properties.label === label); + }); + + localStorage.setItem( + 'geocontrib-selected-adresses', + JSON.stringify(uniqueAdresses.slice(0, 5)) + ); + }, + + getLocalstorageSelectedAdress() { + return JSON.parse(localStorage.getItem('geocontrib-selected-adresses')) || []; + }, + + retrievePreviousPlaces() { + const previousAdresses = this.getLocalstorageSelectedAdress(); + if (previousAdresses.length > 0) { + this.addresses = previousAdresses.map(x=>x.properties); + this.resultats = previousAdresses; + } + }, } }; </script> -<style scoped lang="less"> -.geocoder-container { +<style lang="less"> +#geocoder-container { position: absolute; - right: 0.5em; + right: 6px; // each button have (more or less depends on borders) .5em space between // zoom buttons are 60px high, geolocation and full screen button is 34px high with borders top: calc(1.6em + 60px + 34px + 34px); @@ -151,7 +206,7 @@ export default { border: 2px solid rgba(0,0,0,.2); background-clip: padding-box; padding: 0; - border-radius: 2px; + border-radius: 4px; display: flex; .button-geocoder { @@ -161,8 +216,8 @@ export default { text-align: center; background-color: #fff; color: rgb(39, 39, 39); - width: 28px; - height: 28px; + width: 30px; + height: 30px; font: 700 18px Lucida Console,Monaco,monospace; border-radius: 2px; line-height: 1.15; @@ -180,21 +235,57 @@ export default { .expanded-geocoder { max-width: 400px; } -} -.expanded { - .button-geocoder { - height: 40px; - color: rgb(99, 99, 99); + &&.isExpanded { + .button-geocoder { + height: 41px; + color: rgb(99, 99, 99); + border-radius: 2px 0 0 2px; + } } -} -#marker { - width: 20px; - height: 20px; - border: 1px solid rgb(136, 66, 0); - border-radius: 10px; - background-color: rgb(201, 114, 15); - opacity: 0.7; + #marker { + width: 20px; + height: 20px; + border: 1px solid rgb(136, 66, 0); + border-radius: 10px; + background-color: rgb(201, 114, 15); + opacity: 0.7; + } + + // /* keep placeholder width when opening dropdown */ + .multiselect { + min-width: 208px; + } + /* keep font-weight from overide of semantic classes */ + .multiselect__placeholder, .multiselect__content, .multiselect__tags { + font-weight: initial !important; + } + /* keep placeholder eigth */ + .multiselect .multiselect__placeholder { + margin-bottom: 9px !important; + padding-top: 1px; + } + /* keep placeholder height when opening dropdown without selection */ + input.multiselect__input { + padding: 3px 0 0 0 !important; + } + /* keep placeholder height when opening dropdown with already a value selected */ + .multiselect__tags .multiselect__single { + padding: 1px 0 0 0 !important; + margin-bottom: 9px; + } + .multiselect__tags { + border: 0 !important; + min-height: 41px !important; + } + .multiselect input { + line-height: 1em !important; + padding: 0 !important; + } + .multiselect__content-wrapper { + border: 2px solid rgba(0,0,0,.2); + } } </style> + \ No newline at end of file diff --git a/src/components/Map/Geolocation.vue b/src/components/Map/Geolocation.vue index cc83f8c9..d94c83b4 100644 --- a/src/components/Map/Geolocation.vue +++ b/src/components/Map/Geolocation.vue @@ -51,7 +51,7 @@ button.button-geolocation { width: 30px; height: 30px; font: 700 18px Lucida Console,Monaco,monospace; - border-radius: 4px; + border-radius: 2px; line-height: 1.15; cursor: pointer; } diff --git a/src/services/map-service.js b/src/services/map-service.js index 01d6cd8b..b9c5b31c 100644 --- a/src/services/map-service.js +++ b/src/services/map-service.js @@ -714,6 +714,14 @@ const mapService = { stopEvent: false }); this.map.addOverlay(marker); + }, + + getMapCenter() { + const location = this.map.getView().getCenter(); + if (location) { + return transform(location, 'EPSG:3857', 'EPSG:4326'); + } + return null; } }; -- GitLab