Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Way to add hover popup to a geoJSON layer element #66

Open
aarepuu opened this issue Dec 9, 2018 · 3 comments
Open

Way to add hover popup to a geoJSON layer element #66

aarepuu opened this issue Dec 9, 2018 · 3 comments

Comments

@aarepuu
Copy link

aarepuu commented Dec 9, 2018

Looking for a way to add popup without any specific coordinates and change coordinates on hovering an element on a map. Trying to achieve something similar as this Mapbox example.

Haven't found a good way to do it using the mgl-popup component yet, here's what I have:

<template lang="pug">
.continer.map-wrapper
  mgl-map.map-container(
    :accessToken="accessToken",
    :mapStyle.sync="mapStyle",
    @load="mapLoaded")
    mgl-navigation-control(position="top-right")
    mgl-geojson-layer(
      type="circle",
      :sourceId="geoJsonSource.properties.id"
      :layerId="geoJsonSource.properties.id"
      :source.sync="geoJsonSource.data",
      :paint="paint")
    mgl-popup(
      ref="popup",
      :coordinates="popupCoordinates",
      :closeButton="closeButton",
      :closeOnClick="closeOnClick",
      anchor="bottom")
      .map-popup-content {{ popupContent }}
</template>

<script>
import { 
  MglMap,
  MglNavigationControl,
  MglGeojsonLayer,
  MglPopup
} from 'vue-mapbox';

export default {
  name: 'ClusterMap',
  components: {
    MglMap,
    MglNavigationControl,
    MglGeojsonLayer,
  },
 data: () => ({
    accessToken: MAP_ACCESS_TOKEN,
    mapStyle: MAP_STYLE,
    popupCoordinates: [0,0],
    popupContent: null,
    closeButton: false,
    closeOnClick: false,
    geoJsonSource: {
      properties: { id: 'geopoints' },
      data: { //...some GeoJSON object }
    }
    paint: {
      'circle-color': '#11b4da',
      'circle-radius': 4,
      'circle-stroke-width': 1,
      'circle-stroke-color': '#fff',
    },
  }),
  methods: {
    mapLoaded(e) {
      e.map.on('mouseenter', 'geopoints', (event) => {
        e.map.getCanvas().style.cursor = 'pointer';
        const coordinates = event.features[0].geometry.coordinates.slice();
        const content = event.features[0].properties.name;

        // 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(event.lngLat.lng - coordinates[0]) > 180) {
          coordinates[0] += event.lngLat.lng > coordinates[0] ? 360 : -360;
        }
        this.popupCoordinates = coordinates;
        this.popupContent = content;
        this.$refs.popup.popup.addTo(e.map); // not the best way to do this
      });
      e.map.on('mouseleave', 'geopoints', () => {
        e.map.getCanvas().style.cursor = '';
        this.$refs.popup.popup.remove(); // not the best way to do this
      });
    },
  },
};
</script>
<style lang="sass" scoped>
.map-wrapper
  width: 100%
  height: 100%
  .map-container
    width: 100%
    height: 600px
</style>

Will produce:

screen shot 2018-12-09 at 15 51 11

Also having a similar issue to this one #55. And for some reason two popup elements are added to the map.

<div data-v-75ee5279="" id="map-6544415584706778" class="map-container mapboxgl-map">
....
  <div class="mapboxgl-popup mapboxgl-popup-anchor-bottom"
       style="transform: translate(-50%, -100%) translate(722px, 360px);">
    <div class="mapboxgl-popup-tip"></div>
    <div class="mapboxgl-popup-content"></div>
  </div>
  <div class="mapboxgl-popup mapboxgl-popup-anchor-bottom"
       style="transform: translate(-50%, -100%) translate(1062px, 345px);">
    <div class="mapboxgl-popup-tip"></div>
    <div class="mapboxgl-popup-content">
      <div data-v-75ee5279="" class="map-popup-content">Test Place</div>
    </div>
  </div>
</div>

Any ideas?
Thanks

@luizotcarvalho
Copy link

I'm having the same issue, debugging a little I find out that the method $_deferredMount on Popup.vue is called twice, creating two Popups in DOM, but when it is destroyed the remove method just remove one popup element.

I see two workarounds to fix this issue:
1 - add a parent class to map element when the popup is open and a css to hide all popups when this class is not present.
2 - manually remove all mapboxgl-popup elements with javascript on mouseleave

@soal
Copy link
Owner

soal commented Feb 8, 2019

@luizotcarvalho Thank you for the info.
Version 0.2 is coming at the end of the week. Component registration mechanism will be changed completely, $_deferredMount will be removed and I think this issue will be fixed. Stay tuned! =)

@aarepuu
Copy link
Author

aarepuu commented Feb 12, 2019

I did something similar to @luizotcarvalho recommendations. Here's how I do it:

/* my GeoPopup component */

<template lang="pug">
mgl-popup(
  ref="popup",
  :coordinates="getCoordinates",
  :closeButton="closeButton",
  :closeOnClick="closeOnClick")
  .map-popup-content.has-text-centered
    strong {{ content}}
</template>

<script>
import { MglPopup } from 'vue-mapbox';

export default {
  name: 'GeoPopup',
  components: {
    MglPopup,
  },
  props: {
    coordinates: {
      type: Array,
     default: undefined, /* this will not initialise the popup when you add it */
    },
    content: {
      type: Object,
      default() {
        return {};
      },
    },
    show: {
      type: Boolean,
      default: true,
    },
  },
  data: () => ({
    popupContent: null,
    closeButton: false,
    closeOnClick: false,
  }),
  watch: {
    show() {
      if (!this.show) {
        if (this.$refs.popup) { this.$refs.popup.popup.remove(); }
      } else if (this.$refs.popup) { this.$refs.popup.popup.addTo(this.$store.map); }
    },
  },
  computed: {
    getCoordinates() {
      // Here we can do stuff with the coordinates if needed
      // ...
      return this.coordinates;
    },
  },
  methods: {
  },
};
</script>

<style scoped>
</style>

And then I use the show parameter to show the popup or remove it from map. Not the best solution, but works for now. Looking forward to the new release!
Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants