# Shapes, Custom Icons, and Geocoding ## Polygons and Shapes ### Google Maps ```javascript const polygon = new google.maps.Polygon({ paths: [ { lat: 37.7749, lng: -122.4194 }, { lat: 37.7849, lng: -122.4094 }, { lat: 37.7649, lng: -122.4094 } ], strokeColor: '#FF0000', strokeOpacity: 0.8, strokeWeight: 2, fillColor: '#FF0000', fillOpacity: 0.35, map: map }); ``` ### Mapbox GL JS ```javascript map.addSource('polygon', { type: 'geojson', data: { type: 'Feature', geometry: { type: 'Polygon', coordinates: [ [ [-122.4194, 37.7749], [-122.4094, 37.7849], [-122.4094, 37.7649], [-122.4194, 37.7749] // Close the ring ] ] } } }); map.addLayer({ id: 'polygon-layer', type: 'fill', source: 'polygon', paint: { 'fill-color': '#FF0000', 'fill-opacity': 0.35 } }); // Add outline map.addLayer({ id: 'polygon-outline', type: 'line', source: 'polygon', paint: { 'line-color': '#FF0000', 'line-width': 2, 'line-opacity': 0.8 } }); ``` ## Polylines / Lines ### Google Maps ```javascript const line = new google.maps.Polyline({ path: [ { lat: 37.7749, lng: -122.4194 }, { lat: 37.7849, lng: -122.4094 } ], strokeColor: '#0000FF', strokeWeight: 3, map: map }); ``` ### Mapbox GL JS ```javascript map.addSource('route', { type: 'geojson', data: { type: 'Feature', geometry: { type: 'LineString', coordinates: [ [-122.4194, 37.7749], [-122.4094, 37.7849] ] } } }); map.addLayer({ id: 'route-layer', type: 'line', source: 'route', paint: { 'line-color': '#0000FF', 'line-width': 3 } }); ``` ## Custom Icons and Symbols ### Google Maps ```javascript const marker = new google.maps.Marker({ position: { lat: 37.7749, lng: -122.4194 }, map: map, icon: { url: 'marker.png', scaledSize: new google.maps.Size(32, 32) } }); ``` ### Mapbox GL JS **Option 1: HTML Marker** ```javascript const el = document.createElement('div'); el.className = 'marker'; el.style.backgroundImage = 'url(marker.png)'; el.style.width = '32px'; el.style.height = '32px'; new mapboxgl.Marker(el).setLngLat([-122.4194, 37.7749]).addTo(map); ``` **Option 2: Symbol Layer (Better Performance)** ```javascript // Load image map.loadImage('marker.png', (error, image) => { if (error) throw error; map.addImage('custom-marker', image); map.addLayer({ id: 'markers', type: 'symbol', source: 'points', layout: { 'icon-image': 'custom-marker', 'icon-size': 1 } }); }); ``` ## Geocoding ### Google Maps ```javascript const geocoder = new google.maps.Geocoder(); geocoder.geocode({ address: '1600 Amphitheatre Parkway' }, (results, status) => { if (status === 'OK') { map.setCenter(results[0].geometry.location); } }); ``` ### Mapbox GL JS ```javascript // Use Mapbox Geocoding API v6 fetch( `https://api.mapbox.com/search/geocode/v6/forward?q=1600+Amphitheatre+Parkway&access_token=${mapboxgl.accessToken}` ) .then((response) => response.json()) .then((data) => { const [lng, lat] = data.features[0].geometry.coordinates; map.setCenter([lng, lat]); }); // Or use mapbox-gl-geocoder plugin const geocoder = new MapboxGeocoder({ accessToken: mapboxgl.accessToken, mapboxgl: mapboxgl, countries: 'us', // ISO 3166-1 alpha-2 code(s), comma-separated; hard filter, not a soft bias language: 'en' // Also affects which result ranks first, not just the UI/response text }); map.addControl(geocoder); ``` **Note:** `countries` and `language` change _which_ results come back, not just how they're filtered or displayed. `language` affects result scoring (the same query can rank a different place first depending on language), and `countries` excludes everything outside the listed codes. Port these over from the original Google Maps `region`/locale config.