How to embed a Leaflet map into a Reveal.js presentation?
Asked Answered
W

2

4

I am trying to create a presentation running on top of Reveal.js, which would include a Leaflet.js map within one of the slides. I have included all necessary Javascript & CSS files into my Reveal.js presentation and I can make the map appear on the slide.

However, the problem is: map tiles are not displayed correctly. Instead of the actual map tiles, all I am seeing is gray background and some horizontal black lines. I can zoom in/out and pan the map, and the black lines are moving accordingly.

There are no error message in the Javascript console, and the browser seems to be downloading map tiles from server exactly as it should. I believe the problem has something to do with the CSS code of Leaflet map tiles - .leaflet-tile within leaflet.css - being somehow incompatible with Reveal.js.

The question is: Does anyone know how to get around this issue? Or is it a deadend with no possible solution?

I have the following CSS for the <div id="map">:

#map {
    height:400px;
    width:100%;
}

EDIT: One obvious workaround for this is to use <iframe> tag to embed the map into the presentation. Seems to work just fine, and maybe it is better to keep the frameworks separated. However, the downside is that if there are several maps in the presentation, each within its own <iframe>, a copy of Leaflet.js is loaded to memory for each and every iframe.

EDIT #2: A better solution, it seems, is to use Polymaps instead of Leaflet.js. It seems that several Polymaps maps can be embedded into a reveal.js presentaion. No issues.

Washington answered 21/11, 2013 at 11:17 Comment(0)
P
1

I found it easily to do it with a web component, this way, the shadow dom will protect my leaflet map from the evil hands of reveals css

here is a repo with an example

<link rel="import" href="./leaflet-map.html">
...
<div class="reveal">
  <div class="slides">
    <section data-state="map">
       <leaflet-map></leaflet-map>
    </section>
  </div>
</div>

Here is the web component

<template id="leaflet-map-template">
<link rel="stylesheet" href="./bower_components/leaflet/dist/leaflet.css">
<div id="mapid" style="height: 500px"></div>
    <!-- LEAFLET JS -->
</template>
<script src="./bower_components/leaflet/dist/leaflet.js"></script>
<script>
    class LeafletMap extends HTMLElement {
        constructor () {
            super();
            let tmpl = document.currentScript.ownerDocument.querySelector('template')
            let shadowRoot = this.attachShadow({mode: 'open'})
            shadowRoot.appendChild(tmpl.content.cloneNode(true))

            let mapDiv = this.shadowRoot.getElementById('mapid')
            this.map = L.map(mapDiv).setView([19.39682052576622, -99.13478851318361], 13)
            // this.setAttribute('map', map)
            // Tiles de open street maps
            //L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(map)

            L.tileLayer('https://api.tiles.mapbox.com/v4/{id}/{z}/{x}/{y}.png?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw', {
                maxZoom: 18,
                attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, ' +
                    '<a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, ' +
                    'Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
                id: 'mapbox.streets'
            }).addTo(this.map)
            let myIcon = L.icon({
                iconUrl: './lentes.png',

                iconSize:     [40, 40], // size of the icon
                iconAnchor:   [20, 20], // point of the icon which will correspond to marker's location
                tooltipAnchor: [20,0]
            })
            L.marker(
                [19.418657758792698, -99.14065182209016],
                {icon: myIcon}
            ).bindTooltip('Ranchito').addTo(this.map)
        }

        resize() {
            this.map.invalidateSize()
        }
    }
    window.customElements.define('leaflet-map', LeafletMap)
</script>
Pervasive answered 6/7, 2018 at 18:46 Comment(0)
E
0

It might be happening because the #map element is hidden (due to the hidden slide) when it is initialized, so it cannot read the dimensions..

Try using map.invalidateSize(false); once your slide becomes visible..

Reveal.addEventListener( 'slidechanged', function( event ) {
    // event.previousSlide, event.currentSlide, event.indexh, event.indexv
    if (event.indexh == 5){ // assuming your 5th slide is the one with the map
        map.invalidateSize(false); // assuming that map holds the the reference to your leaflet instance
    }
} );
Effortless answered 21/11, 2013 at 12:29 Comment(3)
Thanks for your suggestion. However, I tried it, but it does not seem to change anything... I have understood that invalidateSize() only adjusts container size - in my case the container is shown properly and the problem only concerns map tiles.Washington
i figured that invalidating the size will cause a redraw, and was hoping that it would be solved with a forced redraw of the tiles.. Does it work if you put the map in the page (not in a slide, just at the root of the body) ? Also do you have a live demo of the page (or can recreate it in jsfiddle ?)Effortless
If I put the map in the body of the HTML, the tiles are displayed properly. As soon as the map is put inside the <div class="reveal"> element, the tiles turn into gray. Unfortunately I do not have a live demo at the moment, and probably it is not worth setting up one, because iframes can be used to work around the issue. Anyhow, thanks again for your effort!Washington

© 2022 - 2024 — McMap. All rights reserved.