如何嵌入含自定义标记的Google Maps数据层并实现API交互?
Hey there! I see you're trying to get a Google Maps Data Layer up and running with custom markers, and want to add interactions like finding nearby locations and navigation—let's work through this step by step.
1. Fix GeoJSON Loading Issues
Your current code uses JSONP to load the GeoJSON file, but that only works if the file is formatted for JSONP (which your GS bucket file likely isn't). Let's switch to the fetch API for more reliable loading, and also convert your custom "markers" array into a standard GeoJSON FeatureCollection (since Google Maps Data Layer expects this format).
function initMap() { map = new google.maps.Map(document.getElementById("map"), { center: { lat: 37.7853, lng: -122.41669 }, // Center on your first marker for better UX zoom: 12, }); // Fetch your GeoJSON (ensure the GS bucket file is publicly accessible) fetch("gs://firstbucketfor2locationsmapslaer/גאו.geojson") .then(response => response.json()) .then(data => { // Convert your custom markers to standard GeoJSON const geoJsonData = { type: "FeatureCollection", features: data.markers.map(marker => ({ type: "Feature", properties: marker.properties, geometry: marker.geometry })) }; // Add converted data to the Data Layer map.data.addGeoJson(geoJsonData); // Set up custom markers and interactions after loading setupCustomMarkers(); }) .catch(error => console.error("Error loading GeoJSON:", error)); }
2. Render Custom Markers
To display your custom icons and add basic interactivity (like info windows), use the setStyle method and click event listeners:
function setupCustomMarkers() { // Apply custom icons from your GeoJSON map.data.setStyle(feature => { return { icon: feature.getProperty("icon"), title: feature.getProperty("name") // Shows tooltip on hover }; }); // Add info window for marker clicks const infoWindow = new google.maps.InfoWindow(); map.data.addListener("click", event => { const name = event.feature.getProperty("name"); const description = event.feature.getProperty("description"); const position = event.feature.getGeometry().get(); const lat = position.lat(); const lng = position.lng(); // Add navigation options to the info window const navUrl = `https://www.google.com/maps/dir/?api=1&destination=${lat},${lng}&travelmode=driving`; infoWindow.setContent(` <h3>${name}</h3> <p>${description}</p> <button onclick="displayRouteToLocation(${lat}, ${lng})">Show Route on Map</button> <br><a href="${navUrl}" target="_blank">Open in Google Maps</a> `); infoWindow.setPosition(position); infoWindow.open(map); }); }
3. Find Nearest Locations
We'll use the Haversine formula to calculate distances between the user's location and your markers, then find the closest one:
// Calculate distance between two lat/lng points (returns kilometers) function calculateDistance(lat1, lng1, lat2, lng2) { const earthRadius = 6371; // km const dLat = (lat2 - lat1) * Math.PI / 180; const dLng = (lng2 - lng1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLng/2) * Math.sin(dLng/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return earthRadius * c; } // Find the nearest marker to the user's location function findNearestLocation(userLat, userLng) { let nearest = null; let minDistance = Infinity; map.data.forEach(feature => { const geometry = feature.getGeometry(); if (geometry.getType() === "Point") { const [lng, lat] = geometry.get().toJSON(); const distance = calculateDistance(userLat, userLng, lat, lng); if (distance < minDistance) { minDistance = distance; nearest = { feature, distance: distance.toFixed(2) }; } } }); if (nearest) { const position = nearest.feature.getGeometry().get(); map.panTo(position); const infoWindow = new google.maps.InfoWindow(); infoWindow.setContent(` <h3>${nearest.feature.getProperty("name")}</h3> <p>Distance: ${nearest.distance} km</p> <button onclick="displayRouteToLocation(${position.lat()}, ${position.lng()})">Show Route</button> `); infoWindow.setPosition(position); infoWindow.open(map); return nearest; } return null; } // Trigger nearest location search using user's geolocation function getUserLocationAndFindNearest() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(position => { findNearestLocation(position.coords.latitude, position.coords.longitude); }, error => { alert("Could not access your location. Please enable geolocation in your browser."); }); } else { alert("Geolocation is not supported by your browser."); } }
Add a button to your HTML to trigger this function:
<div style="text-align: center; margin: 1rem 0;"> <button onclick="getUserLocationAndFindNearest()">Find Nearest Location</button> </div>
4. Add On-Map Navigation (Using Directions API)
To display routes directly on your map, use the Google Maps Directions API (ensure your API key has this service enabled):
function displayRouteToLocation(destLat, destLng) { const directionsService = new google.maps.DirectionsService(); const directionsRenderer = new google.maps.DirectionsRenderer(); directionsRenderer.setMap(map); if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(position => { const origin = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); const destination = new google.maps.LatLng(destLat, destLng); directionsService.route({ origin: origin, destination: destination, travelMode: google.maps.TravelMode.DRIVING }, (response, status) => { if (status === google.maps.DirectionsStatus.OK) { directionsRenderer.setDirections(response); } else { alert(`Failed to load directions: ${status}`); } }); }, error => { alert("Could not get your location to display the route."); }); } else { alert("Geolocation not supported by your browser."); } }
Full Working Code
HTML
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>My Custom Map Layer</title> <link rel="stylesheet" type="text/css" href="themlayer.css"> </head> <body> <h1>My Map Layer</h1> <div style="text-align: center; margin: 1rem 0;"> <button onclick="getUserLocationAndFindNearest()">Find Nearest Location</button> </div> <div id="map"></div> <script src="scriptlayerv1.js"></script> <!-- Replace YOUR_API_KEY with your actual Google Maps API key --> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap"></script> </body> </html>
CSS (themlayer.css)
html { box-sizing: border-box; font-size: 100%; } *, *::before, *::after { box-sizing: inherit; } body { margin: 0; padding: 0; background-color: black; color: aliceblue; } h1 { text-align: center; padding: 1rem 0; } #map { height: 80vh; width: 90%; margin: 0 auto; border-radius: 8px; } button { padding: 0.5rem 1rem; font-size: 1rem; cursor: pointer; background-color: #4285F4; color: white; border: none; border-radius: 4px; } button:hover { background-color: #3367D6; }
JavaScript (scriptlayerv1.js)
let map; function initMap() { map = new google.maps.Map(document.getElementById("map"), { center: { lat: 37.7853, lng: -122.41669 }, zoom: 12, }); fetch("gs://firstbucketfor2locationsmapslaer/גאו.geojson") .then(response => response.json()) .then(data => { const geoJsonData = { type: "FeatureCollection", features: data.markers.map(marker => ({ type: "Feature", properties: marker.properties, geometry: marker.geometry })) }; map.data.addGeoJson(geoJsonData); setupCustomMarkers(); }) .catch(error => console.error("Error loading GeoJSON:", error)); } function setupCustomMarkers() { map.data.setStyle(feature => { return { icon: feature.getProperty("icon"), title: feature.getProperty("name") }; }); const infoWindow = new google.maps.InfoWindow(); map.data.addListener("click", event => { const name = event.feature.getProperty("name"); const description = event.feature.getProperty("description"); const position = event.feature.getGeometry().get(); const lat = position.lat(); const lng = position.lng(); const navUrl = `https://www.google.com/maps/dir/?api=1&destination=${lat},${lng}&travelmode=driving`; infoWindow.setContent(` <h3>${name}</h3> <p>${description}</p> <button onclick="displayRouteToLocation(${lat}, ${lng})">Show Route on Map</button> <br><a href="${navUrl}" target="_blank">Open in Google Maps</a> `); infoWindow.setPosition(position); infoWindow.open(map); }); } function calculateDistance(lat1, lng1, lat2, lng2) { const earthRadius = 6371; const dLat = (lat2 - lat1) * Math.PI / 180; const dLng = (lng2 - lng1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLng/2) * Math.sin(dLng/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return earthRadius * c; } function findNearestLocation(userLat, userLng) { let nearest = null; let minDistance = Infinity; map.data.forEach(feature => { const geometry = feature.getGeometry(); if (geometry.getType() === "Point") { const [lng, lat] = geometry.get().toJSON(); const distance = calculateDistance(userLat, userLng, lat, lng); if (distance < minDistance) { minDistance = distance; nearest = { feature, distance: distance.toFixed(2) }; } } }); if (nearest) { const position = nearest.feature.getGeometry().get(); map.panTo(position); const infoWindow = new google.maps.InfoWindow(); infoWindow.setContent(` <h3>${nearest.feature.getProperty("name")}</h3> <p>Distance: ${nearest.distance} km</p> <button onclick="displayRouteToLocation(${position.lat()}, ${position.lng()})">Show Route</button> `); infoWindow.setPosition(position); infoWindow.open(map); return nearest; } return null; } function getUserLocationAndFindNearest() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(position => { findNearestLocation(position.coords.latitude, position.coords.longitude); }, error => { alert("Could not access your location. Please enable geolocation in your browser."); }); } else { alert("Geolocation is not supported by your browser."); } } function displayRouteToLocation(destLat, destLng) { const directionsService = new google.maps.DirectionsService(); const directionsRenderer = new google.maps.DirectionsRenderer(); directionsRenderer.setMap(map); if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(position => { const origin = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); const destination = new google.maps.LatLng(destLat, destLng); directionsService.route({ origin: origin, destination: destination, travelMode: google.maps.TravelMode.DRIVING }, (response, status) => { if (status === google.maps.DirectionsStatus.OK) { directionsRenderer.setDirections(response); } else { alert(`Failed to load directions: ${status}`); } }); }, error => { alert("Could not get your location to display the route."); }); } else { alert("Geolocation not supported by your browser."); } } window.initMap = initMap;
Key Reminders
- Ensure your Google Maps API key has Maps JavaScript API and Directions API enabled in the Google Cloud Console.
- Make sure your GeoJSON file in the GS bucket is publicly accessible (otherwise the fetch request will fail).
- Test geolocation features over HTTPS (browsers block geolocation on HTTP except localhost).
备注:内容来源于stack exchange,提问作者Einav Kesem S.

