-
-
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> |
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 :)
Fantastic, thanks so much