Handle marker collisions
Vector maps provide basic support for marker collision. For example, you can modify the marker API to hide labels. Vector maps also provide support for prioritization of markers.
The following example always displays markers and hides underlying labels:
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
collisionBehavior:
google.maps.CollisionBehavior.REQUIRED_AND_HIDES_OPTIONAL,
});
The following example hides markers if they collide with a required marker and hides underlying labels:
var marker = new google.maps.Marker({
position: event.latLng,
map: map,
collisionBehavior:
google.maps.CollisionBehavior.OPTIONAL_AND_HIDES_LOWER_PRIORITY,
});
TypeScript
let map: google.maps.Map; // Initialize and add the map function initMap(): void { let markers: google.maps.Marker[] = []; // @ts-ignore Beta functionality let collisionBehavior = google.maps.CollisionBehavior.REQUIRED; map = new google.maps.Map( document.getElementById("map") as HTMLElement, { mapId: "3a3b33f0edd6ed2a", center: { lat: 47.609414458375674, lng: -122.33897030353548 }, zoom: 17, } as google.maps.MapOptions ); const menuList = document.querySelector(".mdc-list") as HTMLUListElement; // Add the behaviors to the select options // @ts-ignore Beta functionality for (const [key, value] of Object.entries(google.maps.CollisionBehavior)) { const item = document.createElement("LI"); item.classList.add("mdc-list-item"); item.setAttribute("data-value", key); const itemText = document.createElement("SPAN") as HTMLSpanElement; itemText.classList.add("mdc-list-item__text"); itemText.innerText = value as string; item.appendChild(itemText); menuList.appendChild(item); } // @ts-ignore const select = new mdc.select.MDCSelect( document.querySelector(".mdc-select") as HTMLElement ); select.listen("MDCSelect:change", () => { collisionBehavior = select.value; markers.forEach((marker) => { marker.set("collisionBehavior", collisionBehavior); }); }); select.value = collisionBehavior; // Create some markers on the map markers = [ [-122.3402, 47.6093], [-122.3402, 47.6094], [-122.3403, 47.6094], [-122.3384, 47.6098], [-122.3389, 47.6095], [-122.3396, 47.6095], [-122.3379, 47.6097], [-122.3378, 47.6097], [-122.3396, 47.6091], [-122.3383, 47.6089], [-122.3379, 47.6093], [-122.3381, 47.6095], [-122.3378, 47.6095], ].map( ([lng, lat]: number[]) => new google.maps.Marker({ position: new google.maps.LatLng({ lat, lng }), map, collisionBehavior: collisionBehavior, } as google.maps.MarkerOptions) ); }
JavaScript
// eslint-disable no-undef let map; // Initialize and add the map function initMap() { let markers = []; let collisionBehavior = google.maps.CollisionBehavior.REQUIRED; map = new google.maps.Map(document.getElementById("map"), { mapId: "3a3b33f0edd6ed2a", center: { lat: 47.609414458375674, lng: -122.33897030353548 }, zoom: 17, }); const menuList = document.querySelector(".mdc-list"); // Add the behaviors to the select options for (const [key, value] of Object.entries(google.maps.CollisionBehavior)) { const item = document.createElement("LI"); item.classList.add("mdc-list-item"); item.setAttribute("data-value", key); const itemText = document.createElement("SPAN"); itemText.classList.add("mdc-list-item__text"); itemText.innerText = value; item.appendChild(itemText); menuList.appendChild(item); } const select = new mdc.select.MDCSelect( document.querySelector(".mdc-select") ); select.listen("MDCSelect:change", () => { collisionBehavior = select.value; markers.forEach((marker) => { marker.set("collisionBehavior", collisionBehavior); }); }); select.value = collisionBehavior; // Create some markers on the map markers = [ [-122.3402, 47.6093], [-122.3402, 47.6094], [-122.3403, 47.6094], [-122.3384, 47.6098], [-122.3389, 47.6095], [-122.3396, 47.6095], [-122.3379, 47.6097], [-122.3378, 47.6097], [-122.3396, 47.6091], [-122.3383, 47.6089], [-122.3379, 47.6093], [-122.3381, 47.6095], [-122.3378, 47.6095], ].map( ([lng, lat]) => new google.maps.Marker({ position: new google.maps.LatLng({ lat, lng }), map, collisionBehavior: collisionBehavior, }) ); }
CSS
:root { --mdc-theme-primary: #1a73e8; --mdc-theme-secondary: #rgb(225, 245, 254); --mdc-theme-on-primary: #fff; --mdc-theme-on-secondary: rgb(1, 87, 155); } .mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label { color: var(--mdc-theme-primary); } .mdc-select--focused .mdc-select__dropdown-icon { background: url(data:image/svg+xml,%3Csvg%20width%3D%2210px%22%20height%3D%225px%22%20viewBox%3D%227%2010%2010%205%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%20%20%3Cpolygon%20id%3D%22Shape%22%20stroke%3D%22none%22%20fill%3D%22%23000%22%20fill-rule%3D%22evenodd%22%20opacity%3D%220.54%22%20points%3D%227%2010%2012%2015%2017%2010%22%3E%3C%2Fpolygon%3E%0A%3C%2Fsvg%3E) no-repeat center; } .mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label { color: var(--mdc-theme-primary); } /* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } #container { height: 100%; display: flex; } #sidebar { flex-basis: 15rem; flex-grow: 1; padding: 1rem; max-width: 30rem; height: 100%; box-sizing: border-box; display: flex; } #map { flex-basis: 0; flex-grow: 4; height: 100%; } .mdc-select__anchor, .mdc-select__menu { width: 100%; }
HTML
<!DOCTYPE html> <html> <head> <title>Marker Collision Management</title> <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script> <link href="https://unpkg.com/material-components-web@6.0.0/dist/material-components-web.css" rel="stylesheet" /> <script src="https://unpkg.com/material-components-web@6.0.0/dist/material-components-web.min.js"></script> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <link rel="stylesheet" type="text/css" href="./style.css" /> <script src="./index.js"></script> </head> <body> <div id="container"> <div id="map"></div> <div id="sidebar"> <div class="mdc-select mdc-select--outlined"> <div class="mdc-select__anchor" aria-labelledby="outlined-select-label" > <input type="text" disabled readonly id="demo-selected-text" class="mdc-select__selected-text" /> <i class="mdc-select__dropdown-icon"></i> <span class="mdc-notched-outline"> <span class="mdc-notched-outline__leading"></span> <span class="mdc-notched-outline__notch"> <span id="outlined-select-label" class="mdc-floating-label mdc-theme--primary" >Pick a Collision Behavior</span > </span> <span class="mdc-notched-outline__trailing"></span> </span> </div> <div class="mdc-select__menu mdc-menu mdc-menu-surface"> <ul class="mdc-list"></ul> </div> </div> </div> </div> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=beta&map_ids=3a3b33f0edd6ed2a" defer ></script> </body> </html>
All
<!DOCTYPE html> <html> <head> <title>Marker Collision Management</title> <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script> <link href="https://unpkg.com/material-components-web@6.0.0/dist/material-components-web.css" rel="stylesheet" /> <script src="https://unpkg.com/material-components-web@6.0.0/dist/material-components-web.min.js"></script> <link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons" /> <style type="text/css"> :root { --mdc-theme-primary: #1a73e8; --mdc-theme-secondary: #rgb(225, 245, 254); --mdc-theme-on-primary: #fff; --mdc-theme-on-secondary: rgb(1, 87, 155); } .mdc-text-field--focused:not(.mdc-text-field--disabled) .mdc-floating-label { color: var(--mdc-theme-primary); } .mdc-select--focused .mdc-select__dropdown-icon { background: url(data:image/svg+xml,%3Csvg%20width%3D%2210px%22%20height%3D%225px%22%20viewBox%3D%227%2010%2010%205%22%20version%3D%221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F%2Fwww.w3.org%2F1999%2Fxlink%22%3E%0A%20%20%20%20%3Cpolygon%20id%3D%22Shape%22%20stroke%3D%22none%22%20fill%3D%22%23000%22%20fill-rule%3D%22evenodd%22%20opacity%3D%220.54%22%20points%3D%227%2010%2012%2015%2017%2010%22%3E%3C%2Fpolygon%3E%0A%3C%2Fsvg%3E) no-repeat center; } .mdc-select:not(.mdc-select--disabled).mdc-select--focused .mdc-floating-label { color: var(--mdc-theme-primary); } /* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } #container { height: 100%; display: flex; } #sidebar { flex-basis: 15rem; flex-grow: 1; padding: 1rem; max-width: 30rem; height: 100%; box-sizing: border-box; display: flex; } #map { flex-basis: 0; flex-grow: 4; height: 100%; } .mdc-select__anchor, .mdc-select__menu { width: 100%; } </style> <script> // eslint-disable no-undef let map; // Initialize and add the map function initMap() { let markers = []; let collisionBehavior = google.maps.CollisionBehavior.REQUIRED; map = new google.maps.Map(document.getElementById("map"), { mapId: "3a3b33f0edd6ed2a", center: { lat: 47.609414458375674, lng: -122.33897030353548 }, zoom: 17, }); const menuList = document.querySelector(".mdc-list"); // Add the behaviors to the select options for (const [key, value] of Object.entries( google.maps.CollisionBehavior )) { const item = document.createElement("LI"); item.classList.add("mdc-list-item"); item.setAttribute("data-value", key); const itemText = document.createElement("SPAN"); itemText.classList.add("mdc-list-item__text"); itemText.innerText = value; item.appendChild(itemText); menuList.appendChild(item); } const select = new mdc.select.MDCSelect( document.querySelector(".mdc-select") ); select.listen("MDCSelect:change", () => { collisionBehavior = select.value; markers.forEach((marker) => { marker.set("collisionBehavior", collisionBehavior); }); }); select.value = collisionBehavior; // Create some markers on the map markers = [ [-122.3402, 47.6093], [-122.3402, 47.6094], [-122.3403, 47.6094], [-122.3384, 47.6098], [-122.3389, 47.6095], [-122.3396, 47.6095], [-122.3379, 47.6097], [-122.3378, 47.6097], [-122.3396, 47.6091], [-122.3383, 47.6089], [-122.3379, 47.6093], [-122.3381, 47.6095], [-122.3378, 47.6095], ].map( ([lng, lat]) => new google.maps.Marker({ position: new google.maps.LatLng({ lat, lng }), map, collisionBehavior: collisionBehavior, }) ); } </script> </head> <body> <div id="container"> <div id="map"></div> <div id="sidebar"> <div class="mdc-select mdc-select--outlined"> <div class="mdc-select__anchor" aria-labelledby="outlined-select-label" > <input type="text" disabled readonly id="demo-selected-text" class="mdc-select__selected-text" /> <i class="mdc-select__dropdown-icon"></i> <span class="mdc-notched-outline"> <span class="mdc-notched-outline__leading"></span> <span class="mdc-notched-outline__notch"> <span id="outlined-select-label" class="mdc-floating-label mdc-theme--primary" >Pick a Collision Behavior</span > </span> <span class="mdc-notched-outline__trailing"></span> </span> </div> <div class="mdc-select__menu mdc-menu mdc-menu-surface"> <ul class="mdc-list"></ul> </div> </div> </div> </div> <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap&libraries=&v=beta&map_ids=3a3b33f0edd6ed2a" defer ></script> </body> </html>
Create a starter application from sample
A skeleton starter application using TypeScript, Webpack, and Babel can be generated from this sample using one of the methods below.
Run Locally
Node.js is required to run this sample locally. Follow these instructions to install Node.js and NPM.
npx @googlemaps/js-samples init marker-collision-management DESTINATION_FOLDER
Run in Google Cloud Shell
Google Cloud Shell is an interactive shell environment for Google Cloud Platform that makes it easy for you to learn and experiment with GCP and manage your projects and resources from your web browser.
Run in Cloud Shell