{"id":15400,"plugin_id":"plugin_asdk_app_6a2c0bf33cb48191884d842b15ad3c20","kind":"skill","collection_source":null,"comparison_source":null,"observed_at":"2026-09-30T23:11:22.333Z","digest":"428686531c851c9abb193a4f50138172252e9b8a1c50e868d291d072e4a81bd3","against":null,"payload":{"name":"mapbox-google-maps-migration","description":"Migration guide for developers moving from Google Maps Platform to Mapbox GL JS, covering API equivalents, pattern translations, and key differences","included_files":[{"relative_path":"AGENTS.md","size_in_bytes":8730},{"relative_path":"evals/evals.json","size_in_bytes":2790},{"relative_path":"references/api-services.md","size_in_bytes":3767},{"relative_path":"references/clustering-styling.md","size_in_bytes":2684},{"relative_path":"references/data-performance.md","size_in_bytes":1972},{"relative_path":"references/directions-controls.md","size_in_bytes":1968},{"relative_path":"references/shapes-geocoding.md","size_in_bytes":3963}],"skill_md_contents":"---\nname: mapbox-google-maps-migration\ndescription: Migration guide for developers moving from Google Maps Platform to Mapbox GL JS, covering API equivalents, pattern translations, and key differences\n---\n\n# Mapbox Google Maps Migration Skill\n\nComprehensive guidance for migrating from Google Maps Platform to Mapbox GL JS. Provides API equivalents, pattern translations, and strategies for successful migration.\n\n## Core Philosophy Differences\n\n### Google Maps: Imperative & Object-Oriented\n\n- Create objects (Marker, Polygon, etc.)\n- Add to map with `.setMap(map)`\n- Update properties with setters\n- Heavy reliance on object instances\n\n### Mapbox GL JS: Declarative & Data-Driven\n\n- Add data sources\n- Define layers (visual representation)\n- Style with JSON\n- Update data, not object properties\n\n**Key Insight:** Mapbox treats everything as data + styling, not individual objects.\n\n## Map Initialization\n\n### Google Maps\n\n```javascript\nconst map = new google.maps.Map(document.getElementById('map'), {\n  center: { lat: 37.7749, lng: -122.4194 },\n  zoom: 12,\n  mapTypeId: 'roadmap' // or 'satellite', 'hybrid', 'terrain'\n});\n```\n\n### Mapbox GL JS\n\n```javascript\nmapboxgl.accessToken = 'YOUR_MAPBOX_TOKEN';\nconst map = new mapboxgl.Map({\n  container: 'map',\n  style: 'mapbox://styles/mapbox/streets-v12', // or satellite-v9, outdoors-v12\n  center: [-122.4194, 37.7749], // [lng, lat] - note the order!\n  zoom: 12\n});\n```\n\n**Key Differences:**\n\n- **Coordinate order:** Google uses `{lat, lng}`, Mapbox uses `[lng, lat]`\n- **Authentication:** Google uses API key in script tag, Mapbox uses access token in code\n- **Styling:** Google uses map types, Mapbox uses full style URLs\n\n## API Equivalents Reference\n\n### Map Methods\n\n| Google Maps              | Mapbox GL JS                           | Notes                         |\n| ------------------------ | -------------------------------------- | ----------------------------- |\n| `map.setCenter(latLng)`  | `map.setCenter([lng, lat])`            | Coordinate order reversed     |\n| `map.getCenter()`        | `map.getCenter()`                      | Returns LngLat object         |\n| `map.setZoom(zoom)`      | `map.setZoom(zoom)`                    | Same behavior                 |\n| `map.getZoom()`          | `map.getZoom()`                        | Same behavior                 |\n| `map.panTo(latLng)`      | `map.panTo([lng, lat])`                | Animated pan                  |\n| `map.fitBounds(bounds)`  | `map.fitBounds([[lng,lat],[lng,lat]])` | Different bound format        |\n| `map.setMapTypeId(type)` | `map.setStyle(styleUrl)`               | Completely different approach |\n| `map.getBounds()`        | `map.getBounds()`                      | Similar                       |\n\n### Map Events\n\n| Google Maps                                       | Mapbox GL JS           | Notes                 |\n| ------------------------------------------------- | ---------------------- | --------------------- |\n| `google.maps.event.addListener(map, 'click', fn)` | `map.on('click', fn)`  | Simpler syntax        |\n| `event.latLng`                                    | `event.lngLat`         | Event property name   |\n| `'center_changed'`                                | `'move'` / `'moveend'` | Different event names |\n| `'zoom_changed'`                                  | `'zoom'` / `'zoomend'` | Different event names |\n| `'bounds_changed'`                                | `'moveend'`            | No direct equivalent  |\n| `'mousemove'`                                     | `'mousemove'`          | Same                  |\n| `'mouseout'`                                      | `'mouseleave'`         | Different name        |\n\n## Markers and Points\n\n### Simple Marker\n\n**Google Maps:**\n\n```javascript\nconst marker = new google.maps.Marker({\n  position: { lat: 37.7749, lng: -122.4194 },\n  map: map,\n  title: 'San Francisco',\n  icon: 'custom-icon.png'\n});\n\n// Remove marker\nmarker.setMap(null);\n```\n\n**Mapbox GL JS:**\n\n```javascript\n// Create marker\nconst marker = new mapboxgl.Marker()\n  .setLngLat([-122.4194, 37.7749])\n  .setPopup(new mapboxgl.Popup().setText('San Francisco'))\n  .addTo(map);\n\n// Remove marker\nmarker.remove();\n```\n\n### Multiple Markers\n\n**Google Maps:**\n\n```javascript\nconst markers = locations.map(\n  (loc) =>\n    new google.maps.Marker({\n      position: { lat: loc.lat, lng: loc.lng },\n      map: map\n    })\n);\n```\n\n**Mapbox GL JS (Equivalent Approach):**\n\n```javascript\n// Same object-oriented approach\nconst markers = locations.map((loc) => new mapboxgl.Marker().setLngLat([loc.lng, loc.lat]).addTo(map));\n```\n\n**Mapbox GL JS (Data-Driven Approach - Recommended for 100+ points):**\n\n```javascript\n// Add as GeoJSON source + layer (uses WebGL, not DOM)\nmap.addSource('points', {\n  type: 'geojson',\n  data: {\n    type: 'FeatureCollection',\n    features: locations.map((loc) => ({\n      type: 'Feature',\n      geometry: { type: 'Point', coordinates: [loc.lng, loc.lat] },\n      properties: { name: loc.name }\n    }))\n  }\n});\n\nmap.addLayer({\n  id: 'points-layer',\n  type: 'circle', // or 'symbol' for icons\n  source: 'points',\n  paint: {\n    'circle-radius': 8,\n    'circle-color': '#ff0000'\n  }\n});\n```\n\n**Performance Advantage:** Google Maps renders all markers as DOM elements (even when using the Data Layer), which becomes slow with 500+ markers. Mapbox's circle and symbol layers are rendered by WebGL, making them much faster for large datasets (1,000-10,000+ points). This is a significant advantage when building applications with many points.\n\n## Info Windows / Popups\n\n### Google Maps\n\n```javascript\nconst infowindow = new google.maps.InfoWindow({\n  content: '<h3>Title</h3><p>Content</p>'\n});\n\nmarker.addListener('click', () => {\n  infowindow.open(map, marker);\n});\n```\n\n### Mapbox GL JS\n\n```javascript\n// Option 1: Attach to marker\nconst marker = new mapboxgl.Marker()\n  .setLngLat([-122.4194, 37.7749])\n  .setPopup(new mapboxgl.Popup().setHTML('<h3>Title</h3><p>Content</p>'))\n  .addTo(map);\n\n// Option 2: On layer click (for data-driven markers)\nmap.on('click', 'points-layer', (e) => {\n  const coordinates = e.features[0].geometry.coordinates.slice();\n  const description = e.features[0].properties.description;\n\n  new mapboxgl.Popup().setLngLat(coordinates).setHTML(description).addTo(map);\n});\n```\n\n## Migration Strategy\n\n### Step 1: Audit Current Implementation\n\nIdentify all Google Maps features you use:\n\n- [ ] Basic map with markers\n- [ ] Info windows/popups\n- [ ] Polygons/polylines\n- [ ] Geocoding\n- [ ] Directions\n- [ ] Clustering\n- [ ] Custom styling\n- [ ] Drawing tools\n- [ ] Street View (no Mapbox equivalent)\n- [ ] Other advanced features\n\n### Step 2: Set Up Mapbox\n\n```html\n<!-- Replace Google Maps script -->\n<script src=\"https://api.mapbox.com/mapbox-gl-js/v3.18.1/mapbox-gl.js\"></script>\n<link href=\"https://api.mapbox.com/mapbox-gl-js/v3.18.1/mapbox-gl.css\" rel=\"stylesheet\" />\n```\n\n### Step 3: Convert Core Map\n\nStart with basic map initialization:\n\n1. Replace `new google.maps.Map()` with `new mapboxgl.Map()`\n2. Fix coordinate order (lat,lng -> lng,lat)\n3. Update zoom/center\n\n### Step 4: Convert Features One by One\n\nPrioritize by complexity:\n\n1. **Easy:** Map controls, basic markers\n2. **Medium:** Popups, polygons, lines\n3. **Complex:** Clustering, custom styling, data updates\n\n### Step 5: Update Event Handlers\n\nChange event syntax:\n\n- `google.maps.event.addListener()` -> `map.on()`\n- Update event property names (`latLng` -> `lngLat`)\n\n### Step 6: Optimize for Mapbox\n\nTake advantage of Mapbox features:\n\n- Convert multiple markers to data-driven layers\n- Use clustering (built-in)\n- Leverage vector tiles for custom styling\n- Use expressions for dynamic styling\n\n### Step 7: Test Thoroughly\n\n- Cross-browser testing\n- Mobile responsiveness\n- Performance with real data volumes\n- Touch/gesture interactions\n\n## Gotchas and Common Issues\n\n### Coordinate Order\n\n```javascript\n// Google Maps\n{ lat: 37.7749, lng: -122.4194 }\n\n// Mapbox (REVERSED!)\n[-122.4194, 37.7749]\n```\n\n**Always double-check coordinate order!**\n\n### Event Properties\n\n```javascript\n// Google Maps\nmap.on('click', (e) => {\n  console.log(e.latLng.lat(), e.latLng.lng());\n});\n\n// Mapbox\nmap.on('click', (e) => {\n  console.log(e.lngLat.lat, e.lngLat.lng);\n});\n```\n\n### Timing Issues\n\n```javascript\n// Google Maps - immediate\nconst marker = new google.maps.Marker({ map: map });\n\n// Mapbox - wait for load\nmap.on('load', () => {\n  map.addSource(...);\n  map.addLayer(...);\n});\n```\n\n### Removing Features\n\n```javascript\n// Google Maps\nmarker.setMap(null);\n\n// Mapbox - must remove both\nmap.removeLayer('layer-id');\nmap.removeSource('source-id');\n```\n\n### Updating Data Without Flash\n\n**Never** remove and re-add layers to update data — this reinitializes WebGL resources and causes a visible flash. Instead:\n\n```javascript\n// ✅ Update data in place (no flash)\nmap.getSource('stores').setData(newGeoJSON);\n\n// ✅ Filter existing data (GPU-side, fastest)\nmap.setFilter('stores-layer', ['==', ['get', 'category'], 'coffee']);\n\n// ❌ BAD: remove + re-add causes flash\nmap.removeLayer('stores-layer');\nmap.removeSource('stores');\nmap.addSource('stores', { ... });\nmap.addLayer({ ... });\n```\n\n## When NOT to Migrate\n\nConsider staying with Google Maps if:\n\n- **Street View is critical** - Mapbox doesn't have equivalent\n- **Tight Google Workspace integration** - Places API deeply integrated\n- **Already heavily optimized** - Migration cost > benefits\n- **Team expertise** - Retraining costs too high\n- **Short-term project** - Not worth migration effort\n\n## Quick Reference: Side-by-Side Comparison\n\n```javascript\n// GOOGLE MAPS\nconst map = new google.maps.Map(el, {\n  center: { lat: 37.7749, lng: -122.4194 },\n  zoom: 12\n});\n\nconst marker = new google.maps.Marker({\n  position: { lat: 37.7749, lng: -122.4194 },\n  map: map\n});\n\ngoogle.maps.event.addListener(map, 'click', (e) => {\n  console.log(e.latLng.lat(), e.latLng.lng());\n});\n\n// MAPBOX GL JS\nmapboxgl.accessToken = 'YOUR_TOKEN';\nconst map = new mapboxgl.Map({\n  container: el,\n  center: [-122.4194, 37.7749], // REVERSED!\n  zoom: 12,\n  style: 'mapbox://styles/mapbox/streets-v12'\n});\n\nconst marker = new mapboxgl.Marker()\n  .setLngLat([-122.4194, 37.7749]) // REVERSED!\n  .addTo(map);\n\nmap.on('click', (e) => {\n  console.log(e.lngLat.lat, e.lngLat.lng);\n});\n```\n\n**Remember:** lng, lat order in Mapbox!\n\n## Additional Resources\n\n- [Mapbox GL JS Documentation](https://docs.mapbox.com/mapbox-gl-js/)\n- [Official Google Maps to Mapbox Migration Guide](https://docs.mapbox.com/help/tutorials/google-to-mapbox/)\n- [Mapbox Examples](https://docs.mapbox.com/mapbox-gl-js/examples/)\n- [Style Specification](https://docs.mapbox.com/mapbox-gl-js/style-spec/)\n\n## Integration with Other Skills\n\n**Works with:**\n\n- **mapbox-web-integration-patterns**: Framework-specific migration guidance\n- **mapbox-web-performance-patterns**: Optimize after migration\n- **mapbox-token-security**: Secure your Mapbox tokens properly\n- **mapbox-geospatial-operations**: Use Mapbox's geospatial tools effectively\n- **mapbox-search-patterns**: Migrate geocoding/search functionality\n\n## Reference Files\n\nThe following reference files contain detailed migration guides for specific topics. Load them when working on those areas:\n\n- **`references/shapes-geocoding.md`** — Polygons, Polylines, Custom Icons, Geocoding\n- **`references/directions-controls.md`** — Directions/Routing, Controls\n- **`references/clustering-styling.md`** — Clustering, Styling/Appearance\n- **`references/data-performance.md`** — Data Updates, Performance, Common Migration Patterns (Store Locator, Drawing Tools, Heatmaps)\n- **`references/api-services.md`** — API Services Comparison, Pricing, Plugins, Framework Integration, Testing, Migration Checklist\n\nTo load a reference, read the file relative to this skill directory, e.g.:\n\n```\nLoad references/shapes-geocoding.md\n```\n"},"changes":[],"summary":"First saved snapshot. No earlier version is available for comparison.","summary_kind":"deterministic","summary_metadata":{}}