在不可见的 div 中创建 lealetjs 地图

creating lealetjs map in an invisible div

我要在 remarkjs 幻灯片中添加 leafletjs 地图。如果包含地图 div 的幻灯片在网页初始加载时可见,则地图工作正常。但是,如果带有地图 div 的幻灯片不是可见幻灯片,则地图 div 是不可见的,因此传单地图无法正常工作,因为所有图块都未加载到 div.我想做的是将所有地图 div 加载到幻灯片中,无论它们在哪张幻灯片上,然后在包含地图的幻灯片出现时让它们正确显示。

更新: 建议的答案似乎应该回答我的问题,但我仍然卡住了,不确定我是否在正确的轨道上。以下是更多详细信息。

因为我可以在幻灯片中添加很多地图,所以我使用 class 地图名称 divs。

// css
.map { width: 100vh; height: 100vh; }

// html
<div class="map" data-lat="47" data-lon="106"></div>
<div class="map" data-lat="0" data-lon="0"></div>
<!-- possibly on a different slide -->
<div class="map" data-lat="30" data-lon="28"></div>

// js
var maps = []; // for storing map elements
var mapDivs = document.getElementsByClassName('map');

for (var i=0, j=mapDivs.length; i<j; i++) {
    var map = L.map(mapDivs[i]).setView(
        [mapDivs[i].dataset.lat, mapDivs[i].dataset.lon], 
        13
    );

    // store map for later
    maps.push(map);
    L.tileLayer(…).addTo(map);
}

slideshow.on('showSlide', function (slide) {
    for (var i=0, j=maps.length; i<j; i++) {
        maps[i].invalidateSize();
    }
});

我的逻辑是上面的方法应该可行,但实际上不行。我做错了什么?

Update2: map.invalidateSize() 答案确实是解决方案的一部分。我的错是我打电话给 slideshow.on('showSlide', fn) 但我真的应该打电话给 slideshow.on('afterShowSlide', fn)。后者使 remarkjs 有机会实际创建可能具有地图 div 的当前幻灯片,这反过来允许 map.invalidateSize() 正确触发并重新绘制地图。

leafletjs 需要 div 的宽度和高度 > 0px 存在,即可见,而不是隐藏,以下载所需的地图图块并显示地图。将地图 div 添加到 remarkjs 幻灯片意味着其中一个或多个 div 将在幻灯片启动时隐藏。因此,leafletjs 将无法在那些 div 中显示地图(随机图块将丢失),直到调整浏览器大小迫使 leafletjs 重新计算地图的大小 divs 并下载正确的图块。解决方案是在显示带有地图 div 的幻灯片时触发 map.invalidateSize() 方法。这是我最终的做法

/* css ******************************/
.map { width: 100vh; height: 100vh; }


<!---------------------------------------------
html
map divs possibly on different slides, with a
`map: true` property on each slide with a map
----------------------------------------------->

---
map: true
<div class="map" data-lat="47" data-lon="106"></div>
---
map: true
<div class="map" data-lat="0" data-lon="0"></div>
---
map: true
<div class="map" data-lat="30" data-lon="28"></div>

// js /////////////////////////////////////////
var maps = []; // for storing leaflet map elements
var mapDivs = document.getElementsByClassName('map');

for (var i=0, j=mapDivs.length; i<j; i++) {

    // store map for later
    maps.push(L.map(mapDivs[i]).setView(
        [mapDivs[i].dataset.lat, mapDivs[i].dataset.lon], 
        zoomLevel
    ));

    // add map to the tileLayer
    L.tileLayer(…).addTo(maps[i]);
}

// use the 'afterShowSlide' event to ensure the 
// map div has been created
slideshow.on('afterShowSlide', function (slide) {

    // only if the slide has a 'map' property
    if (slide.properties.map) {
        for (var i=0, j=maps.length; i<j; i++) {
            maps[i].invalidateSize();
        }
    }
});