Mapbox中点击按钮在多条线其中一条线上生成一条新的可编辑的线

在 Mapbox 中实现「点击按钮在指定已有线上生成可编辑新线(更宽、更亮)」的功能,核心要点包括:初始化多线图层、按钮触发新线生成(基于原线坐标)、新线配置高亮样式、开启 Mapbox 编辑交互。

以下是完整可运行代码,包含 HTML 结构、Mapbox 初始化、多原线加载、按钮触发逻辑、可编辑新线实现,代码中做了详细注释。

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mapbox 生成可编辑高亮新线(保留所有状态)</title>
    <!-- 引入Mapbox核心库 -->
    <link href="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css" rel="stylesheet">
    <script src="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js"></script>
    <!-- 引入Draw插件 -->
    <link rel="stylesheet" href="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.css" />
    <script src="https://api.mapbox.com/mapbox-gl-js/plugins/mapbox-gl-draw/v1.4.3/mapbox-gl-draw.js"></script>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body { height: 100vh; position: relative; }
        #createLineBtn {
            position: absolute; top: 20px; left: 20px; z-index: 100;
            padding: 8px 16px; background: #409eff; color: #fff;
            border: none; border-radius: 4px; cursor: pointer; font-size: 14px;
            user-select: none; transition: background 0.2s;
        }
        #createLineBtn:hover { background: #337ecc; }
        #map { width: 100%; height: 100vh; }
    </style>
</head>
<body>
    <button id="createLineBtn">在第一条线上生成可编辑高亮新线</button>
    <div id="map"></div>

    <script>
        // 替换为自己的Mapbox Access Token
        mapboxgl.accessToken = "Access Token";
        const map = new mapboxgl.Map({
            container: 'map', style: 'mapbox://styles/mapbox/streets-v12',
            center: [116.403874, 39.914885], zoom: 12, pitch: 0
        });

        // 全局变量
        let originalLinesGeoJson;
        let draw = null;
        const DRAW_UPDATE_EVENT = 'draw.update.editableLine';
        const DRAW_DELETE_EVENT = 'draw.delete.editableLine';
        let isNewLineCreated = false; // 新线是否已创建
        let editedNewLineFeature = null; // 缓存编辑后的新线要素

        map.on('load', () => {
            // 初始化3条测试原线
            originalLinesGeoJson = {
                type: 'FeatureCollection',
                features: [
                    { type: 'Feature', properties: { name: '原线1' }, geometry: { type: 'LineString', coordinates: [[116.391384, 39.908692], [116.414728, 39.917012]] } },
                    { type: 'Feature', properties: { name: '原线2' }, geometry: { type: 'LineString', coordinates: [[116.391384, 39.908692], [116.373802, 39.913478]] } },
                    { type: 'Feature', properties: { name: '原线3' }, geometry: { type: 'LineString', coordinates: [[116.391384, 39.908692], [116.419785, 39.881656]] } }
                ]
            };

            // 添加原线图层(深灰色3px)
            map.addSource('original-lines-source', { type: 'geojson', data: originalLinesGeoJson });
            map.addLayer({
                id: 'original-lines-layer', type: 'line', source: 'original-lines-source',
                layout: { 'line-join': 'round', 'line-cap': 'round' },
                paint: { 'line-width': 3, 'line-color': '#666666' }
            });

            // 绑定按钮点击事件
            document.getElementById('createLineBtn').addEventListener('click', createEditableHighlightLine);
            // 添加地图导航控件
            map.addControl(new mapboxgl.NavigationControl(), 'bottom-right');
        });

        /**
         * 核心函数:生成新线(已创建则直接返回,保留编辑状态)
         */
        function createEditableHighlightLine() {
            if (!map.loaded() || !originalLinesGeoJson?.features?.length) {
                alert('地图未加载完成或无原线数据!');
                return;
            }
            // 已创建新线,直接返回不操作
            if (isNewLineCreated) {
                console.log('新线已创建,保留编辑后状态');
                return;
            }
            // 首次创建:基于第一条原线生成新线
            const targetLineCoords = originalLinesGeoJson.features[0].geometry.coordinates;
            const newLineFeature = {
                type: 'Feature',
                properties: { name: '可编辑高亮新线' },
                geometry: { type: 'LineString', coordinates: targetLineCoords }
            };
            initDraw(newLineFeature);
            isNewLineCreated = true;
        }

        /**
         * 初始化Draw:核心修复【全状态样式】,解决点击空白处消失问题
         */
        function initDraw(initFeature) {
            draw = new MapboxDraw({
                displayControlsDefault: false, // 隐藏默认控件
                controls: {}, // 不启用任何控件
                modes: {
                    // 保留原生模式,禁用手动绘制
                    ...MapboxDraw.modes,
                    draw_line_string: false,
                    draw_polygon: false,
                    draw_point: false
                },
                styles: [
                    // ========== 核心修复1:未激活(未选中)新线样式 ==========
                    // 点击空白处后新线处于未激活状态,匹配此样式,保证不消失
                    {
                        id: 'gl-draw-line-inactive',
                        type: 'line',
                        filter: ['all', ['==', '$type', 'LineString'], ['==', 'active', 'false']],
                        layout: { 'line-join': 'round', 'line-cap': 'round' },
                        paint: {
                            'line-width': 8, // 与激活状态同宽度,保证视觉一致
                            'line-color': '#ff4d4f', // 与激活状态同亮色,保证高亮
                            'line-opacity': 0.8 // 透明度一致
                        }
                    },
                    // ========== 原有:激活(选中)新线样式 ==========
                    // 编辑时/选中时的样式,保持高亮
                    {
                        id: 'gl-draw-line-active',
                        type: 'line',
                        filter: ['all', ['==', '$type', 'LineString'], ['==', 'active', 'true']],
                        layout: { 'line-join': 'round', 'line-cap': 'round' },
                        paint: {
                            'line-width': 8,
                            'line-color': '#ff4d4f',
                            'line-opacity': 0.8
                        }
                    },
                    // ========== 核心修复2:未激活节点样式 ==========
                    // 点击空白处后节点未激活,匹配此样式,保证节点不消失
                    {
                        id: 'gl-draw-point-inactive',
                        type: 'circle',
                        filter: ['all', ['==', '$type', 'Point'], ['==', 'active', 'false']],
                        paint: {
                            'circle-radius': 5,
                            'circle-color': '#ff7878' // 浅红色,与激活节点区分
                        }
                    },
                    // ========== 原有:激活节点样式 ==========
                    // 编辑时/选中时的节点样式
                    {
                        id: 'gl-draw-point-active',
                        type: 'circle',
                        filter: ['all', ['==', '$type', 'Point'], ['==', 'active', 'true']],
                        paint: {
                            'circle-radius': 6,
                            'circle-color': '#ff4d4f' // 亮红色,与新线匹配
                        }
                    }
                ]
            });

            // 将Draw添加到地图
            map.addControl(draw, 'top-right');
            // 添加新线要素并进入编辑模式
            const featureIds = draw.add(initFeature);
            draw.changeMode('simple_select', { featureIds: featureIds });

            // 实时缓存编辑后的新线要素
            map.on(DRAW_UPDATE_EVENT, (e) => {
                if (e.features.length) {
                    editedNewLineFeature = e.features[0];
                    console.log('新线编辑后缓存成功', editedNewLineFeature.geometry.coordinates);
                }
            });
            map.on(DRAW_DELETE_EVENT, (e) => {
                if (e.features.length) {
                    editedNewLineFeature = e.features[0];
                    console.log('删除节点后缓存成功', editedNewLineFeature.geometry.coordinates);
                }
            });
        }

        // 全局重置方法:如需重新生成新线,控制台调用 resetNewLine() 即可
        window.resetNewLine = function() {
            if (draw) {
                map.off(DRAW_UPDATE_EVENT);
                map.off(DRAW_DELETE_EVENT);
                draw.deleteAll();
                map.removeControl(draw);
                draw = null;
            }
            isNewLineCreated = false;
            editedNewLineFeature = null;
            console.log('新线已重置,可再次点击按钮生成');
        };
    </script>
</body>
</html>
相关推荐
WebGIS开发4 天前
新中地系统学习3个月能做出什么效果?
openlayers·mapbox·webgis
duansamve6 天前
Mapbox中如何对已经加载的线段进行编辑?
mapbox
duansamve6 天前
Mapbox中如何需改线的样式?
mapbox
WebGIS开发23 天前
WebGIS开发实战|智慧城市济南地图可视化开发系统
智慧城市·mapbox·webgis
WebGIS开发23 天前
WebGIS开发实战|广州市智慧城市监测平台
智慧城市·mapbox·gis开发·webgis
duansamve23 天前
Mapbox中移动、拖拽多边形
mapbox
GDAL24 天前
深入解析 @mapbox/mbtiles:Node.js 玩转 MBTiles 瓦片格式
mapbox
GISHUB1 个月前
地图矢量切片常用的几种开源方案
开源·mapbox
GDAL1 个月前
Mapbox GL JS 核心表达式:`==` 相等判断完全教程
javascript·mapbox