在 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>