AlexLavoie42 / Nuxt-Mapbox

Elegant Mapbox integration with Nuxt
81 stars 11 forks source link

Hide popups on initial load / target markers individually #58

Closed lisaschumann closed 1 year ago

lisaschumann commented 1 year ago

Hi there!

Thanks so much for such a great integration! A question on the popups; how do I hide them on initial load? They currently all display at once when the map loads.

Also, how do I target a marker individually and call a function on that marker click. In the mapbox docs I found you can target them each by their ID, but not sure how to retrieve that as with nuxt-mapbox are nested within HTML markup and not initiated like you would do while using mapbox directly.

<MapboxDefaultMarker v-for="item, index in geojson.features.value" :key="item.id" :lnglat="item.geometry.coordinates"
    :marker-id="`marker-${index}`" :options="{ color: '#21A34C'}">
    <MapboxDefaultPopup :pop-id="index" :lnglat="item.geometry.coordinates">
    </MapboxDefaultPopup>
</MapboxDefaultMarker>

Many thanks in advance for your help.

AlexLavoie42 commented 1 year ago

I am not sure how you could hide popups with mapbox, so you will have to do some research there.

To access popups & markers, there are the useMapboxMarker & useMapboxPopup composable. You will just need to pass in their respective id (make sure each one has a unique id, and for the popup component it should be popup-id instead of pop-id).

See #38 for adding html events.

Gants102 commented 1 year ago

I had the same issue, definitely possible through using the mapbox api. I used the plugin but was mainly using the api directly:

const mapData = useCleanUpGQL(data?.value.data.page)

    const mapBoxData = 
        mapData.map(venue => {
            return {
                'type': 'Feature',
                'properties': {
                'details': {
                  'title': venue.venueName,
                  'description': venue.description.text,
                  'url': venue.urlSlug,
                  'logo': {
                    'url': venue.logo.url,
                    'alt': venue.logo.altText,
                    'title': venue.logo.imageTitle,
                    },
                    'events': venue.venueEvents
                }
                },
                'icon': 'profile-logo', 
                'geometry': {
                'type': 'Point',
                'coordinates': [
                    venue.venueAddress.geoCoordinates.longitude,
                    venue.venueAddress.geoCoordinates.latitude   
                ]
                }
            }
        });

    const mapBoxLayer = {
        'type': 'FeatureCollection',
                    'features': 
                        mapBoxData

    }
    const {getWeekDay, getDay, nth} = useDateFormatter()
    useMapboxBeforeLoad('IBWVenues', (map)=>{
        map.on('load', () => {
          map.loadImage(
              '../map-icon.png',
              (error, image) => {
              if (error) throw error;

              // Add the image to the map style.
              map.addImage('IBW', image);
            map.addSource('pubs', {
                'type': 'geojson',
                'data': {
                    'type': 'FeatureCollection',
                    'features': 
                        mapBoxData     
                }
                });

                // Add a layer showing the places.
                map.addLayer({
                    'id': 'pubs',
                    'type': 'symbol',
                    'source': 'pubs',
                    'layout': {
                      'icon-image': 'IBW', // reference the image
                      'icon-size': .25,
                      'icon-anchor': 'bottom'
                      }
                });
              })
                // When a click event occurs on a feature in the places layer, open a popup at the
                // location of the feature, with description HTML from its properties.
                map.on('click', 'pubs', (e) => {
                // Copy coordinates array.
                const coordinates = e.features[0].geometry.coordinates.slice();
                const details = JSON.parse(e.features[0].properties.details);
                let events = ''
                const t = ()=> details.events.forEach(event => {
                  events = events + `<a class='eventLink' href="${event.urlSlug}" title="Link to ${event.eventName} page">
                    <span class="eventName">${event.eventName}</span> <span>${getWeekDay(event.eventStartDateTime)} ${getDay(event.eventStartDateTime)} ${nth(event.eventStartDateTime)}</span>
                    </a>`
                });
                t()
                console.log(events)
                const popupTemp = `
                  <div class="popupContent">
                    <a href="${details.url}" title="Link to ${details.title} page">
                      <img src="${details.logo.url}" alt="${details.logo.alt}" title="${details.logo.title}">
                    </a>
                    <h3>About ${details.title}</h3>
                    <p>${details.description.slice(0,200)}...</p>
                    <h3>${details.events?.length > 1 ? 'Events' : 'Event'}</h3>
                    ${events}
                  </div>
                `

                // Ensure that if the map is zoomed out such that multiple
                // copies of the feature are visible, the popup appears
                // over the copy being pointed to.
                while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
                coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
                }

                defineMapboxPopup('any', {closeButton: false, maxWidth: 'none', offset: 5, anchor: 'bottom' } );
                useMapboxPopup('any', (popup)=>{
                  popup.setLngLat(coordinates).setHTML(popupTemp).addTo(map);
                })
                });

                // Change the cursor to a pointer when the mouse is over the places layer.
                map.on('mouseenter', 'pubs', () => {
                map.getCanvas().style.cursor = 'pointer';
                });

                // Change it back to a pointer when it leaves.
                map.on('mouseleave', 'pubs', () => {
                map.getCanvas().style.cursor = '';
                });
        });
    })

Not the most elegant solution but works for what I need. Would be amazing if this sort of feature could be more baked in to the plugin.

Used these two articles for the code:

Popup on click

Popup on hover

dsdsdsdsdsds commented 11 months ago
useMapboxPopup(`popup-${index}`, (popup) => {
  popup.remove()
})
fparaggio commented 4 months ago

Anybody has been able to solve this?