MapLibre GL JS第72课:用boxZoomEnd回调选择要素

📌 学习目标

  • 掌握用boxZoomEnd回调选择要素的实现方法
  • 理解相关API的使用
  • 能够独立完成类似功能开发

🎯 核心概念

使用boxZoomEnd回调通过Shift-拖动选择要素。

💻 完 整 代 码

<!DOCTYPE html>
<html lang="en">
<head>
    <title>Select features with a boxZoomEnd callback</title>
    <meta property="og:description" content="使用 boxZoomEnd 回调通过 Shift 拖动选择要素,而不是将地图适配到拖动的框。" />
    <meta property="og:created" content="2026-02-25" />
    <meta charset='utf-8'>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link rel='stylesheet' href='https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.css' />
    <script src='https://unpkg.com/maplibre-gl@5.24.0/dist/maplibre-gl.js'></script>
    <style>
        body { margin: 0; padding: 0; }
        html, body, #map { height: 100%; }
        #ui {
            position: absolute;
            top: 10px;
            left: 10px;
            z-index: 1;
            max-width: 360px;
            padding: 8px;
            border-radius: 4px;
            background: rgba(255, 255, 255, 0.9);
            font: 13px/1.4 sans-serif;
        }
    </style>
</head>
<body>
<div id="map"></div>
<div id="ui">
    Shift + drag with <code>boxZoomEnd</code> (no default zoom). Selected: <span id="selected-count">0</span>
    <button id="clear-selection" type="button">Clear</button>
</div>
<script>
    const BASE_LAYER_ID = 'earthquakes-base';
    const SELECTED_LAYER_ID = 'earthquakes-selected';
    const selectedCountElement = document.getElementById('selected-count');

    const map = new maplibregl.Map({
        container: 'map',
        style: 'https://demotiles.maplibre.org/style.json',
        center: [-100, 40],
        zoom: 2.8,
        boxZoom: {
            boxZoomEnd: (mapInstance, p0, p1) => {
                const features = mapInstance.queryRenderedFeatures([
                    [Math.min(p0.x, p1.x), Math.min(p0.y, p1.y)],
                    [Math.max(p0.x, p1.x), Math.max(p0.y, p1.y)]
                ], {layers: [BASE_LAYER_ID]});
                const ids = [...new Set(features.map((feature) => feature.id).filter((id) => id != null))];
                setSelectedIds(ids);
            }
        }
    });

    function setSelectedIds(ids) {
        selectedCountElement.textContent = String(ids.length);
        if (map.getLayer(SELECTED_LAYER_ID)) {
            map.setFilter(SELECTED_LAYER_ID, ['in', ['id'], ['literal', ids]]);
        }
    }

    document.getElementById('clear-selection').addEventListener('click', () => setSelectedIds([]));

    map.on('load', () => {
        map.addSource('earthquakes', {
            type: 'geojson',
            data: 'https://maplibre.org/maplibre-gl-js/docs/assets/earthquakes.geojson',
            promoteId: 'id'
        });

        map.addLayer({
            id: BASE_LAYER_ID,
            type: 'circle',
            source: 'earthquakes',
            paint: {'circle-radius': 4, 'circle-color': '#1f78b4', 'circle-opacity': 0.65}
        });
        map.addLayer({
            id: SELECTED_LAYER_ID,
            type: 'circle',
            source: 'earthquakes',
            paint: {'circle-radius': 6, 'circle-color': '#ff6b00', 'circle-opacity': 0.95},
            filter: ['in', ['id'], ['literal', []]]
        });
        setSelectedIds([]);
    });
</script>
</body>
</html>

🔍 代码解析

1. 初始化地图

使用 new maplibregl.Map() 创建地图实例,配置美国区域作为初始视图。

2. 关键配置项

  • boxZoom配置: 自定义boxZoom行为,使用boxZoomEnd回调
  • queryRenderedFeatures(): 查询框选范围内的要素
  • setFilter(): 使用过滤器高亮选中要素
  • Set去重: 使用Set数据结构去除重复ID

3. 核心逻辑

  • Shift+拖动触发框选模式
  • boxZoomEnd回调中计算框选矩形范围
  • queryRenderedFeatures查询框内所有要素
  • 使用filter表达式高亮显示选中要素

⚙️ 参数说明

参数类型必填说明
p0, p1Point框选矩形对角坐标
layersstring[]只查询指定图层
filterexpression-设置图层过滤器

🎨 效果说明

在这里插入图片描述

运行代码后,地图显示美国区域,包含地震数据点。Shift+拖动可以在地图上画出一个选择框,框内的地震点会被高亮显示,选中数量会在界面顶部显示。点击Clear按钮可清除选择。

💡 常 见 问 题

Q1: 框选没有反应?
A: 检查以下几点:

  1. 确认按住了Shift键再拖动
  2. 检查boxZoom配置是否正确
  3. 确认数据源包含id字段

Q2: 为什么需要Set去重?
A: 同一个要素可能被多个图层引用,使用Set去重得到唯一的要素ID列表。

Q3: 如何同时选择多个图层?
A: 修改queryRenderedFeatures的layers参数:

queryRenderedFeatures(bounds, {layers: ['layer1', 'layer2']})

📝 练习任务

  1. 基础练习:修改选中点的样式(颜色、大小)
  2. 进阶挑战:添加双击清除选择功能
  3. 拓展思考:如何实现多选(累加选择)?
  4. 综合实践:创建一个框选数据导出功能

🌟 最佳实践

  1. 用户体验: 提供清晰的选择反馈(高亮+数量统计)
  2. 状态管理: 及时更新选中状态和UI显示
  3. 性能优化: 使用Set去重避免重复处理
  4. 交互设计: 提供清除选择的便捷方式
  5. 数据导出: 支持将选中数据导出为JSON或CSV

🔗 延伸阅读


本文是MapLibre GL JS实践课程系列的一部分,欢迎关注收藏

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丷丩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值