Page Summary
-
This example demonstrates how to replace the default map controls with custom ones.
-
It covers creating custom zoom, map type, and fullscreen controls.
-
The sample provides code in both JavaScript and TypeScript.
-
Users can interact with a live demo through JSFiddle or Google Cloud Shell.
-
Instructions for cloning and running the sample locally are included.
Read the documentation.
TypeScript
const mapElement = document.querySelector('gmp-map') as google.maps.MapElement; let innerMap: google.maps.Map; async function initMap() { // Load the needed libraries. await google.maps.importLibrary('maps'); innerMap = mapElement.innerMap; // Disable the default controls. innerMap.setOptions({ disableDefaultUI: true, }); initZoomControl(innerMap); initMapTypeControl(innerMap); initFullscreenControl(innerMap); } function initZoomControl(map: google.maps.Map) { const zoomInButton = document.querySelector( '.zoom-control-in' ) as HTMLButtonElement; const zoomOutButton = document.querySelector( '.zoom-control-out' ) as HTMLButtonElement; zoomInButton.addEventListener('click', () => { map.setZoom((map.getZoom() || 0) + 1); }); zoomOutButton.addEventListener('click', () => { map.setZoom((map.getZoom() || 0) - 1); }); } async function initMapTypeControl(innerMap: google.maps.Map) { const mapTypeControlDiv = document.querySelector( '.maptype-control' ) as HTMLElement; const btnMap = document.querySelector( '.maptype-control-map' ) as HTMLButtonElement; const btnSatellite = document.querySelector( '.maptype-control-satellite' ) as HTMLButtonElement; btnMap.addEventListener('click', () => { mapTypeControlDiv.classList.add('maptype-control-is-map'); mapTypeControlDiv.classList.remove('maptype-control-is-satellite'); innerMap.setMapTypeId('roadmap'); }); btnSatellite.addEventListener('click', () => { mapTypeControlDiv.classList.add('maptype-control-is-satellite'); mapTypeControlDiv.classList.remove('maptype-control-is-map'); innerMap.setMapTypeId('hybrid'); }); } async function initFullscreenControl(innerMap: google.maps.Map) { // Get the UI elements for the fullscreen control. const btnFullscreen = document.querySelector( '#fullscreen-button' ) as HTMLButtonElement; btnFullscreen.addEventListener('click', () => { toggleFullScreen(mapElement); }); } async function toggleFullScreen(element: google.maps.MapElement) { const fullScreenIcon = document.querySelector( '#fullscreen-button .material-icons' ) as HTMLElement; try { if (!document.fullscreenElement) { element.requestFullscreen(); fullScreenIcon.innerText = 'fullscreen_exit'; } else { document.exitFullscreen(); fullScreenIcon.innerText = 'fullscreen'; } } catch (error) { console.error('Error toggling fullscreen:', error); } } initMap();
JavaScript
const mapElement = document.querySelector('gmp-map'); let innerMap; async function initMap() { // Load the needed libraries. await google.maps.importLibrary('maps'); innerMap = mapElement.innerMap; // Disable the default controls. innerMap.setOptions({ disableDefaultUI: true, }); initZoomControl(innerMap); initMapTypeControl(innerMap); initFullscreenControl(innerMap); } function initZoomControl(map) { const zoomInButton = document.querySelector('.zoom-control-in'); const zoomOutButton = document.querySelector('.zoom-control-out'); zoomInButton.addEventListener('click', () => { map.setZoom((map.getZoom() || 0) + 1); }); zoomOutButton.addEventListener('click', () => { map.setZoom((map.getZoom() || 0) - 1); }); } async function initMapTypeControl(innerMap) { const mapTypeControlDiv = document.querySelector('.maptype-control'); const btnMap = document.querySelector('.maptype-control-map'); const btnSatellite = document.querySelector('.maptype-control-satellite'); btnMap.addEventListener('click', () => { mapTypeControlDiv.classList.add('maptype-control-is-map'); mapTypeControlDiv.classList.remove('maptype-control-is-satellite'); innerMap.setMapTypeId('roadmap'); }); btnSatellite.addEventListener('click', () => { mapTypeControlDiv.classList.add('maptype-control-is-satellite'); mapTypeControlDiv.classList.remove('maptype-control-is-map'); innerMap.setMapTypeId('hybrid'); }); } async function initFullscreenControl(innerMap) { // Get the UI elements for the fullscreen control. const btnFullscreen = document.querySelector('#fullscreen-button'); btnFullscreen.addEventListener('click', () => { toggleFullScreen(mapElement); }); } async function toggleFullScreen(element) { const fullScreenIcon = document.querySelector('#fullscreen-button .material-icons'); try { if (!document.fullscreenElement) { element.requestFullscreen(); fullScreenIcon.innerText = 'fullscreen_exit'; } else { document.exitFullscreen(); fullScreenIcon.innerText = 'fullscreen'; } } catch (error) { console.error('Error toggling fullscreen:', error); } } initMap();
CSS
/* Optional: Makes the sample page fill the window. */ html, body { height: 100%; margin: 0; padding: 0; } .controls { margin: 10px; background-color: white; box-shadow: rgba(0, 0, 0, 0.3) 0px 1px 4px -1px; box-sizing: border-box; border-radius: 2px; display: flex; user-select: none; background-clip: padding-box; overflow: hidden; /* Keeps button backgrounds inside the rounded corners */ } .controls button { border: 0; background-color: white; color: rgba(0, 0, 0, 0.6); cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; transition: color 0.2s ease; } .controls button:hover { color: rgba(0, 0, 0, 0.9); } .controls.zoom-control { flex-direction: column; width: 40px; } .controls.zoom-control button { height: 40px; width: 40px; font-size: 24px; } .controls.maptype-control { flex-direction: row; height: 40px; } .controls.maptype-control button { padding: 0 12px; font-size: 14px; font-family: Roboto, Arial, sans-serif; text-transform: uppercase; height: 100%; } .controls.maptype-control.maptype-control-is-map .maptype-control-map { font-weight: 700; } .controls.maptype-control.maptype-control-is-satellite .maptype-control-satellite { font-weight: 700; } .controls.fullscreen-control { width: 40px; height: 40px; } .controls.fullscreen-control button { background: none; border: none; padding: 0; display: flex; align-items: center; justify-content: center; cursor: pointer; width: 100%; height: 100%; } .controls.fullscreen-control { width: 40px; height: 40px; } #fullscreen-button .material-icons { font-size: 28px; }
HTML
<html>
<head>
<title>Replacing Default Controls</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
<script type="module" src="./index.js"></script>
<link
href="https://fonts.googleapis.com/icon?family=Material+Icons"
rel="stylesheet" />
<!-- prettier-ignore -->
<script>(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})
({key: "AIzaSyA6myHzS10YXdcazAFalmXvDkrYCp5cLc8", v: "weekly"});</script>
</head>
<body>
<gmp-map center="-34.397,150.644" zoom="8">
<div
class="controls zoom-control"
slot="control-inline-end-block-end">
<button class="zoom-control-in" title="Zoom In">+</button>
<button class="zoom-control-out" title="Zoom Out">-</button>
</div>
<div
class="controls maptype-control maptype-control-is-map"
slot="control-block-start-inline-start">
<button class="maptype-control-map" title="Show road map">
Map
</button>
<button
class="maptype-control-satellite"
title="Show satellite imagery">
Satellite
</button>
</div>
<div
class="controls fullscreen-control"
slot="control-block-start-inline-end">
<button id="fullscreen-button" title="Toggle Fullscreen">
<span class="material-icons">fullscreen</span>
</button>
</div>
</gmp-map>
</body>
</html>Try Sample
Clone Sample
Git and Node.js are required to run this sample locally. Follow these instructions to install Node.js and NPM. The following commands clone, install dependencies and start the sample application.
git clone https://github.com/googlemaps-samples/js-api-samples.gitcd samples/control-replacementnpm inpm start