用途
这是一个面向浏览器端 Mapbox GL JS v3.x 的高级工具包,用于构建生产级 Web 地图体验。范围明确限定为浏览器中的 mapbox-gl-js v3.x(CDN mapbox-gl-js/v3.x/),不适用于原生 iOS/Android SDK(API 不同)。采用纯 GL JS,与前端框架无关。部分模式提炼自一个生产环境的步道地图,使用时需将常量适配到自己的设计。
主要能力
工具包按任务组织参考文档,仅在任务需要时读取对应文件:
- 自定义 SVG/canvas 标记、addImage/updateImage、命名空间、抗锯齿/边缘白边、圆形图片遮罩、锚点(references/markers.md)
- 虚线/描边轨迹线、line-dasharray 单位、山体阴影上的半透明、按属性着色、line-gradient/lineMetrics(references/lines-and-trails.md)
- 山体阴影、密集等高线、3D 地形(setTerrain)、增强或添加现有样式的地形(references/terrain.md)
- 符号图层文字标注不遮挡图标(text-optional)、AllTrails 风格放置(references/labels.md)
- 重着色基础样式的陆地/植被填充(调色板偏移/分级统计图式匹配)(references/palette.md)
- 自定义弹窗、圆形照片卡片、随缩放缩放的偏移(references/popups.md)
- 样式表达式 interpolate/step/match/case、zoom 最外层规则、表达式中的 feature-state(references/expressions.md)
- 通过 feature-state 实现悬停/选中(而非 setData)、queryRenderedFeatures 注意事项、聚合、GeoJSON 性能、事件卫生(references/interaction-and-performance.md)
- 数据可视化与 3D:fill-extrusion 建筑/挤出数据、热力图图层、数据连接分级统计图(feature-state/match)、比例符号、天空/雾(references/dataviz-and-3d.md)
- 地图中的 three.js:CustomLayerInterface + 共享 GL 上下文、动画 3D 对象/模型、烘焙矩阵与重建相机(Threebox CameraSync)的分支、射线拾取、ENU 米制场景空间、恒定屏幕尺寸角色、地形高程、俯仰角下的远平面裁剪(references/three-custom-layer.md)
- 镜头与动画:flyTo/easeTo/fitBounds 内边距、freeCameraOptions 电影感/环绕、飞行/第一人称相机(bearing+pitch 编排;roll 仅 MapLibre 支持)、动画昼夜循环(setLights)、与相机同步的 HUD、沿线取点、线条绘制动画、paint 过渡、旋转地球、essential/reduced-motion 注意事项(references/camera-and-animation.md)
- 样式库与组合:第一方样式目录、按用例选择基础样式、自定义/第三方样式、样式切换器、明暗主题、手写样式 JSON(references/styles.md 及 assets/style-catalog.json)
- 生命周期:setStyle 清除自定义图层、0×0 resize() 缺陷、SPA 拆除/WebGL 上下文上限、令牌安全、就绪事件(references/lifecycle.md)
- v3 Standard 样式:slots 与 beforeId、setConfigProperty/lightPreset、为何图层遍历(调色板/地形)会失效;本地化、RTL、地球(references/v3-standard-style.md)
- 无头截图与像素级标记对齐校验(Playwright、map.project)(references/verification.md)
使用方式
设置不变量:
- 在 new mapboxgl.Map(...) 之前设置 mapboxgl.accessToken。
- 地图需要 'load' 事件后才能添加 sources/layers/images。在节流或后台标签页中 'load' 可能被错过——同时绑定 'idle' 作为一次性回退,并用 _inited 标志保护(见 verification.md)。
- 从 .env 解析 token/style:先读 token(这会触发 .env 加载),再读 MAPBOX_STYLE。先读 style 会在 token 加载前静默回退到默认样式。见 palette.md。
- Classic 与 Standard 样式。此处若干技术(底图调色板重着色、地形增强或添加的 getStyle().layers 遍历)假设使用 classic 样式(Streets/Outdoors/Light/Dark …-v12)。v3 默认 Standard 样式没有可枚举的命名图层——改用 slots + setConfigProperty。移植到 Standard 前请阅读 v3-standard-style.md。
捆绑资源:
- 起始代码 assets/circular_image_marker.js:复制到页面即可注册圆形照片标记(canvas → 预乘 ImageBitmap、destination-in 遮罩、接触阴影 + 投影)。仅浏览器片段,非 CLI——需将 frameColor/box 常量适配到自己的设计。
- 校验脚本 scripts/screenshot_map.py:驱动无头 Chromium 对已服务的地图页面截图,断言标记投影到其 lng/lat,并暴露控制台错误。运行方式:
python -m http.server 8777 --directory <site-dir> & # serve the page
uv run --with playwright scripts/screenshot_map.py \
http://localhost:8777/preview/index.html out.png --expect 146.9 -36.1
# exit 0 = no console errors; 10 = errors found; 5 = playwright missing; 7 = map never ready
uv run --with playwright scripts/screenshot_map.py URL out.png --json | jq '.data'
- 陈旧性校验脚本 scripts/check-mapbox-facts.py:仅用标准库(无 Playwright),守护本技能编码的快速变化事实(SKILL-RESOURCE-PROTOCOL §7)。--offline(默认)断言内部一致性——v3 Standard 配置枚举(lightPreset/theme)、地形 tileset ID、天气(≥3.7)版本门槛、无原生相机 roll 的事实(roll 是 MapLibre GL JS v5,非 Mapbox),以及 assets/style-catalog.json 中每个样式 URL/id。--live 解析第三方样式 URL,并探测 Mapbox GL JS 是否已发布 v3 之后的主版本。
python scripts/check-mapbox-facts.py --offline # exit 0 ok, 4 inconsistency
python scripts/check-mapbox-facts.py --live --json # exit 7 network, 10 drift
三个最高价值的注意事项(完整细节见参考文件)
- 为每个 addImage 名称加命名空间(例如 "rcpin-<glyph>")。Mapbox 样式自带字面名为 parking/toilet 等的 sprite 图标——未加命名空间的 hasImage() 会对这些返回 true,你的图标会被静默丢弃。
- 将图标注册为预乘的 createImageBitmap(),而非原始 HTMLImageElement/ImageData——直通 alpha 源会让 Mapbox 在抗锯齿边缘产生白色光晕。updateImage(name, bmp) 可原地重着色。
- 数据驱动的 icon-offset 在 GL JS v3 中被静默忽略。使用常量 icon-offset(它会随 icon-size 缩放),或将标记拆分为多个符号图层,每个图层使用自己的常量 anchor/offset。
适用场景
适合需要在 Web 端构建复杂地图交互的开发者,包括主题化数据可视化、3D 地形与建筑、轨迹与步道展示、镜头动画与电影感运镜、three.js 自定义图层集成,以及需要自动化截图校验地图渲染正确性的场景。
限制
仅支持浏览器中的 mapbox-gl-js v3.x,不支持原生 iOS/Android SDK。部分技术假设使用 classic 样式,Standard 样式需改用 slots + setConfigProperty。roll 相机效果仅 MapLibre GL JS v5 支持,Mapbox 无此能力。数据驱动的 icon-offset 在 v3 中被忽略。