-
-
Save bootsified/7d3bbfe05e0b73d5c5d3 to your computer and use it in GitHub Desktop.
<!-- | |
* GOOGLE MAP W/ MULTIPLE MARKERS AND OPTIONAL GEOCODING | |
* by Boots (www.boots.media) | |
* Working demo here: https://codepen.io/bootsified/details/XWbgwNr | |
* | |
* To use geocoding for locations, set `useGeocoding = true;` (limit 10 locations). | |
* To manually place markers by lat/lng, set `useGeocoding = false;` (no limit). Locations array must contain lat/lng data. | |
--> | |
<script src="https://maps.googleapis.com/maps/api/js?key=[YOUR_APP_KEY_GOES_HERE]"></script> | |
<script> | |
// Set global variables | |
var map; | |
var bounds; | |
var locationCount; | |
var mapOptions; | |
var infoWindow = null; | |
var defaultZoom = 14; // The minimum zoom level | |
var mapElementId = "myGoogleMap"; | |
var mapElement = document.getElementById(mapElementId); | |
var useGeocoding = true; // true: geocode marker from street address, false: set markers using lat/lng | |
// Set marker attributes. If you need unique values for each marker, | |
// you can update the values directly in the locations array. | |
var markerWidth = 32; | |
var markerHeight = 32; | |
var markerScale = 1; // Scale the image, if you can't control the source file (0 - 1). | |
// The array of locations to mark on the map. | |
// Google limits geocoded locations to 10 per pageload. | |
// No limit for markers set with lat/lng. | |
var locations = [ | |
[ | |
"Empire State Building", // name | |
"20 W 34th St", // street | |
"", // street 2 (ex. Suite 1234) | |
"New York", // city | |
"NY", // state | |
"10001", // zip | |
{ | |
// Marker icon config object | |
url: "https://maps.google.com/mapfiles/ms/micons/blue.png", | |
size: new google.maps.Size(markerWidth, markerHeight), | |
origin: new google.maps.Point(0, 0), | |
anchor: new google.maps.Point(markerWidth * (markerScale / 2), markerHeight * markerScale), | |
scaledSize: new google.maps.Size(markerWidth * markerScale, markerHeight * markerScale) | |
}, | |
new google.maps.Size(markerWidth * (markerScale / 4) * -1, markerHeight * markerScale), // marker offset | |
new google.maps.LatLng(40.7484995, -73.9882267) | |
], | |
[ | |
"Independence Hall", // name | |
"520 Chestnut St", // street | |
"", // street 2 (ex. Suite 1234) | |
"Philadelphia", // city | |
"PA", // state | |
"19106", // zip | |
{ | |
// Marker icon config object | |
url: "https://maps.google.com/mapfiles/ms/micons/red.png", | |
size: new google.maps.Size(markerWidth, markerHeight), | |
origin: new google.maps.Point(0, 0), | |
anchor: new google.maps.Point(markerWidth * (markerScale / 2), markerHeight * markerScale), | |
scaledSize: new google.maps.Size(markerWidth * markerScale, markerHeight * markerScale) | |
}, | |
new google.maps.Size(markerWidth * (markerScale / 4) * -1, markerHeight * markerScale), // marker offset | |
new google.maps.LatLng(39.949140, -75.149730) | |
] | |
]; | |
// Init map on Google 'load' event | |
google.maps.event.addDomListener(window, "load", init); | |
// Init the map | |
function init() { | |
// Customize look of the map. | |
// https://www.mapbuildr.com/ | |
mapOptions = { | |
zoom: defaultZoom, | |
zoomControl: true, | |
zoomControlOptions: { | |
style: google.maps.ZoomControlStyle.SMALL | |
}, | |
disableDoubleClickZoom: false, | |
mapTypeControl: false, | |
panControl: false, | |
scaleControl: false, | |
scrollwheel: false, | |
streetViewControl: false, | |
draggable: true, | |
overviewMapControl: false, | |
mapTypeId: google.maps.MapTypeId.ROADMAP, | |
styles: [ | |
{ | |
featureType: "all", | |
stylers: [{ saturation: -100 }, { gamma: 0.8 }] | |
}, | |
{ | |
featureType: "poi", | |
stylers: [{ visibility: "off" }] | |
}, | |
{ | |
featureType: "transit", | |
stylers: [{ visibility: "off" }] | |
} | |
] | |
}; | |
// Create new map object | |
map = new google.maps.Map(mapElement, mapOptions); | |
// OPTIONAL: Set listener to tell when map is idle | |
// Can be useful during dev | |
// google.maps.event.addListener(map, "idle", function() { | |
// console.log("map is idle"); | |
// }); | |
if (useGeocoding) { | |
var geocoder = new google.maps.Geocoder(); | |
} | |
bounds = new google.maps.LatLngBounds(); | |
locationCount = 0; | |
// Init InfoWindow and leave it | |
// for use when user clicks marker | |
infoWindow = new google.maps.InfoWindow({ content: "Loading content..." }); | |
// Loop through locations and set markers | |
for (i = 0; i < locations.length; i++) { | |
if (useGeocoding) { | |
// street+city,state+zip | |
var address = locations[i][1] + "+" + locations[i][2] + "," + locations[i][3] + "+" + locations[i][4]; | |
//Get latitude and longitude from address | |
geocoder.geocode({ address: address }, onGeocodeComplete(i)); | |
} else { | |
placeLatLngMarker(i); | |
} | |
} | |
// Re-center map on window resize | |
google.maps.event.addDomListener(window, "resize", function() { | |
var center = map.getCenter(); | |
google.maps.event.trigger(map, "resize"); | |
map.setCenter(center); | |
}); | |
} // END init() | |
// Triggered as the geocode callback | |
function onGeocodeComplete(i) { | |
// Callback function for geocode on response from Google. | |
// We wrap it in 'onGeocodeComplete' so we can send the | |
// location index through to the marker to establish | |
// content. | |
var geocodeCallBack = function(results, status) { | |
if (status == google.maps.GeocoderStatus.OK) { | |
// Create the marker for the location | |
// We use 'html' key to attach the | |
// InfoWindow content to the marker. | |
var marker = new google.maps.Marker({ | |
icon: locations[i][6], | |
position: results[0].geometry.location, | |
map: map, | |
window_offset: locations[i][7], | |
html: getInfoWindowContent(i) | |
}); | |
// Set event to display the InfoWindow anchored | |
// to the marker when the marker is clicked. | |
google.maps.event.addListener(marker, "click", function() { | |
showInfoWindow(this); | |
}); | |
// Add this marker to the map bounds | |
extendBounds(results[0].geometry.location); | |
} else { | |
console.log("Location geocoding has failed: " + google.maps.GeocoderStatus); | |
// Hide empty map element on error | |
mapElement.style.display = "none"; | |
} | |
}; // END geocodeCallBack() | |
return geocodeCallBack; | |
} // END onGeocodeComplete() | |
function placeLatLngMarker(i) { | |
// Create the marker for the location | |
// We use 'html' key to attach the | |
// InfoWindow content to the marker. | |
var marker = new google.maps.Marker({ | |
icon: locations[i][6], | |
position: locations[i][8], | |
map: map, | |
window_offset: locations[i][7], | |
html: getInfoWindowContent(i) | |
}); | |
// Set event to display the InfoWindow anchored | |
// to the marker when the marker is clicked. | |
google.maps.event.addListener(marker, "click", function() { | |
showInfoWindow(this); | |
}); | |
// Add this marker to the map bounds | |
extendBounds(locations[i][8]); | |
} | |
// The HTML content for the InfoWindow. | |
// Includes a form to allow the user to | |
// get directions. | |
function getInfoWindowContent(i) { | |
var windowContent = '<form id="form-directions" action="http://maps.google.com/maps" method="get" target="_blank">\ | |
<p><strong>' + locations[i][0] + '</strong><br>\ | |
' + locations[i][1] + ', ' + locations[i][2] + '<br>\ | |
' + locations[i][3] + ', ' + locations[i][4] + ' ' + locations[i][5] + '</p>\ | |
<input type="hidden" name="daddr" value="' + locations[i][1] + ', ' + locations[i][3] + ', ' + locations[i][4] + ' ' + locations[i][5] + '" />\ | |
<label for="saddr" class="alt-italic">Need directions?</label>\ | |
<div class="input-group input-group--inline input-group--sm">\ | |
<input name="saddr" type="text" class="input-group__input" placeholder="Your Address...">\ | |
<button class="input-group__btn button" type="submit">Go!</button>\ | |
</div><!-- /input-group -->\ | |
</form>'; | |
return windowContent; | |
} | |
function showInfoWindow(marker) { | |
// Updates the InfoWindow content with | |
// the HTML held in the marker ('this'). | |
infoWindow.setOptions({ | |
content: marker.html, | |
pixelOffset: marker.window_offset | |
}); | |
infoWindow.open(map, marker); | |
} | |
// Establishes the bounds for all the markers | |
// then centers and zooms the map to show all. | |
function extendBounds(latlng) { | |
++locationCount; | |
bounds.extend(latlng); | |
if (locationCount == locations.length) { | |
map.fitBounds(bounds); | |
var currentZoom = map.getZoom(); | |
if (currentZoom > mapOptions.zoom) { | |
map.setZoom(mapOptions.zoom); | |
} | |
} | |
} // END extendBounds() | |
</script> | |
<style> | |
.google-map { | |
background-color: #e0e0e0; | |
height: 40rem; | |
max-height: 100vh; | |
} | |
</style> | |
<div id="myGoogleMap" class="google-map"></div> |
Sadly this does not work anymore.
"cation geocoding has failed: ' + google.maps.GeocoderStatus)', 'window.log' is undefined)"
After i changed window.log to console.log it outputs just a "Location geocoding has failed: [object Object]".
:-(
For me it´s working perfect. Don't forget to set the url to your marker PNG's.
You don't need "sensor=false" anymore.
This worked perfectly. Saved me from quite a headache I was encountering with the Geocoder, particularly with the info windows. Thanks for sharing this.
This worked perfectly. Saved me from quite a headache I was encountering with the Geocoder, particularly with the info windows. Thanks for sharing this.
@pwil30 Awesome! Glad I could help. This one took a while to put together, but it's been so handy. 🙌
I realized I'd tweaked this out some over the years in my projects, so I updated it here. Adds the ability to scale the marker icon, if needed (if you can't control the source image). Also sets a minimum zoom level, so the map won't zoom in too far if there is only one marker.
Fantastic, thanks so much
Love this, and has so far proved extremely helpful, so thank you very much for that :)
One thing that would be very helpful however, would be the addition of using lat/long, rather than the address. One issue with using addresses for markers is that we seem to be limited to a max number of 10. Using lat / long be all accounts does not have limits.
I'm currently trying to work my way through this adding in the addition of lat / long for the markers.
Craig
@untiedshoes It's actually much simpler to set markers by lat/lng. I've updated the gist with that option, as well as cleaning things up a bit more. You can also now see a working demo here: https://codepen.io/bootsified/details/XWbgwNr.
I never thought about adding that option. Makes total sense. Thanks for the suggestion. 🙌
Awesome man!!
I've literally (in just the last 10 mins), also done my own solution.
Be interesting to see how you've done it too :)
This was very useful and helped me solve dealing with geocoding's asynchronous ways.