Leaflet重建地图后WMS图层不显示问题求助
Leaflet WMS图层切换后无法显示的问题修复
问题描述
我开发了一个Flask Python应用,流程是:用户在页面选择车辆,系统通过Ajax从数据库获取该车辆对应的WMS图层配置,在Leaflet的图层控件中提供对应的图层供勾选开关。所有船舶标记被整合到同一个图层组,减少复选框数量。
问题现象:首次选择车辆时功能完全正常,但切换到其他车辆后再切回原车辆,WMS图层在图层控件中显示为选中状态,但实际不会在地图上渲染出来。
原JavaScript代码
var vesselVar = null; var mapVessel = null; var layerControl = null; var baseMaps = null; var overlayMaps = null; var layerNameArr = null; var layerLinkArr = null; var baseMapArr = null; var myVessels = null; var sLayerName = null; var sUrl = null; var wmsOptions = null; var myWmsLayer = null; function myOnSelectedVessel() { let sSelectedVessel = $('#sSelectedVessel').find(":selected").text() if (sSelectedVessel.length > 0) { $.ajax({ url: '/vessel_map_set_vessel_id', data: { 'sSelectedVesselName': sSelectedVessel, }, type: 'POST', dataType: 'json', success: function (response) { if (response.result) { alert(response.msg); } myCreateOverlay(response.liVessels, response.liLastVesselPos, response.arrLeaflet.toString()); myCreateBaseLayers(); myCreateMap(response.lat, response.lon); mapVessel.panTo(new L.LatLng(parseFloat(response.lat), parseFloat(response.lon))); }, error: function (error) { alert("error in function vessel_map.myOnSelectedVessel"); } }); } } function myCreateVesselGroup(liVessels, liLastVesselPos) { try { myVessels = null; vesselVar = null; myVessels = L.layerGroup([]); vesselVar = []; let iLen = liLastVesselPos.length; const arrVesselNames = liVessels.toString().split(','); const arrVesselPos = liLastVesselPos.toString().split(','); let iCntVesselPos = 0; for (let iCn7 = 0; iCn7 < iLen; iCn7++) { arrPos = liLastVesselPos[iCn7]; myAddVesselMarker(arrVesselNames[iCn7], arrVesselPos[iCntVesselPos], arrVesselPos[iCntVesselPos + 1]); myVessels.addLayer(vesselVar[iCn7]); iCntVesselPos += 2; } } catch (err) { alert("Error in function myCreateBaseLayers: " + err.message); } } function myCreateOverlay(liVessels, liLastVesselPos, sLeafletWmsString) { try { if (mapVessel !== null) { if ((overlayMaps !== null) && (layerControl !== null)) { mapVessel.eachLayer(function (layer) { mapVessel.removeLayer(layer); }); } } overlayMaps = null; overlayMaps = {}; myCreateVesselGroup(liVessels, liLastVesselPos) overlayMaps['Vessels'] = myVessels; if (sLeafletWmsString.length > 1) { const arrLeaflet2 = sLeafletWmsString.split(',') let iLen = arrLeaflet2.length; for (let iCnt4 = 0; iCnt4 < iLen; iCnt4 += 2) { sLayerName = null; sLayerName = arrLeaflet2[iCnt4].toString(); wmsOptions = null; wmsOptions = {}; wmsOptions.layers = sLayerName; wmsOptions.format = 'image/png'; wmsOptions.transparent = true; wmsOptions.opacity = 0.5; sUrl = null; sUrl = arrLeaflet2[iCnt4 + 1]; myWmsLayer = null myWmsLayer = new L.tileLayer.wms(sUrl, wmsOptions); overlayMaps[sLayerName] = myWmsLayer; } } } catch (err) { alert("Error in function myCreateOverlay: " + err.message); } } function myCreateBaseLayers() { try { layerNameArr = null; layerLinkArr = null; baseMaps = null; layerNameArr = []; layerLinkArr = []; baseMaps = [] layerNameArr.push('OpenStreetMap'); layerLinkArr.push(L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19, attribution: 'OpenStreetMap', transparent: true })); for (iCn2 = 0; iCn2 < layerLinkArr.length; iCn2++) { baseMaps[layerNameArr[iCn2]] = layerLinkArr[iCn2]; } } catch (err) { alert("Error in function myCreateBaseLayers: " + err.message); } } function myAddVesselMarker(sTitle, dLat, dLon) { try { var markerOptions = {}; markerOptions.title = sTitle; markerOptions.clickable = true; markerOptions.draggable = false; var sPopupText = "Lat: " + dLat.toString() + ", Lon: " + dLon.toString(); vesselVar.push(L.marker([dLat, dLon], markerOptions).bindPopup(sPopupText)); } catch (err) { alert("Error in function myAddVesselMarker: " + err.message); } } function myCreateMap(dLatCenter, dLonCenter) { try { if (mapVessel !== null) { mapVessel.invalidateSize(); mapVessel.off(); mapVessel.remove(); } mapVessel = null; layerControl = null; mapVessel = new L.map('map', { center: [dLatCenter, dLonCenter], zoom: 13, layers: [layerLinkArr[0]] }); layerControl = new L.control.layers(baseMaps, overlayMaps).addTo(mapVessel); } catch (err) { alert("Error in function myCreateMap: " + err.message); } }
问题根源
每次切换车辆时都完全销毁并重建了Leaflet地图实例和图层控件。切回原车辆时,图层控件仅保留了名称的选中标记,但新创建的WMS图层实例与控件的选中状态没有关联,导致地图上未添加对应的新图层。此外,myCreateOverlay中移除所有图层的逻辑会删掉底图,造成不必要的闪烁和状态丢失。
修复方案
1. 新增状态保存变量
添加变量记录当前选中的overlay图层名称:
// 保存当前选中的overlay图层名称 var selectedOverlayLayers = [];
2. 修改myOnSelectedVessel函数
调整执行顺序,复用现有地图并恢复选中状态:
function myOnSelectedVessel() { let sSelectedVessel = $('#sSelectedVessel').find(":selected").text() if (sSelectedVessel.length > 0) { $.ajax({ url: '/vessel_map_set_vessel_id', data: { 'sSelectedVesselName': sSelectedVessel, }, type: 'POST', dataType: 'json', success: function (response) { if (response.result) { alert(response.msg); } // 保存当前选中状态(地图已存在时) if (mapVessel && layerControl) { selectedOverlayLayers = []; Object.keys(overlayMaps).forEach(layerName => { if (mapVessel.hasLayer(overlayMaps[layerName])) { selectedOverlayLayers.push(layerName); } }); } // 仅初始化一次底图 if (!baseMaps) { myCreateBaseLayers(); } // 创建新的overlay图层 myCreateOverlay(response.liVessels, response.liLastVesselPos, response.arrLeaflet.toString()); // 创建或更新地图 if (!mapVessel) { myCreateMap(response.lat, response.lon); } else { // 更新图层控件的overlay图层 layerControl.remove(); layerControl = L.control.layers(baseMaps, overlayMaps).addTo(mapVessel); // 恢复选中状态 selectedOverlayLayers.forEach(layerName => { if (overlayMaps[layerName]) { overlayMaps[layerName].addTo(mapVessel); } }); // 平移到目标位置 mapVessel.panTo(new L.LatLng(parseFloat(response.lat), parseFloat(response.lon))); } }, error: function (error) { alert("error in function vessel_map.myOnSelectedVessel"); } }); } }
3. 修改myCreateOverlay函数
仅清理旧的overlay图层,保留底图:
function myCreateOverlay(liVessels, liLastVesselPos, sLeafletWmsString) { try { // 清理旧的overlay图层(从地图上移除) if (mapVessel && overlayMaps) { Object.values(overlayMaps).forEach(layer => { if (mapVessel.hasLayer(layer)) { mapVessel.removeLayer(layer); } }); } overlayMaps = {}; myCreateVesselGroup(liVessels, liLastVesselPos) overlayMaps['Vessels'] = myVessels; if (sLeafletWmsString.length > 1) { const arrLeaflet2 = sLeafletWmsString.split(',') let iLen = arrLeaflet2.length; for (let iCnt4 = 0; iCnt4 < iLen; iCnt4 += 2) { sLayerName = arrLeaflet2[iCnt4].toString(); wmsOptions = { layers: sLayerName, format: 'image/png', transparent: true, opacity: 0.5 }; sUrl = arrLeaflet2[iCnt4 + 1]; myWmsLayer = new L.tileLayer.wms(sUrl, wmsOptions); overlayMaps[sLayerName] = myWmsLayer; } } } catch (err) { alert("Error in function myCreateOverlay: " + err.message); } }
4. 修改myCreateMap函数
仅在地图不存在时创建,并默认选中船舶图层:
function myCreateMap(dLatCenter, dLonCenter) { try { mapVessel = new L.map('map', { center: [dLatCenter, dLonCenter], zoom: 13, layers: [layerLinkArr[0]] }); layerControl = new L.control.layers(baseMaps, overlayMaps).addTo(mapVessel); // 默认选中Vessels图层 if (overlayMaps['Vessels']) { overlayMaps['Vessels'].addTo(mapVessel); selectedOverlayLayers.push('Vessels'); } } catch (err) { alert("Error in function myCreateMap: " + err.message); } }
内容的提问来源于stack exchange,提问作者user10028792
相关产品推荐
相关产品推荐

