You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Leaflet中两张地图间GeoJSON数据的联动高亮实现需求

实现跨地图GeoJSON要素悬停联动高亮

要实现悬停第二张地图的GeoJSON对象时自动高亮第一张地图中start_fid匹配的要素,我们需要调整事件处理逻辑,同时优化要素查找效率,具体步骤如下:

关键修改点

  • 预构建要素映射:提前将两个GeoJSON图层的要素按start_fid存入对象,避免每次悬停时遍历整个图层查找
  • 修改悬停事件处理:在第二张地图要素的mouseover事件中,通过映射找到第一张地图的对应要素并高亮;mouseout时重置两个要素的样式
  • 优化样式重置逻辑:确保能精准重置对应要素的样式,而不是只操作当前触发图层

修改后的完整代码

<!DOCTYPE html>
<html>
<head>
    <link href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.css" rel="stylesheet"/>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.5.1/leaflet.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <style>
        #mapid { 
            height: 100%; 
            width: 50%; 
            left: 0; 
            position: fixed; 
            z-index: 0; 
        }
        #mapid2 { 
            height: 100%; 
            width: 50%; 
            right: 0; 
            position: fixed; 
            z-index: 0; 
        }
    </style>
</head>
<body>
    <div id="mapid"></div>
    <div id="mapid2"></div>
    <script>
        var dat1 =({ 
            "type" : "FeatureCollection", 
            "name" : "NewFeatureType", 
            "features" : [ 
                { 
                    "type" : "Feature", 
                    "geometry" : { 
                        "type" : "Polygon", 
                        "coordinates" : [ [ [ 7.2518485112, 47.1390738345 ], [ 7.2540323762, 47.1390773819 ], [ 7.2540289251, 47.1400723508 ], [ 7.2518450195, 47.1400688032 ], [ 7.2518485112, 47.1390738345 ] ] ] 
                    }, 
                    "properties" : { "start_fid" : "504748" } 
                }, 
                { 
                    "type" : "Feature", 
                    "geometry" : { 
                        "type" : "Polygon", 
                        "coordinates" : [ [ [ 7.2565390484, 47.130837227 ], [ 7.2633719322, 47.1308479108 ], [ 7.2633626773, 47.1336579369 ], [ 7.2565294346, 47.1336472526 ], [ 7.2565390484, 47.130837227 ] ] ] 
                    }, 
                    "properties" : { "start_fid" : "862126" } 
                } 
            ] 
        });
        var dat2 =({ 
            "type" : "FeatureCollection", 
            "name" : "NewFeatureType", 
            "features" : [ 
                { 
                    "type" : "Feature", 
                    "geometry" : { 
                        "type" : "Point", 
                        "coordinates" : [ -19.9169596449, 32.1396903724 ] 
                    }, 
                    "properties" : { "start_fid" : "504748" } 
                }, 
                { 
                    "type" : "Feature", 
                    "geometry" : { 
                        "type" : "Point", 
                        "coordinates" : [ -19.924214327, 32.1530002773 ] 
                    }, 
                    "properties" : { "start_fid" : "862126" } 
                } 
            ] 
        });

        // 预构建要素映射,按start_fid存储图层
        const featureMap1 = {};
        const featureMap2 = {};

        var mymap = L.map('mapid').setView([47.132,7.260], 15);
        L.tileLayer('https://api.mapbox.com/styles/v1/mtheisen/citei76iz005f2jpac8g7ilcl/tiles/256/{z}/{x}/{y}?access_token=pk.eyJ1IjoibXRoZWlzZW4iLCJhIjoiY2l0ZWk0NTBoMDVmMDJ0bXlyNmxzZ3RnMyJ9.fErHtcHVcTsHCLMPN1ZcQg', { 
            attribution: 'Map data &copy; <a href="http://openstreetmap.org">OpenStreetMap</a> contributors, <a href="http://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="http://mapbox.com">Mapbox</a> ', 
            maxZoom: 18, 
            id: 'mtheisen', 
            accessToken: 'pk.eyJ1IjoibXRoZWlzZW4iLCJhIjoiY2l0ZWk0NTBoMDVmMDJ0bXlyNmxzZ3RnMyJ9.fErHtcHVcTsHCLMPN1ZcQg' 
        }).addTo(mymap);

        var geojson1 = L.geoJson(dat1, {
            style: style, 
            onEachFeature: function(feature, layer) {
                const fid = feature.properties.start_fid;
                featureMap1[fid] = layer; // 存入映射
                layer._leaflet_id = fid;
                layer.on({ 
                    mouseover: highlightFeature, 
                    mouseout: resetHighlight, 
                    click: zoomTo 
                });
                // 原列表生成逻辑保留
                $('#mapid2').append('<li data-value="' + fid + '">'+fid+'</li>');
            } 
        }).addTo(mymap);

        var mymapid2 = L.map('mapid2',{ zoomControl:false }).setView([32.1378527851,-19.9229088608], 14);
        var geojson2 = L.geoJson(dat2, { 
            pointToLayer: function (feature, latlng) { 
                return L.circleMarker(latlng); 
            }, 
            style: style, 
            onEachFeature: function(feature, layer) {
                const fid = feature.properties.start_fid;
                featureMap2[fid] = layer; // 存入映射
                layer._leaflet_id = fid;
                // 这里修改mouseover和mouseout处理,实现跨地图联动
                layer.on({
                    mouseover: function(e) {
                        const currentLayer = e.target;
                        const fid = currentLayer.feature.properties.start_fid;
                        // 高亮当前图层和第一张地图的对应图层
                        currentLayer.setStyle(highlightStyle);
                        if (featureMap1[fid]) {
                            featureMap1[fid].setStyle(highlightStyle);
                        }
                    },
                    mouseout: function(e) {
                        const currentLayer = e.target;
                        const fid = currentLayer.feature.properties.start_fid;
                        // 重置当前图层和第一张地图的对应图层
                        geojson2.resetStyle(currentLayer);
                        if (featureMap1[fid]) {
                            geojson1.resetStyle(featureMap1[fid]);
                        }
                    },
                    click: zoomTo
                });
            } 
        }).addTo(mymapid2);

        function style(feature) { 
            return { 
                fillColor: "red", 
                weight: 1, 
                opacity: 1, 
                color: 'red', 
                dashArray: '3', 
                fillOpacity: 0.7 
            }; 
        }

        var highlightStyle = { 
            fillColor: "yellow", 
            weight: 2, 
            opacity: 1, 
            color: 'yellow', 
            dashArray: '3', 
            fillOpacity: 0.7 
        };

        function highlightFeature(e) { 
            var layer = e.target; 
            layer.setStyle(highlightStyle); 
            // 如果需要悬停第一张地图时也联动第二张,可以添加以下代码
            // const fid = layer.feature.properties.start_fid;
            // if (featureMap2[fid]) {
            //     featureMap2[fid].setStyle(highlightStyle);
            // }
        }

        function resetHighlight(e) { 
            var layer = e.target;
            geojson1.resetStyle(layer);
            // 如果需要悬停第一张地图移出时联动重置第二张,可以添加以下代码
            // const fid = layer.feature.properties.start_fid;
            // if (featureMap2[fid]) {
            //     geojson2.resetStyle(featureMap2[fid]);
            // }
        }

        function zoomTo(e) { 
            var layer = e.target; 
            // 判断当前图层属于哪个地图,然后缩放对应的地图
            if (layer._map === mymap) {
                mymap.fitBounds(layer.getBounds());
            } else if (layer._map === mymapid2) {
                mymapid2.fitBounds(layer.getBounds());
            }
        }

        // 保留原列表悬停联动逻辑
        var hovered_id, layer, layer2;
        $('#mapid2 li').on('mouseenter', function(e){ 
            hovered_id = $(e.target).data('value'); 
            layer = geojson1.getLayer(hovered_id); 
            layer2 = geojson2.getLayer(hovered_id); 
            layer.setStyle(highlightStyle); 
            layer2.setStyle(highlightStyle); 
        }).on('mouseout', function(e){ 
            geojson1.resetStyle(layer); 
            geojson2.resetStyle(layer2); 
        });
    </script>
</body>
</html>

代码解释

  1. 要素映射:我们创建了featureMap1和featureMap2两个对象,分别存储第一张和第二张地图的要素,键为start_fid,值为对应的Leaflet图层对象,这样可以在O(1)时间内找到匹配的要素。
  2. 第二张地图的悬停事件:在onEachFeature里为第二张地图的要素绑定了自定义的mouseover和mouseout事件,当鼠标悬停时,通过start_fid从featureMap1中找到对应图层并高亮;移出时重置两个图层的样式。
  3. 可选的反向联动:如果需要悬停第一张地图时也高亮第二张的对应要素,可以取消highlightFeature和resetHighlight函数里的注释代码。
  4. 优化缩放逻辑:修改了zoomTo函数,判断当前图层所属的地图,然后缩放对应的地图,避免缩放错误。

内容的提问来源于stack exchange,提问作者vogis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 09:11:37