2

I am using VueJS and Leaflet to show the map with special localisation. I have added the css leaflet on index.html as told in the documentation.

link rel="stylesheet" href="https://unpkg.com/leaflet@1.2.0/dist/leaflet.css">

But I have just a part of the map. I have to change the size of the screen to have all the map with the marker.

enter image description here

This is the vue where I implement the map (iMap.vue)

<template>
  <div id="professionnel">
    <b-row>
     <b-tabs>
        <b-tab title="A" >
            <div>
                <b-col class="col-12">
                    <div>Où nous joindre</div>
                </b-col>
            </div>
        </b-tab>
       <b-tab title="B">
            <div class="tab-content-active" >
                <b-col class="col-6">
                    <div>heure</div>
                </b-col>
                <b-col class="col-6 data_map">
                    <iMap1></iMap>
                </b-col>
            </div>
        </b-tab>
      </tabs>
    </b-row>
  </div>
</template>

<script>
import iMap1 from './iMap1'

export default {
  name: 'professionnel',
  components: {
    iMap1
  },
  data() {
    return {}
  }
</script>

And this is the vue of the Map (iMap.vue)

    <template>
        <div id="imap1" class="map" >
        </div>
    </template>

    <script>

    import leaflet from 'leaflet'

    export default {
      name: 'imap1',
      components: {
        leaflet
      },
      data() {
        return {
            professionnel: {},
            map1: null,
            tileLayer: null,
        }
      },
        methods: {
        initMap() {
            this.map1 = L.map('imap1').setView([47.413220, -1.219482], 12)
            this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png',
                      //'https://cartodb-basemaps-{s}.global.ssl.fastly.net/rastertiles/voyager/{z}/{x}/{y}.png',
            {
                maxZoom: 18,
                center: [47.413220, -1.219482],
                attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>, &copy; <a href="https://carto.com/attribution">CARTO</a>',
            }).addTo(this.map1)

 L.marker([47.413220, -1.219482]).addTo(this.map1).bindPopup('name')
                        .openPopup()

 this.map1.invalidateSize()

  })
 },
},
created () {
 this.initMap()
}

}
</script>
Y.Coding
  • 109
  • 3
  • 15
  • Possible duplicate of [Data-toggle tab does not download Leaflet map](https://stackoverflow.com/questions/36246815/data-toggle-tab-does-not-download-leaflet-map) – ghybs Jul 06 '18 at 09:42
  • Thank you for your answer. Actually I am adding the map on tabs. – Y.Coding Jul 06 '18 at 10:25
  • PIease I added this.map1.invalidateSize() to the code but nothing changes. Can you see the code below. Thank you for your answer. – Y.Coding Jul 06 '18 at 11:03
  • 1
    make sure the `imap1` element is visible on screen before running your code, as it will do miscalculations if the element does not have dimensions. – Gabriele Petrioli Jul 06 '18 at 11:04
  • If you do not know how to listen to when your tab becomes visible, you can try using a `setTimeout` as a first approach. If you need further help, please make sure to provide an [MCVE](https://stackoverflow.com/help/mcve). – ghybs Jul 06 '18 at 11:06
  • Please I put my code below so you can see if something is not well coded. I thank you for your help. – Y.Coding Jul 06 '18 at 13:11

1 Answers1

2

Use the mounted lifecycle hook instead of the created one.

created is typically to subscribe to some data / start some async processes, whereas mounted is rather when the DOM of your component is ready (but not necessarily insterted in the page IIRC).

Then, as explained in Data-toggle tab does not download Leaflet map, you have to use invalidateSize after the Tab that contains your Map container is opened, i.e. you have to listen to an event that signals that your user has opened the Tab.

In the case of Bootstrap-Vue, you have the <b-tabs>'s "input" event, but which signals only when the user has clicked on the Tab. But the latter is still not opened. Therefore you have to give it a short delay (typically with setTimeout) before calling invalidateSize:

Vue.use(bootstrapVue);

Vue.component('imap', {
  template: '#imap',
  methods: {
    resizeMap() {
      if (this.map1) {
        this.map1.invalidateSize();
        // Workaround to re-open popups at their correct position.
        this.map1.eachLayer((layer) => {
          if (layer instanceof L.Marker) {
            layer.openPopup();
          }
        });
      }
    },
    initMap() {
      this.map1 = L.map('imap1').setView([47.413220, -1.219482], 12)
      this.tileLayer = L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
        maxZoom: 18,
        center: [47.413220, -1.219482],
        attribution: '&copy; <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>',
      }).addTo(this.map1)

      L.marker([47.413220, -1.219482]).addTo(this.map1).bindPopup('name')
        .openPopup() // Opening the popup while the map is incorrectly sized seems to place it at an incorrect position.
    },
  },
  mounted() {
    this.initMap()
  },
});

new Vue({
  el: '#app',
  methods: {
    checkMap(tab_index) {
      if (tab_index === 1) {
        // Unfortunately the "input" event occurs when user clicks
        // on the tab, but the latter is still not opened yet.
        // Therefore we have to wait a short delay to allow the
        // the tab to appear and the #imap1 element to have its final size.
        setTimeout(() => {
          this.$refs.mapComponent.resizeMap();
        }, 0); // 0ms seems enough to execute resize after tab opens.
      }
    }
  },
});
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.3.1/dist/leaflet.css" integrity="sha512-Rksm5RenBEKSKFjgI3a41vrjkw4EVPlJ3+OiI65vTjIdo9brlAacEuKOiQ5OFh7cOI1bkDwLqdLw3Zg0cRJAAQ==" crossorigin="" />
<script src="https://unpkg.com/leaflet@1.3.1/dist/leaflet-src.js" integrity="sha512-IkGU/uDhB9u9F8k+2OsA6XXoowIhOuQL1NTgNZHY1nkURnqEGlDZq3GsfmdJdKFe1k1zOc6YU2K7qY+hF9AodA==" crossorigin=""></script>
<script src="https://unpkg.com/vue@2"></script>
<link rel="stylesheet" href="https://unpkg.com/bootstrap@4/dist/css/bootstrap.css" />
<link rel="stylesheet" href="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.css" />
<script src="https://unpkg.com/bootstrap-vue@2.0.0-rc.11/dist/bootstrap-vue.js"></script>

<div id="app">
  <!-- https://bootstrap-vue.js.org/docs/components/tabs -->
  <b-tabs @input="checkMap">
    <b-tab title="First Tab" active>
      <br>I'm the first fading tab
    </b-tab>
    <b-tab title="Second Tab with Map">
      <imap ref="mapComponent"></imap>
    </b-tab>
  </b-tabs>
</div>

<template id="imap">
  <div id="imap1" style="height: 130px;"></div>
</template>
tony19
  • 125,647
  • 18
  • 229
  • 307
ghybs
  • 47,565
  • 6
  • 74
  • 99