mcpField
M
mapbox-google-maps-migration

mapbox-google-maps-migration

github.com/mapbox开发831.4k 次安装4 周前更新
代码仓库

关于 mapbox-google-maps-migration

为将 Google Maps Platform 迁移到 Mapbox GL JS 提供指导,面向维护地图应用的开发者。内容涵盖 API 对照、模式转换、迁移步骤与常见问题。

主要功能

  1. 01Google Maps 与 Mapbox API 对照
  2. 02地图事件与坐标转换说明
  3. 03标记、弹窗和图层迁移
  4. 04分阶段迁移与测试建议
  5. 05常见问题及性能优化提示

适用场景

  1. 01将现有 Google Maps 地图替换为 Mapbox GL JS
  2. 02转换标记、弹窗和地图事件处理
  3. 03处理经纬度顺序及数据图层更新
  4. 04评估迁移范围并规划测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mapbox/mapbox-agent-skills --skill mapbox-google-maps-migration

安装后在 Claude Code 中输入/mapbox-google-maps-migration确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

AGENTS.md
evals/
evals.json
references/
api-services.md
clustering-styling.md
data-performance.md
directions-controls.md
shapes-geocoding.md

详细介绍

Mapbox Google Maps 迁移技能

从 Google Maps Platform 迁移到 Mapbox GL JS 的全面指南。提供 API 对应关系、模式转换和成功迁移的策略。

核心理念差异

Google Maps:命令式与面向对象
  • 创建对象(Marker、Polygon 等)
  • 使用 .setMap(map) 添加到地图
  • 使用 setter 更新属性
  • 高度依赖对象实例
Mapbox GL JS:声明式与数据驱动
  • 添加数据源
  • 定义图层(可视化表示)
  • 使用 JSON 设置样式
  • 更新数据,而非对象属性

关键要点: Mapbox 将一切视为数据 + 样式,而非单独的对象。

地图初始化

Google Maps
const map = new google.maps.Map(document.getElementById('map'), {
  center: { lat: 37.7749, lng: -122.4194 },
  zoom: 12,
  mapTypeId: 'roadmap' // or 'satellite', 'hybrid', 'terrain'
});
Mapbox GL JS
mapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';
const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/streets-v12', // or satellite-v9, outdoors-v12
  center: [-122.4194, 37.7749], // [lng, lat] - note the order!
  zoom: 12
});

主要差异:

  • 坐标顺序: Google 使用 {lat, lng},Mapbox 使用 [lng, lat]
  • 身份验证: Google 在脚本标签中使用 API 密钥,Mapbox 在代码中使用访问令牌
  • 样式: Google 使用地图类型,Mapbox 使用完整的样式 URL

API 对应关系参考

地图方法
Google MapsMapbox GL JS说明
map.setCenter(latLng)map.setCenter([lng, lat])坐标顺序相反
map.getCenter()map.getCenter()返回 LngLat 对象
map.setZoom(zoom)map.setZoom(zoom)行为相同
map.getZoom()map.getZoom()行为相同
map.panTo(latLng)map.panTo([lng, lat])平滑移动
map.fitBounds(bounds)map.fitBounds([[lng,lat],[lng,lat]])边界格式不同
map.setMapTypeId(type)map.setStyle(styleUrl)方法完全不同
map.getBounds()map.getBounds()类似
地图事件
Google MapsMapbox GL JS说明
google.maps.event.addListener(map, 'click', fn)map.on('click', fn)语法更简洁
event.latLngevent.lngLat事件属性名称
'center_changed''move' / 'moveend'事件名称不同
'zoom_changed''zoom' / 'zoomend'事件名称不同
'bounds_changed''moveend'没有直接对应项
'mousemove''mousemove'相同
'mouseout''mouseleave'名称不同

标记和点

简单标记

Google Maps:

const marker = new google.maps.Marker({
  position: { lat: 37.7749, lng: -122.4194 },
  map: map,
  title: 'San Francisco',
  icon: 'custom-icon.png'
});

// Remove marker
marker.setMap(null);

Mapbox GL JS:

// Create marker
const marker = new mapboxgl.Marker()
  .setLngLat([-122.4194, 37.7749])
  .setPopup(new mapboxgl.Popup().setText('San Francisco'))
  .addTo(map);

// Remove marker
marker.remove();
多个标记

Google Maps:

const markers = locations.map(
  (loc) =>
    new google.maps.Marker({
      position: { lat: loc.lat, lng: loc.lng },
      map: map
    })
);

Mapbox GL JS(对应方式):

// Same object-oriented approach
const markers = locations.map((loc) => new mapboxgl.Marker().setLngLat([loc.lng, loc.lat]).addTo(map));

Mapbox GL JS(数据驱动方式——推荐用于 100 个以上的点):

// Add as GeoJSON source + layer (uses WebGL, not DOM)
map.addSource('points', {
  type: 'geojson',
  data: {
    type: 'FeatureCollection',
    features: locations.map((loc) => ({
      type: 'Feature',
      geometry: { type: 'Point', coordinates: [loc.lng, loc.lat] },
      properties: { name: loc.name }
    }))
  }
});

map.addLayer({
  id: 'points-layer',
  type: 'circle', // or 'symbol' for icons
  source: 'points',
  paint: {
    'circle-radius': 8,
    'circle-color': '#ff0000'
  }
});

性能优势: Google Maps 会将所有标记渲染为 DOM 元素(即使使用 Data Layer 也是如此),当标记超过 500 个时,速度会变慢。Mapbox 的圆形图层和符号图层通过 WebGL 渲染,因此处理大型数据集(1,000 至 10,000 个以上的点)时速度快得多。这对于构建包含大量点的应用来说是一项显著优势。

信息窗口 / 弹出窗口

Google Maps
const infowindow = new google.maps.InfoWindow({
  content: '<h3>Title</h3><p>Content</p>'
});

marker.addListener('click', () => {
  infowindow.open(map, marker);
});
Mapbox GL JS
// Option 1: Attach to marker
const marker = new mapboxgl.Marker()
  .setLngLat([-122.4194, 37.7749])
  .setPopup(new mapboxgl.Popup().setHTML('<h3>Title</h3><p>Content</p>'))
  .addTo(map);

// Option 2: On layer click (for data-driven markers)
map.on('click', 'points-layer', (e) => {
  const coordinates = e.features[0].geometry.coordinates.slice();
  const description = e.features[0].properties.description;

  new mapboxgl.Popup().setLngLat(coordinates).setHTML(description).addTo(map);
});

迁移策略

步骤 1:审查当前实现

确定你使用的所有 Google Maps 功能:

  • 基础地图与标记
  • 信息窗口/弹出窗口
  • 多边形/折线
  • 地理编码
  • 路线规划
  • 聚类
  • 自定义样式
  • 绘图工具
  • 街景(Mapbox 没有对应功能)
  • 其他高级功能
步骤 2:设置 Mapbox

<script src="https://api.mapbox.com/mapbox-gl-js/v3.18.1/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.18.1/mapbox-gl.css" rel="stylesheet" />
步骤 3:转换核心地图

从基础地图初始化开始:

  1. 将 new google.maps.Map() 替换为 new mapboxgl.Map()
  2. 修正坐标顺序(lat,lng -> lng,lat)
  3. 更新缩放级别/中心点
步骤 4:逐一转换功能

按复杂程度确定优先级:

  1. 简单: 地图控件、基础标记
  2. 中等: 弹出窗口、多边形、线条
  3. 复杂: 聚类、自定义样式、数据更新
步骤 5:更新事件处理程序

更改事件语法:

  • google.maps.event.addListener() -> map.on()
  • 更新事件属性名称(latLng -> lngLat)
步骤 6:针对 Mapbox 进行优化

利用 Mapbox 的功能:

  • 将多个标记转换为数据驱动图层
  • 使用聚类(内置)
  • 利用矢量瓦片实现自定义样式
  • 使用表达式实现动态样式
步骤 7:全面测试
  • 跨浏览器测试
  • 移动设备响应式表现
  • 使用实际数据量测试性能
  • 触控/手势交互

注意事项和常见问题

坐标顺序
// Google Maps
{ lat: 37.7749, lng: -122.4194 }

// Mapbox (REVERSED!)
[-122.4194, 37.7749]

务必仔细检查坐标顺序!

事件属性
// Google Maps
map.on('click', (e) => {
  console.log(e.latLng.lat(), e.latLng.lng());
});

// Mapbox
map.on('click', (e) => {
  console.log(e.lngLat.lat, e.lngLat.lng);
});
时序问题
// Google Maps - immediate
const marker = new google.maps.Marker({ map: map });

// Mapbox - wait for load
map.on('load', () => {
  map.addSource(...);
  map.addLayer(...);
});
移除功能
// Google Maps
marker.setMap(null);

// Mapbox - must remove both
map.removeLayer('layer-id');
map.removeSource('source-id');
更新数据且不闪烁

切勿通过移除并重新添加图层来更新数据——这会重新初始化 WebGL 资源,并导致明显闪烁。请改用:

// ✅ Update data in place (no flash)
map.getSource('stores').setData(newGeoJSON);

// ✅ Filter existing data (GPU-side, fastest)
map.setFilter('stores-layer', ['==', ['get', 'category'], 'coffee']);

// ❌ BAD: remove + re-add causes flash
map.removeLayer('stores-layer');
map.removeSource('stores');
map.addSource('stores', { ... });
map.addLayer({ ... });

不适合迁移的情况

以下情况可考虑继续使用 Google Maps:

  • 街景至关重要 - Mapbox 没有对应功能
  • 与 Google Workspace 深度集成 - Places API 集成紧密
  • 已完成大量优化 - 迁移成本高于收益
  • 团队专业知识 - 重新培训成本过高
  • 短期项目 - 不值得投入迁移工作

快速参考:并排对比

// GOOGLE MAPS
const map = new google.maps.Map(el, {
  center: { lat: 37.7749, lng: -122.4194 },
  zoom: 12
});

const marker = new google.maps.Marker({
  position: { lat: 37.7749, lng: -122.4194 },
  map: map
});

google.maps.event.addListener(map, 'click', (e) => {
  console.log(e.latLng.lat(), e.latLng.lng());
});

// MAPBOX GL JS
mapboxgl.accessToken = 'YOUR_TOKEN';
const map = new mapboxgl.Map({
  container: el,
  center: [-122.4194, 37.7749], // REVERSED!
  zoom: 12,
  style: 'mapbox://styles/mapbox/streets-v12'
});

const marker = new mapboxgl.Marker()
  .setLngLat([-122.4194, 37.7749]) // REVERSED!
  .addTo(map);

map.on('click', (e) => {
  console.log(e.lngLat.lat, e.lngLat.lng);
});

请记住: Mapbox 中的坐标顺序是 lng, lat!

其他资源

与其他技能集成

可配合使用:

  • mapbox-web-integration-patterns:针对特定框架的迁移指导
  • mapbox-web-performance-patterns:迁移后进行优化
  • mapbox-token-security:妥善保护 Mapbox 令牌
  • mapbox-geospatial-operations:有效使用 Mapbox 地理空间工具
  • mapbox-search-patterns:迁移地理编码/搜索功能

参考文件

以下参考文件包含特定主题的详细迁移指南。在处理相关领域时,请加载这些文件:

  • references/shapes-geocoding.md — 多边形、折线、自定义图标、地理编码
  • references/directions-controls.md — 路线规划/路由、控件
  • references/clustering-styling.md — 聚类、样式/外观
  • references/data-performance.md — 数据更新、性能、常见迁移模式(门店定位器、绘图工具、热力图)
  • references/api-services.md — API 服务对比、定价、插件、框架集成、测试、迁移检查清单

要加载参考文件,请读取相对于此技能目录的文件,例如:

Load references/shapes-geocoding.md

评论

支持 Markdown