-
-
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