I have a leaflet map that shows different restaurants and hiking trails in an area. When the user clicks on a marker, I then display info about it in a div below.
However it would be good UX if when you click on a marker, it highlights itself on the map so you can see exactly which marker you're currently reading about.
However I can't seem to find a way to do this.
The markers are created by using a v-for loop through a JSON file of "location" objects, JSON example:
"locations": {
"restaurants": [{
"id": "R1",
"name": "El Rancho Grande",
"latlong": [
"36.90316216998795",
"-4.115129907833307"
],
"type": "Restaurant",
"description": "This is a description of the location",
"img": "https://www.viewranger.com/routelibrary/discoverywalks/axarquia/0115.jpg"
}
...
In my head, one method could be:
Create all markers and add to an array.
Add them all to the map.
When one is clicked, find that marker in the array, update its icon to show its currently selected.
Remove all markers.
Replot them all with the now updated marker.
However this method just seems too much so I'm doubting it.
Can anyone give me any ideas? Cheers!
Here is my map in the "Get To Know The Area" page:
...
<!-- ############# INTERACTIVE MAP ############# -->
<div class="area__map">
<div id="map-wrap">
<no-ssr>
<l-map :zoom="13" :center="[36.9023, -4.1139]" ref="map">
<l-tile-layer
url="http://{s}.tile.osm.org/{z}/{x}/{y}.png"
></l-tile-layer>
<!-- ############# CREATE RESTAURANT MARKERS ############# -->
<l-marker
v-for="restaurant in restaurants"
:key="restaurant.id"
:lat-lng="restaurant.latlong"
:icon="eatIcon"
v-on:click="getPin(restaurant.id)"
></l-marker>
<!-- ############# CREATE HIKING TRAIL MARKERS ############# -->
<l-marker
v-for="walk in walks"
:key="walk.id"
:lat-lng="walk.latlong"
:icon="walkIcon"
v-on:click="getPin(walk.id)"
></l-marker>
</l-map>
</no-ssr>
</div>
<!-- ############# SHOW CURRENT SELECTED MARKER INFO ############# -->
<div class="area__map__selected-pin">
<h3>{{ selectedPin.name }}</h3>
<h4>{{ selectedPin.type }}</h4>
<p>{{ selectedPin.description }}</p>
<img
v-if="selectedPin.img != ''"
:src="selectedPin.img"
class="area__map__selected-pin__selected-img"
/>
</div>
<div class="area__subheader triangle triangle-yellow"></div>
</div>
</template>
<script>
import json from '@/static/json/locations.json'
import { latLng, icon } from 'leaflet'
export default {
name: 'Area',
data: function () {
return {
// ############# INTRO VIDEO SETTINGS #############
videoLanguage: 'English',
englishSrc: 'https://www.youtube.com/embed/lRKmJqDbVsY',
spanishSrc: 'https://www.youtube.com/embed/q0WkEkIMmQo',
currentSrc: 'https://www.youtube.com/embed/lRKmJqDbVsY',
// ############# IMAGE GALLERY SETTINGS #############
swiperOption: {
grabCursor: true,
loop: true,
autoplay: {
delay: 5000,
disableOnInteraction: false,
},
pagination: {
el: '.swiper-pagination',
},
map: this.$refs.map,
},
// ############# ARRAY TO STORE GALLERY IMAGES #############
images: [],
locations: json.locations,
// ############# ARRAY TO STORE RESTAURANT OBJECTS #############
restaurants: [],
// ############# ARRAY TO STORE HIKING TRAIL OBJECTS #############
walks: [],
// ############# LEAFLET HIKING TRAIL MARKER ICON #############
walkIcon: icon({
iconUrl: '/MapMarkers/hiking.png',
iconSize: [20, 20],
iconAnchor: [16, 37],
}),
// ############# LEAFLET RESTAURANT MARKER ICON #############
eatIcon: icon({
iconUrl: '/MapMarkers/restaurant.png',
iconSize: [20, 20],
iconAnchor: [16, 37],
}),
// ############# STORE THE CURRENTLY SELECTED LOCATION DATA #############
selectedPin: {
name: 'Please click on a map pin for more information',
},
}
},
// ############# IMPORT THE IMAGES ON MOUNT #############
mounted() {
this.importImages(require.context('~/assets/AreaPictures/', true))
this.importLocations(this.locations)
console.log(this.fas)
},
methods: {
changeSrc() {
if (this.videoLanguage === 'English') {
this.currentSrc = this.englishSrc
} else {
this.currentSrc = this.spanishSrc
}
},
// ############# IMPORT GALLERY IMAGES #############
importImages(r) {
r.keys().forEach((key) => {
var path = key.substring(1) //-----THE PATH FOR SOME REASON CONTAINS A . SO I REMOVE IT
this.images.push({
imageURL: path, //----- CREATE A NEW OBJECT AND ADD IT TO IMAGES
})
})
},
// ############# SPLIT JSON DATA INTO RESTAURANT AND HIKING TRAIL ARRAYS #############
importLocations() {
this.restaurants = this.locations.restaurants
this.walks = this.locations.walks
},
// ############# FIND THE DATA OF THE CURRENTLY SELECTED MAP MARKER BY USING ITS ID #############
getPin(id) {
let item
if (id.includes('W')) {
for (let i = 0; i < this.walks.length; i++) {
item = this.walks[i]
if (item.id === id) {
this.selectedPin = item
}
}
} else if (id.includes('R')) {
for (let i = 0; i < this.restaurants.length; i++) {
item = this.restaurants[i]
if (item.id === id) {
this.selectedPin = item
}
}
} else {
window.alert('Error, no info on marker found')
}
},
},
}
</script>
<style lang="scss">
...
edit: Image for context
