OpenLayers 4多GeoJSON图层复选框控制弹窗信息异常求助
问题分析与解决方案:OpenLayers多图层弹窗显示异常
我希望通过复选框控制标记的显示与隐藏,每个标记点击时弹出包含对应GeoJSON文件信息的弹窗。单独勾选一个复选框时功能正常,但同时勾选两个复选框时,仅最后勾选的图层对应的弹窗信息正确,先勾选的图层弹窗仅显示“undefined”。例如勾选游泳池复选框时弹窗信息正确,再勾选停车场复选框后,游泳池的弹窗全部显示“undefined”,仅停车场弹窗信息正常。我怀疑两段代码未同时执行,请问有解决思路吗?
你的代码片段:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- Affichage correct de la page --> <title>Markers</title> <link rel="stylesheet" href="ol/ol.css"> <link rel="stylesheet" href="ol/ol3-layerswitcher.css"> <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x --> <script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script> <script src="ol/ol.js"></script> <script src="ol/ol3-layerswitcher.js"></script> <link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css" integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous"> <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.12/css/all.css" integrity="sha384-G0fIWCsCzJIMAVNQPfjH08cyYaUtMwjJwqiRKxxE/rx96Uroj1BtIQ6MLJuheaO9" crossorigin="anonymous"> <link rel="stylesheet" href="sidebar/css/ol3-sidebar.css" /> <script src="sidebar/js/ol3-sidebar.js"></script> <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script> </head> <body> <div id="map" class="map"></div> <div id="popup" class="ol-popup"> <a href="#" id="popup-closer" class="ol-popup-closer"></a> <div id="popup-content"></div> </div> <!--Sidemenu--> <div id="sidebar" class="sidebar collapsed"> <div class="sidebar-tabs"> <ul role="tablist"> <li><a href="#home" role="tab"><i class="fa fa-map-marker"></i></a></li> </ul> </div> <div class="sidebar-content"> <div class="sidebar-pane" id="home"> <h1 class="sidebar-header"> Marqueurs <span class="sidebar-close"><i class="fa fa-caret-left"></i></span> </h1> <br> <input type="checkbox" id="swimmpool" name="swimmpool" value="swimmpool"> <label for="subscribeNews">Swimming pools</label> <br><br> <input type="checkbox" id="parking" name="parking" value="parking"> <label for="subscribeNews">Parkings</label> </div> <div class="sidebar-pane" id="profile"> <h1 class="sidebar-header">Profile<span class="sidebar-close"><i class="fa fa-caret-left"></i></span></h1> </div> </div> </div> <script> //Layers var layer1 = new ol.source.TileWMS({ url: '...', params: {...}, attributions: '...' }); var layer2 = new ol.source.TileWMS({ url: '...', params: {...}, attributions: '...' }); var layer3 = new ol.source.TileWMS({ url: '...', params: {...}, attributions: '...' }); //Marker's style var parkvert = new ol.style.Style({ image: new ol.style.Icon(({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', src: 'image/parking-vert.png' })) }); var parkorange = new ol.style.Style({ image: new ol.style.Icon(({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', src: 'image/parking-orange.png' })) }); var parkrouge = new ol.style.Style({ image: new ol.style.Icon(({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', src: 'image/parking-rouge.png' })) }); var parknoir = new ol.style.Style({ image: new ol.style.Icon(({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', src: 'image/parking-noir.png' })) }); var style_swimmpool = new ol.style.Style({ image: new ol.style.Icon(({ anchor: [0.5, 46], anchorXUnits: 'fraction', anchorYUnits: 'pixels', src: 'image/sports-piscine.png' })) }); //GeoJSON files var swimmpoolLayer = new ol.source.Vector({ url: '...', format: new ol.format.GeoJSON() }); var parkingLayer = new ol.source.Vector({ url: '...', format: new ol.format.GeoJSON() }); var vectorLayer_Swimmpool = new ol.layer.Vector({ source: swimmpoolLayer }); var vectorLayer_Parking = new ol.layer.Vector({ source: parkingLa </script>
问题原因分析
这个问题不是两段代码没同时执行,而是你大概率为每个图层单独绑定了map.on('singleclick')事件——OpenLayers中同一个事件(比如singleclick)会被最后绑定的回调函数覆盖,前面的回调会直接失效。当你点击先勾选的图层标记时,实际执行的是最后绑定的那个回调,找不到对应图层的Feature,所以弹窗显示undefined。
两种解决思路及代码
方案1:全局统一处理点击事件
只绑定一次singleclick事件,在回调里判断点击的是哪个图层的Feature,再展示对应信息:
// 初始化弹窗Overlay var popup = document.getElementById('popup'); var popupContent = document.getElementById('popup-content'); var popupCloser = document.getElementById('popup-closer'); // 关闭弹窗逻辑 popupCloser.onclick = function() { popup.style.display = 'none'; popupCloser.blur(); return false; }; var overlay = new ol.Overlay({ element: popup, autoPan: true, autoPanAnimation: { duration: 250 } }); map.addOverlay(overlay); // 全局点击事件:统一处理所有图层的点击 map.on('singleclick', function(evt) { // 获取点击位置的Feature,同时过滤我们关心的图层 var feature = map.forEachFeatureAtPixel(evt.pixel, function(feature, layer) { return layer === vectorLayer_Swimmpool || layer === vectorLayer_Parking ? feature : null; }); if (feature) { var coordinate = evt.coordinate; var content = ''; var targetLayer = feature.getLayer(); // 根据图层类型拼接弹窗内容(替换成你GeoJSON里的实际属性名) if (targetLayer === vectorLayer_Swimmpool) { content = ` <h3>游泳池</h3> <p>名称:${feature.get('pool_name') || '无名称'}</p> <p>地址:${feature.get('address') || '无地址'}</p> `; } else if (targetLayer === vectorLayer_Parking) { content = ` <h3>停车场</h3> <p>名称:${feature.get('parking_name') || '无名称'}</p> <p>容量:${feature.get('capacity') || '未知'}</p> `; } popupContent.innerHTML = content; overlay.setPosition(coordinate); popup.style.display = 'block'; } else { // 点击空白处关闭弹窗 popup.style.display = 'none'; } });
方案2:为每个VectorLayer单独绑定click事件
OpenLayers的VectorLayer本身支持click事件,每个图层的事件独立,不会互相覆盖:
// 初始化弹窗Overlay(同方案1) var popup = document.getElementById('popup'); var popupContent = document.getElementById('popup-content'); var popupCloser = document.getElementById('popup-closer'); popupCloser.onclick = function() { popup.style.display = 'none'; popupCloser.blur(); return false; }; var overlay = new ol.Overlay({ element: popup, autoPan: true, autoPanAnimation: { duration: 250 } }); map.addOverlay(overlay); // 游泳池图层单独绑定click事件 vectorLayer_Swimmpool.on('click', function(evt) { var feature = evt.feature; var coordinate = evt.coordinate; var content = ` <h3>游泳池</h3> <p>名称:${feature.get('pool_name') || '无名称'}</p> <p>地址:${feature.get('address') || '无地址'}</p> `; popupContent.innerHTML = content; overlay.setPosition(coordinate); popup.style.display = 'block'; }); // 停车场图层单独绑定click事件 vectorLayer_Parking.on('click', function(evt) { var feature = evt.feature; var coordinate = evt.coordinate; var content = ` <h3>停车场</h3> <p>名称:${feature.get('parking_name') || '无名称'}</p> <p>容量:${feature.get('capacity') || '未知'}</p> `; popupContent.innerHTML = content; overlay.setPosition(coordinate); popup.style.display = 'block'; }); // 点击空白处关闭弹窗 map.on('singleclick', function(evt) { var feature = map.forEachFeatureAtPixel(evt.pixel, function(f) { return f; }); if (!feature) popup.style.display = 'none'; });
补充:复选框控制图层显示的正确逻辑
别忘了给复选框绑定事件,控制图层的可见性:
// 游泳池复选框 document.getElementById('swimmpool').addEventListener('change', function(e) { vectorLayer_Swimmpool.setVisible(e.target.checked); }); // 停车场复选框 document.getElementById('parking').addEventListener('change', function(e) { vectorLayer_Parking.setVisible(e.target.checked); });
内容的提问来源于stack exchange,提问作者Adrien
相关产品推荐
相关产品推荐

