Create markers with HTML and CSS

With advanced markers you can use custom HTML and CSS to create markers with high visual impact, that can feature interactivity and animation. All AdvancedMarkerElement instances are added to the DOM as HTML elements, which you can access via the element property, and manipulate in the same way as any other DOM element. Because AdvancedMarkerElement is a DOM element, you can directly apply CSS styles to the default marker, and create custom markers completely from scratch using HTML and CSS.

Simple HTML marker

This example map shows creating a simple custom HTML marker:

View the source

The following example shows creating a new DIV element, assigning a CSS class and text content to the DIV, then passing the DIV as the value of AdvancedMarkerElement.content :

TypeScript

 async 
  
 function 
  
 initMap 
 () 
  
 { 
  
 // Request needed libraries. 
  
 const 
  
 { 
  
 Map 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "maps" 
 ) 
  
 as 
  
 google 
 . 
 maps 
 . 
 MapsLibrary 
 ; 
  
 const 
  
 { 
  
 AdvancedMarkerElement 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "marker" 
 ) 
  
 as 
  
 google 
 . 
 maps 
 . 
 MarkerLibrary 
 ; 
  
 const 
  
 map 
  
 = 
  
 new 
  
 Map 
 ( 
 document 
 . 
 getElementById 
 ( 
 'map' 
 ) 
  
 as 
  
 HTMLElement 
 , 
  
 { 
  
 center 
 : 
  
 { 
  
 lat 
 : 
  
 37.42 
 , 
  
 lng 
 : 
  
 - 
 122.1 
  
 }, 
  
 zoom 
 : 
  
 14 
 , 
  
 mapId 
 : 
  
 '4504f8b37365c3d0' 
 , 
  
 }); 
  
 const 
  
 priceTag 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 'div' 
 ); 
  
 priceTag 
 . 
 className 
  
 = 
  
 'price-tag' 
 ; 
  
 priceTag 
 . 
 textContent 
  
 = 
  
 '$2.5M' 
 ; 
  
 const 
  
 marker 
  
 = 
  
 new 
  
 AdvancedMarkerElement 
 ({ 
  
 map 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.42 
 , 
  
 lng 
 : 
  
 - 
 122.1 
  
 }, 
  
 content 
 : 
  
 priceTag 
 , 
  
 }); 
 } 
 initMap 
 (); 
  

JavaScript

 async 
  
 function 
  
 initMap 
 () 
  
 { 
  
 // Request needed libraries. 
  
 const 
  
 { 
  
 Map 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "maps" 
 ); 
  
 const 
  
 { 
  
 AdvancedMarkerElement 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "marker" 
 ); 
  
 const 
  
 map 
  
 = 
  
 new 
  
 Map 
 ( 
 document 
 . 
 getElementById 
 ( 
 'map' 
 ), 
  
 { 
  
 center 
 : 
  
 { 
  
 lat 
 : 
  
 37.42 
 , 
  
 lng 
 : 
  
 - 
 122.1 
  
 }, 
  
 zoom 
 : 
  
 14 
 , 
  
 mapId 
 : 
  
 '4504f8b37365c3d0' 
 , 
  
 }); 
  
 const 
  
 priceTag 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 'div' 
 ); 
  
 priceTag 
 . 
 className 
  
 = 
  
 'price-tag' 
 ; 
  
 priceTag 
 . 
 textContent 
  
 = 
  
 '$2.5M' 
 ; 
  
 const 
  
 marker 
  
 = 
  
 new 
  
 AdvancedMarkerElement 
 ({ 
  
 map 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.42 
 , 
  
 lng 
 : 
  
 - 
 122.1 
  
 }, 
  
 content 
 : 
  
 priceTag 
 , 
  
 }); 
 } 
 initMap 
 (); 
  

CSS

 /* 
 * Always set the map height explicitly to define the size of the div element 
 * that contains the map. 
 */ 
 # 
 map 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
 } 
 /* 
 * Optional: Makes the sample page fill the window. 
 */ 
 html 
 , 
 body 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
  
 margin 
 : 
  
 0 
 ; 
  
 padding 
 : 
  
 0 
 ; 
 } 
 /* HTML marker styles */ 
 . 
 price-tag 
  
 { 
  
 background-color 
 : 
  
 #4285F4 
 ; 
  
 border-radius 
 : 
  
 8 
 px 
 ; 
  
 color 
 : 
  
 #FFFFFF 
 ; 
  
 font-size 
 : 
  
 14 
 px 
 ; 
  
 padding 
 : 
  
 10 
 px 
  
 15 
 px 
 ; 
  
 position 
 : 
  
 relative 
 ; 
  
 transform 
 : 
  
 translateY 
 ( 
 -8 
 px 
 ); 
 } 
 . 
 price-tag 
 :: 
 after 
  
 { 
  
 content 
 : 
  
 "" 
 ; 
  
 position 
 : 
  
 absolute 
 ; 
  
 left 
 : 
  
 50 
 % 
 ; 
  
 top 
 : 
  
 100 
 % 
 ; 
  
 transform 
 : 
  
 translate 
 ( 
 -50 
 % 
 , 
  
 0 
 ); 
  
 width 
 : 
  
 0 
 ; 
  
 height 
 : 
  
 0 
 ; 
  
 border-left 
 : 
  
 8 
 px 
  
 solid 
  
 transparent 
 ; 
  
 border-right 
 : 
  
 8 
 px 
  
 solid 
  
 transparent 
 ; 
  
 border-top 
 : 
  
 8 
 px 
  
 solid 
  
 #4285F4 
 ; 
 } 
  

HTML

<html>
  <head>
    <title>Advanced Marker Simple HTML</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- 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>
  </body>
</html>  

Try Sample

Interactive markers

This example shows creating a set of interactive markers that display fictional information when clicked. Most of the functionality in this example is contained within the CSS.

View the source

TypeScript

 async 
  
 function 
  
 initMap 
 () 
  
 { 
  
 // Request needed libraries. 
  
 const 
  
 { 
  
 Map 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "maps" 
 ) 
  
 as 
  
 google 
 . 
 maps 
 . 
 MapsLibrary 
 ; 
  
 const 
  
 { 
  
 AdvancedMarkerElement 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "marker" 
 ) 
  
 as 
  
 google 
 . 
 maps 
 . 
 MarkerLibrary 
 ; 
  
 const 
  
 center 
  
 = 
  
 { 
 lat 
 : 
  
 37.43238031167444 
 , 
  
 lng 
 : 
  
 - 
 122.16795397128632 
 }; 
  
 const 
  
 map 
  
 = 
  
 new 
  
 Map 
 ( 
 document 
 . 
 getElementById 
 ( 
 "map" 
 ) 
  
 as 
  
 HTMLElement 
 , 
  
 { 
  
 zoom 
 : 
  
 11 
 , 
  
 center 
 , 
  
 mapId 
 : 
  
 "4504f8b37365c3d0" 
 , 
  
 }); 
  
 for 
  
 ( 
 const 
  
 property 
  
 of 
  
 properties 
 ) 
  
 { 
  
 const 
  
 AdvancedMarkerElement 
  
 = 
  
 new 
  
 google 
 . 
 maps 
 . 
 marker 
 . 
 AdvancedMarkerElement 
 ({ 
  
 map 
 , 
  
 content 
 : 
  
 buildContent 
 ( 
 property 
 ), 
  
 position 
 : 
  
 property.position 
 , 
  
 title 
 : 
  
 property.description 
 , 
  
 }); 
  
 AdvancedMarkerElement 
 . 
 addListener 
 ( 
 "click" 
 , 
  
 () 
  
 = 
>  
 { 
  
 toggleHighlight 
 ( 
 AdvancedMarkerElement 
 , 
  
 property 
 ); 
  
 }); 
  
 } 
 } 
 function 
  
 toggleHighlight 
 ( 
 markerView 
 , 
  
 property 
 ) 
  
 { 
  
 if 
  
 ( 
 markerView 
 . 
 content 
 . 
 classList 
 . 
 contains 
 ( 
 "highlight" 
 )) 
  
 { 
  
 markerView 
 . 
 content 
 . 
 classList 
 . 
 remove 
 ( 
 "highlight" 
 ); 
  
 markerView 
 . 
 zIndex 
  
 = 
  
 null 
 ; 
  
 } 
  
 else 
  
 { 
  
 markerView 
 . 
 content 
 . 
 classList 
 . 
 add 
 ( 
 "highlight" 
 ); 
  
 markerView 
 . 
 zIndex 
  
 = 
  
 1 
 ; 
  
 } 
 } 
 function 
  
 buildContent 
 ( 
 property 
 ) 
  
 { 
  
 const 
  
 content 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 "div" 
 ); 
  
 content 
 . 
 classList 
 . 
 add 
 ( 
 "property" 
 ); 
  
 content 
 . 
 innerHTML 
  
 = 
  
 ` 
 <div class="icon"> 
 <i aria-hidden="true" class="fa fa-icon fa- 
 ${ 
 property 
 . 
 type 
 } 
 " title=" 
 ${ 
 property 
 . 
 type 
 } 
 "></i> 
 <span class="fa-sr-only"> 
 ${ 
 property 
 . 
 type 
 } 
< /span 
> </div> 
 <div class="details"> 
 <div class="price"> 
 ${ 
 property 
 . 
 price 
 } 
< /div 
> <div class="address"> 
 ${ 
 property 
 . 
 address 
 } 
< /div 
> <div class="features"> 
 <div> 
 <i aria-hidden="true" class="fa fa-bed fa-lg bed" title="bedroom"></i> 
 <span class="fa-sr-only">bedroom</span> 
 <span> 
 ${ 
 property 
 . 
 bed 
 } 
< /span 
> </div> 
 <div> 
 <i aria-hidden="true" class="fa fa-bath fa-lg bath" title="bathroom"></i> 
 <span class="fa-sr-only">bathroom</span> 
 <span> 
 ${ 
 property 
 . 
 bath 
 } 
< /span 
> </div> 
 <div> 
 <i aria-hidden="true" class="fa fa-ruler fa-lg size" title="size"></i> 
 <span class="fa-sr-only">size</span> 
 <span> 
 ${ 
 property 
 . 
 size 
 } 
 ft<sup>2</sup></span> 
 </div> 
 </div> 
 </div> 
 ` 
 ; 
  
 return 
  
 content 
 ; 
 } 
 const 
  
 properties 
  
 = 
  
 [{ 
  
 address 
 : 
  
 '215 Emily St, MountainView, CA' 
 , 
  
 description 
 : 
  
 'Single family house with modern design' 
 , 
  
 price 
 : 
  
 '$ 3,889,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 5 
 , 
  
 bath 
 : 
  
 4.5 
 , 
  
 size 
 : 
  
 300 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.50024109655184 
 , 
  
 lng 
 : 
  
 - 
 122.28528451834352 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '108 Squirrel Ln &#128063;, Menlo Park, CA' 
 , 
  
 description 
 : 
  
 'Townhouse with friendly neighbors' 
 , 
  
 price 
 : 
  
 '$ 3,050,000' 
 , 
  
 type 
 : 
  
 'building' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 3 
 , 
  
 size 
 : 
  
 200 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.44440882321596 
 , 
  
 lng 
 : 
  
 - 
 122.2160620727 
 , 
  
 }, 
 }, 
 { 
  
 address 
 : 
  
 '100 Chris St, Portola Valley, CA' 
 , 
  
 description 
 : 
  
 'Spacious warehouse great for small business' 
 , 
  
 price 
 : 
  
 '$ 3,125,000' 
 , 
  
 type 
 : 
  
 'warehouse' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 4 
 , 
  
 size 
 : 
  
 800 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.39561833718522 
 , 
  
 lng 
 : 
  
 - 
 122.21855116258479 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '98 Aleh Ave, Palo Alto, CA' 
 , 
  
 description 
 : 
  
 'A lovely store on busy road' 
 , 
  
 price 
 : 
  
 '$ 4,225,000' 
 , 
  
 type 
 : 
  
 'store-alt' 
 , 
  
 bed 
 : 
  
 2 
 , 
  
 bath 
 : 
  
 1 
 , 
  
 size 
 : 
  
 210 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.423928529779644 
 , 
  
 lng 
 : 
  
 - 
 122.1087629822001 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '2117 Su St, MountainView, CA' 
 , 
  
 description 
 : 
  
 'Single family house near golf club' 
 , 
  
 price 
 : 
  
 '$ 1,700,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 3 
 , 
  
 size 
 : 
  
 200 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.40578635332598 
 , 
  
 lng 
 : 
  
 - 
 122.15043378466069 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '197 Alicia Dr, Santa Clara, CA' 
 , 
  
 description 
 : 
  
 'Multifloor large warehouse' 
 , 
  
 price 
 : 
  
 '$ 5,000,000' 
 , 
  
 type 
 : 
  
 'warehouse' 
 , 
  
 bed 
 : 
  
 5 
 , 
  
 bath 
 : 
  
 4 
 , 
  
 size 
 : 
  
 700 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.36399747905774 
 , 
  
 lng 
 : 
  
 - 
 122.10465384268522 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '700 Jose Ave, Sunnyvale, CA' 
 , 
  
 description 
 : 
  
 '3 storey townhouse with 2 car garage' 
 , 
  
 price 
 : 
  
 '$ 3,850,000' 
 , 
  
 type 
 : 
  
 'building' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 4 
 , 
  
 size 
 : 
  
 600 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.38343706184458 
 , 
  
 lng 
 : 
  
 - 
 122.02340436985183 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '868 Will Ct, Cupertino, CA' 
 , 
  
 description 
 : 
  
 'Single family house in great school zone' 
 , 
  
 price 
 : 
  
 '$ 2,500,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 3 
 , 
  
 bath 
 : 
  
 2 
 , 
  
 size 
 : 
  
 100 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.34576403052 
 , 
  
 lng 
 : 
  
 - 
 122.04455090047453 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '655 Haylee St, Santa Clara, CA' 
 , 
  
 description 
 : 
  
 '2 storey store with large storage room' 
 , 
  
 price 
 : 
  
 '$ 2,500,000' 
 , 
  
 type 
 : 
  
 'store-alt' 
 , 
  
 bed 
 : 
  
 3 
 , 
  
 bath 
 : 
  
 2 
 , 
  
 size 
 : 
  
 450 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.362863347890716 
 , 
  
 lng 
 : 
  
 - 
 121.97802139023555 
 , 
  
 }, 
 }, 
  
 { 
  
 address 
 : 
  
 '2019 Natasha Dr, San Jose, CA' 
 , 
  
 description 
 : 
  
 'Single family house' 
 , 
  
 price 
 : 
  
 '$ 2,325,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 3.5 
 , 
  
 size 
 : 
  
 500 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.41391636421949 
 , 
  
 lng 
 : 
  
 - 
 121.94592071575907 
 , 
  
 }, 
 }]; 
 initMap 
 (); 
  

JavaScript

 async 
  
 function 
  
 initMap 
 () 
  
 { 
  
 // Request needed libraries. 
  
 const 
  
 { 
  
 Map 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "maps" 
 ); 
  
 const 
  
 { 
  
 AdvancedMarkerElement 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "marker" 
 ); 
  
 const 
  
 center 
  
 = 
  
 { 
  
 lat 
 : 
  
 37.43238031167444 
 , 
  
 lng 
 : 
  
 - 
 122.16795397128632 
  
 }; 
  
 const 
  
 map 
  
 = 
  
 new 
  
 Map 
 ( 
 document 
 . 
 getElementById 
 ( 
 "map" 
 ), 
  
 { 
  
 zoom 
 : 
  
 11 
 , 
  
 center 
 , 
  
 mapId 
 : 
  
 "4504f8b37365c3d0" 
 , 
  
 }); 
  
 for 
  
 ( 
 const 
  
 property 
  
 of 
  
 properties 
 ) 
  
 { 
  
 const 
  
 AdvancedMarkerElement 
  
 = 
  
 new 
  
 google 
 . 
 maps 
 . 
 marker 
 . 
 AdvancedMarkerElement 
 ({ 
  
 map 
 , 
  
 content 
 : 
  
 buildContent 
 ( 
 property 
 ), 
  
 position 
 : 
  
 property 
 . 
 position 
 , 
  
 title 
 : 
  
 property 
 . 
 description 
 , 
  
 }); 
  
 AdvancedMarkerElement 
 . 
 addListener 
 ( 
 "click" 
 , 
  
 () 
  
 = 
>  
 { 
  
 toggleHighlight 
 ( 
 AdvancedMarkerElement 
 , 
  
 property 
 ); 
  
 }); 
  
 } 
 } 
 function 
  
 toggleHighlight 
 ( 
 markerView 
 , 
  
 property 
 ) 
  
 { 
  
 if 
  
 ( 
 markerView 
 . 
 content 
 . 
 classList 
 . 
 contains 
 ( 
 "highlight" 
 )) 
  
 { 
  
 markerView 
 . 
 content 
 . 
 classList 
 . 
 remove 
 ( 
 "highlight" 
 ); 
  
 markerView 
 . 
 zIndex 
  
 = 
  
 null 
 ; 
  
 } 
  
 else 
  
 { 
  
 markerView 
 . 
 content 
 . 
 classList 
 . 
 add 
 ( 
 "highlight" 
 ); 
  
 markerView 
 . 
 zIndex 
  
 = 
  
 1 
 ; 
  
 } 
 } 
 function 
  
 buildContent 
 ( 
 property 
 ) 
  
 { 
  
 const 
  
 content 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 "div" 
 ); 
  
 content 
 . 
 classList 
 . 
 add 
 ( 
 "property" 
 ); 
  
 content 
 . 
 innerHTML 
  
 = 
  
 ` 
 <div class="icon"> 
 <i aria-hidden="true" class="fa fa-icon fa- 
 ${ 
 property 
 . 
 type 
 } 
 " title=" 
 ${ 
 property 
 . 
 type 
 } 
 "></i> 
 <span class="fa-sr-only"> 
 ${ 
 property 
 . 
 type 
 } 
< /span 
> </div> 
 <div class="details"> 
 <div class="price"> 
 ${ 
 property 
 . 
 price 
 } 
< /div 
> <div class="address"> 
 ${ 
 property 
 . 
 address 
 } 
< /div 
> <div class="features"> 
 <div> 
 <i aria-hidden="true" class="fa fa-bed fa-lg bed" title="bedroom"></i> 
 <span class="fa-sr-only">bedroom</span> 
 <span> 
 ${ 
 property 
 . 
 bed 
 } 
< /span 
> </div> 
 <div> 
 <i aria-hidden="true" class="fa fa-bath fa-lg bath" title="bathroom"></i> 
 <span class="fa-sr-only">bathroom</span> 
 <span> 
 ${ 
 property 
 . 
 bath 
 } 
< /span 
> </div> 
 <div> 
 <i aria-hidden="true" class="fa fa-ruler fa-lg size" title="size"></i> 
 <span class="fa-sr-only">size</span> 
 <span> 
 ${ 
 property 
 . 
 size 
 } 
 ft<sup>2</sup></span> 
 </div> 
 </div> 
 </div> 
 ` 
 ; 
  
 return 
  
 content 
 ; 
 } 
 const 
  
 properties 
  
 = 
  
 [{ 
  
 address 
 : 
  
 '215 Emily St, MountainView, CA' 
 , 
  
 description 
 : 
  
 'Single family house with modern design' 
 , 
  
 price 
 : 
  
 '$ 3,889,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 5 
 , 
  
 bath 
 : 
  
 4.5 
 , 
  
 size 
 : 
  
 300 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.50024109655184 
 , 
  
 lng 
 : 
  
 - 
 122.28528451834352 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '108 Squirrel Ln &#128063;, Menlo Park, CA' 
 , 
  
 description 
 : 
  
 'Townhouse with friendly neighbors' 
 , 
  
 price 
 : 
  
 '$ 3,050,000' 
 , 
  
 type 
 : 
  
 'building' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 3 
 , 
  
 size 
 : 
  
 200 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.44440882321596 
 , 
  
 lng 
 : 
  
 - 
 122.2160620727 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '100 Chris St, Portola Valley, CA' 
 , 
  
 description 
 : 
  
 'Spacious warehouse great for small business' 
 , 
  
 price 
 : 
  
 '$ 3,125,000' 
 , 
  
 type 
 : 
  
 'warehouse' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 4 
 , 
  
 size 
 : 
  
 800 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.39561833718522 
 , 
  
 lng 
 : 
  
 - 
 122.21855116258479 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '98 Aleh Ave, Palo Alto, CA' 
 , 
  
 description 
 : 
  
 'A lovely store on busy road' 
 , 
  
 price 
 : 
  
 '$ 4,225,000' 
 , 
  
 type 
 : 
  
 'store-alt' 
 , 
  
 bed 
 : 
  
 2 
 , 
  
 bath 
 : 
  
 1 
 , 
  
 size 
 : 
  
 210 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.423928529779644 
 , 
  
 lng 
 : 
  
 - 
 122.1087629822001 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '2117 Su St, MountainView, CA' 
 , 
  
 description 
 : 
  
 'Single family house near golf club' 
 , 
  
 price 
 : 
  
 '$ 1,700,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 3 
 , 
  
 size 
 : 
  
 200 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.40578635332598 
 , 
  
 lng 
 : 
  
 - 
 122.15043378466069 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '197 Alicia Dr, Santa Clara, CA' 
 , 
  
 description 
 : 
  
 'Multifloor large warehouse' 
 , 
  
 price 
 : 
  
 '$ 5,000,000' 
 , 
  
 type 
 : 
  
 'warehouse' 
 , 
  
 bed 
 : 
  
 5 
 , 
  
 bath 
 : 
  
 4 
 , 
  
 size 
 : 
  
 700 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.36399747905774 
 , 
  
 lng 
 : 
  
 - 
 122.10465384268522 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '700 Jose Ave, Sunnyvale, CA' 
 , 
  
 description 
 : 
  
 '3 storey townhouse with 2 car garage' 
 , 
  
 price 
 : 
  
 '$ 3,850,000' 
 , 
  
 type 
 : 
  
 'building' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 4 
 , 
  
 size 
 : 
  
 600 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.38343706184458 
 , 
  
 lng 
 : 
  
 - 
 122.02340436985183 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '868 Will Ct, Cupertino, CA' 
 , 
  
 description 
 : 
  
 'Single family house in great school zone' 
 , 
  
 price 
 : 
  
 '$ 2,500,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 3 
 , 
  
 bath 
 : 
  
 2 
 , 
  
 size 
 : 
  
 100 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.34576403052 
 , 
  
 lng 
 : 
  
 - 
 122.04455090047453 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '655 Haylee St, Santa Clara, CA' 
 , 
  
 description 
 : 
  
 '2 storey store with large storage room' 
 , 
  
 price 
 : 
  
 '$ 2,500,000' 
 , 
  
 type 
 : 
  
 'store-alt' 
 , 
  
 bed 
 : 
  
 3 
 , 
  
 bath 
 : 
  
 2 
 , 
  
 size 
 : 
  
 450 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.362863347890716 
 , 
  
 lng 
 : 
  
 - 
 121.97802139023555 
 , 
  
 }, 
  
 }, 
  
 { 
  
 address 
 : 
  
 '2019 Natasha Dr, San Jose, CA' 
 , 
  
 description 
 : 
  
 'Single family house' 
 , 
  
 price 
 : 
  
 '$ 2,325,000' 
 , 
  
 type 
 : 
  
 'home' 
 , 
  
 bed 
 : 
  
 4 
 , 
  
 bath 
 : 
  
 3.5 
 , 
  
 size 
 : 
  
 500 
 , 
  
 position 
 : 
  
 { 
  
 lat 
 : 
  
 37.41391636421949 
 , 
  
 lng 
 : 
  
 - 
 121.94592071575907 
 , 
  
 }, 
  
 }]; 
 initMap 
 (); 
  

CSS

 : 
 root 
  
 { 
  
 --building-color 
 : 
  
 #FF9800 
 ; 
  
 --house-color 
 : 
  
 #0288D1 
 ; 
  
 --shop-color 
 : 
  
 #7B1FA2 
 ; 
  
 --warehouse-color 
 : 
  
 #558B2F 
 ; 
 } 
 /* 
 * Optional: Makes the sample page fill the window. 
 */ 
 html 
 , 
 body 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
  
 margin 
 : 
  
 0 
 ; 
  
 padding 
 : 
  
 0 
 ; 
 } 
 /* 
 * Always set the map height explicitly to define the size of the div element 
 * that contains the map. 
 */ 
 # 
 map 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
  
 width 
 : 
  
 100 
 % 
 ; 
 } 
 /* 
 * Property styles in unhighlighted state. 
 */ 
 . 
 property 
  
 { 
  
 align-items 
 : 
  
 center 
 ; 
  
 background-color 
 : 
  
 #FFFFFF 
 ; 
  
 border-radius 
 : 
  
 50 
 % 
 ; 
  
 color 
 : 
  
 #263238 
 ; 
  
 display 
 : 
  
 flex 
 ; 
  
 font-size 
 : 
  
 14 
 px 
 ; 
  
 gap 
 : 
  
 15 
 px 
 ; 
  
 height 
 : 
  
 30 
 px 
 ; 
  
 justify-content 
 : 
  
 center 
 ; 
  
 padding 
 : 
  
 4 
 px 
 ; 
  
 position 
 : 
  
 relative 
 ; 
  
 position 
 : 
  
 relative 
 ; 
  
 transition 
 : 
  
 all 
  
 0.3 
 s 
  
 ease-out 
 ; 
  
 width 
 : 
  
 30 
 px 
 ; 
  
 transform 
 : 
  
 translateY 
 ( 
 -9 
 px 
 ); 
 } 
 . 
 property 
 :: 
 after 
  
 { 
  
 border-left 
 : 
  
 9 
 px 
  
 solid 
  
 transparent 
 ; 
  
 border-right 
 : 
  
 9 
 px 
  
 solid 
  
 transparent 
 ; 
  
 border-top 
 : 
  
 9 
 px 
  
 solid 
  
 #FFFFFF 
 ; 
  
 content 
 : 
  
 "" 
 ; 
  
 height 
 : 
  
 0 
 ; 
  
 left 
 : 
  
 50 
 % 
 ; 
  
 position 
 : 
  
 absolute 
 ; 
  
 top 
 : 
  
 95 
 % 
 ; 
  
 transform 
 : 
  
 translate 
 ( 
 -50 
 % 
 , 
  
 0 
 ); 
  
 transition 
 : 
  
 all 
  
 0.3 
 s 
  
 ease-out 
 ; 
  
 width 
 : 
  
 0 
 ; 
  
 z-index 
 : 
  
 1 
 ; 
 } 
 . 
 property 
  
 . 
 icon 
  
 { 
  
 align-items 
 : 
  
 center 
 ; 
  
 display 
 : 
  
 flex 
 ; 
  
 justify-content 
 : 
  
 center 
 ; 
  
 color 
 : 
  
 #FFFFFF 
 ; 
 } 
 . 
 property 
  
 . 
 icon 
  
 svg 
  
 { 
  
 height 
 : 
  
 20 
 px 
 ; 
  
 width 
 : 
  
 auto 
 ; 
 } 
 . 
 property 
  
 . 
 details 
  
 { 
  
 display 
 : 
  
 none 
 ; 
  
 flex-direction 
 : 
  
 column 
 ; 
  
 flex 
 : 
  
 1 
 ; 
 } 
 . 
 property 
  
 . 
 address 
  
 { 
  
 color 
 : 
  
 #9E9E9E 
 ; 
  
 font-size 
 : 
  
 10 
 px 
 ; 
  
 margin-bottom 
 : 
  
 10 
 px 
 ; 
  
 margin-top 
 : 
  
 5 
 px 
 ; 
 } 
 . 
 property 
  
 . 
 features 
  
 { 
  
 align-items 
 : 
  
 flex-end 
 ; 
  
 display 
 : 
  
 flex 
 ; 
  
 flex-direction 
 : 
  
 row 
 ; 
  
 gap 
 : 
  
 10 
 px 
 ; 
 } 
 . 
 property 
  
 . 
 features 
 > 
 div 
  
 { 
  
 align-items 
 : 
  
 center 
 ; 
  
 background 
 : 
  
 #F5F5F5 
 ; 
  
 border-radius 
 : 
  
 5 
 px 
 ; 
  
 border 
 : 
  
 1 
 px 
  
 solid 
  
 #ccc 
 ; 
  
 display 
 : 
  
 flex 
 ; 
  
 font-size 
 : 
  
 10 
 px 
 ; 
  
 gap 
 : 
  
 5 
 px 
 ; 
  
 padding 
 : 
  
 5 
 px 
 ; 
 } 
 /* 
 * Property styles in highlighted state. 
 */ 
 . 
 property 
 . 
 highlight 
  
 { 
  
 background-color 
 : 
  
 #FFFFFF 
 ; 
  
 border-radius 
 : 
  
 8 
 px 
 ; 
  
 box-shadow 
 : 
  
 10 
 px 
  
 10 
 px 
  
 5 
 px 
  
 rgba 
 ( 
 0 
 , 
  
 0 
 , 
  
 0 
 , 
  
 0.2 
 ); 
  
 height 
 : 
  
 80 
 px 
 ; 
  
 padding 
 : 
  
 8 
 px 
  
 15 
 px 
 ; 
  
 width 
 : 
  
 auto 
 ; 
 } 
 . 
 property 
 . 
 highlight 
 :: 
 after 
  
 { 
  
 border-top 
 : 
  
 9 
 px 
  
 solid 
  
 #FFFFFF 
 ; 
 } 
 . 
 property 
 . 
 highlight 
  
 . 
 details 
  
 { 
  
 display 
 : 
  
 flex 
 ; 
 } 
 . 
 property 
 . 
 highlight 
  
 . 
 icon 
  
 svg 
  
 { 
  
 width 
 : 
  
 50 
 px 
 ; 
  
 height 
 : 
  
 50 
 px 
 ; 
 } 
 . 
 property 
  
 . 
 bed 
  
 { 
  
 color 
 : 
  
 #FFA000 
 ; 
 } 
 . 
 property 
  
 . 
 bath 
  
 { 
  
 color 
 : 
  
 #03A9F4 
 ; 
 } 
 . 
 property 
  
 . 
 size 
  
 { 
  
 color 
 : 
  
 #388E3C 
 ; 
 } 
 /* 
 * House icon colors. 
 */ 
 . 
 property 
 . 
 highlight 
 : 
 has 
 ( 
 . 
 fa-house 
 ) 
  
 . 
 icon 
  
 { 
  
 color 
 : 
  
 var 
 ( 
 --house-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-house 
 ) 
  
 { 
  
 background-color 
 : 
  
 var 
 ( 
 --house-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-house 
 ) 
 :: 
 after 
  
 { 
  
 border-top 
 : 
  
 9 
 px 
  
 solid 
  
 var 
 ( 
 --house-color 
 ); 
 } 
 /* 
 * Building icon colors. 
 */ 
 . 
 property 
 . 
 highlight 
 : 
 has 
 ( 
 . 
 fa-building 
 ) 
  
 . 
 icon 
  
 { 
  
 color 
 : 
  
 var 
 ( 
 --building-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-building 
 ) 
  
 { 
  
 background-color 
 : 
  
 var 
 ( 
 --building-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-building 
 ) 
 :: 
 after 
  
 { 
  
 border-top 
 : 
  
 9 
 px 
  
 solid 
  
 var 
 ( 
 --building-color 
 ); 
 } 
 /* 
 * Warehouse icon colors. 
 */ 
 . 
 property 
 . 
 highlight 
 : 
 has 
 ( 
 . 
 fa-warehouse 
 ) 
  
 . 
 icon 
  
 { 
  
 color 
 : 
  
 var 
 ( 
 --warehouse-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-warehouse 
 ) 
  
 { 
  
 background-color 
 : 
  
 var 
 ( 
 --warehouse-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-warehouse 
 ) 
 :: 
 after 
  
 { 
  
 border-top 
 : 
  
 9 
 px 
  
 solid 
  
 var 
 ( 
 --warehouse-color 
 ); 
 } 
 /* 
 * Shop icon colors. 
 */ 
 . 
 property 
 . 
 highlight 
 : 
 has 
 ( 
 . 
 fa-shop 
 ) 
  
 . 
 icon 
  
 { 
  
 color 
 : 
  
 var 
 ( 
 --shop-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-shop 
 ) 
  
 { 
  
 background-color 
 : 
  
 var 
 ( 
 --shop-color 
 ); 
 } 
 . 
 property 
 : 
 not 
 ( 
 . 
 highlight 
 ) 
 : 
 has 
 ( 
 . 
 fa-shop 
 ) 
 :: 
 after 
  
 { 
  
 border-top 
 : 
  
 9 
 px 
  
 solid 
  
 var 
 ( 
 --shop-color 
 ); 
 } 
  

HTML

<html>
  <head>
    <title>Advanced Markers with HTML</title>

    <script src="https://use.fontawesome.com/releases/v6.2.0/js/all.js"></script>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="map"></div>

    <!-- 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>
  </body>
</html>  

Try Sample

Animated markers

This example creates the traditional "bounce-drop" animation using CSS and advanced markers. In the IntersectionObserver , it adds the drop CSS style. The IntersectionObserver sees when each marker enters the viewport, and adds the style. Then, the animationend event listener that the createMarker() function added to each marker removes the style.

View the source

TypeScript

 /** 
 * Returns a random lat lng position within the map bounds. 
 * @param {!google.maps.Map} map 
 * @return {!google.maps.LatLngLiteral} 
 */ 
  
 function 
  
 getRandomPosition 
 ( 
 map 
 ) 
  
 { 
  
 const 
  
 bounds 
  
 = 
  
 map 
 . 
 getBounds 
 (); 
  
 const 
  
 minLat 
  
 = 
  
 bounds 
 . 
 getSouthWest 
 (). 
 lat 
 (); 
  
 const 
  
 minLng 
  
 = 
  
 bounds 
 . 
 getSouthWest 
 (). 
 lng 
 (); 
  
 const 
  
 maxLat 
  
 = 
  
 bounds 
 . 
 getNorthEast 
 (). 
 lat 
 (); 
  
 const 
  
 maxLng 
  
 = 
  
 bounds 
 . 
 getNorthEast 
 (). 
 lng 
 (); 
  
 const 
  
 latRange 
  
 = 
  
 maxLat 
  
 - 
  
 minLat 
 ; 
  
 // Note: longitude can span from a positive longitude in the west to a 
  
 // negative one in the east. e.g. 150lng (150E) <-> -30lng (30W) is a large 
  
 // span that covers the whole USA. 
  
 let 
  
 lngRange 
  
 = 
  
 maxLng 
  
 - 
  
 minLng 
 ; 
  
 if 
  
 ( 
 maxLng 
 < 
 minLng 
 ) 
  
 { 
  
 lngRange 
  
 += 
  
 360 
 ; 
  
 } 
  
 return 
  
 { 
  
 lat 
 : 
  
 minLat 
  
 + 
  
 Math 
 . 
 random 
 () 
  
 * 
  
 latRange 
 , 
  
 lng 
 : 
  
 minLng 
  
 + 
  
 Math 
 . 
 random 
 () 
  
 * 
  
 lngRange 
 , 
  
 }; 
  
 } 
  
 const 
  
 total 
  
 = 
  
 100 
 ; 
  
 const 
  
 intersectionObserver 
  
 = 
  
 new 
  
 IntersectionObserver 
 (( 
 entries 
 ) 
  
 = 
>  
 { 
  
 for 
  
 ( 
 const 
  
 entry 
  
 of 
  
 entries 
 ) 
  
 { 
  
 if 
  
 ( 
 entry 
 . 
 isIntersecting 
 ) 
  
 { 
  
 entry 
 . 
 target 
 . 
 classList 
 . 
 add 
 ( 
 'drop' 
 ); 
  
 intersectionObserver 
 . 
 unobserve 
 ( 
 entry 
 . 
 target 
 ); 
  
 } 
  
 } 
  
 }); 
  
 async 
  
 function 
  
 initMap 
 () 
 : 
  
 Promise<void> 
  
 { 
  
 // Request needed libraries. 
  
 const 
  
 { 
  
 Map 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "maps" 
 ) 
  
 as 
  
 google 
 . 
 maps 
 . 
 MapsLibrary 
 ; 
  
 const 
  
 { 
  
 AdvancedMarkerElement 
 , 
  
 PinElement 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "marker" 
 ) 
  
 as 
  
 google 
 . 
 maps 
 . 
 MarkerLibrary 
 ; 
  
 const 
  
 position 
  
 = 
  
 { 
 lat 
 : 
  
 37.4242011827985 
 , 
  
 lng 
 : 
  
 - 
 122.09242296450893 
 }; 
  
 const 
  
 map 
  
 = 
  
 new 
  
 Map 
 ( 
 document 
 . 
 getElementById 
 ( 
 "map" 
 ) 
  
 as 
  
 HTMLElement 
 , 
  
 { 
  
 zoom 
 : 
  
 14 
 , 
  
 center 
 : 
  
 position 
 , 
  
 mapId 
 : 
  
 '4504f8b37365c3d0' 
 , 
  
 }); 
  
 // Create 100 markers to animate. 
  
 google 
 . 
 maps 
 . 
 event 
 . 
 addListenerOnce 
 ( 
 map 
 , 
  
 'idle' 
 , 
  
 () 
  
 = 
>  
 { 
  
 for 
  
 ( 
 let 
  
 i 
  
 = 
  
 0 
 ; 
  
 i 
 < 
 100 
 ; 
  
 i 
 ++ 
 ) 
  
 { 
  
 createMarker 
 ( 
 map 
 , 
  
 AdvancedMarkerElement 
 , 
  
 PinElement 
 ); 
  
 } 
  
 }); 
  
 // Add a button to reset the example. 
  
 const 
  
 controlDiv 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 "div" 
 ); 
  
 const 
  
 controlUI 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 "button" 
 ); 
  
 controlUI 
 . 
 classList 
 . 
 add 
 ( 
 "ui-button" 
 ); 
  
 controlUI 
 . 
 innerText 
  
 = 
  
 "Reset the example" 
 ; 
  
 controlUI 
 . 
 addEventListener 
 ( 
 "click" 
 , 
  
 () 
  
 = 
>  
 { 
  
 // Reset the example by reloading the map iframe. 
  
 refreshMap 
 (); 
  
 }); 
  
 controlDiv 
 . 
 appendChild 
 ( 
 controlUI 
 ); 
  
 map 
 . 
 controls 
 [ 
 google 
 . 
 maps 
 . 
 ControlPosition 
 . 
 TOP_CENTER 
 ]. 
 push 
 ( 
 controlDiv 
 ); 
  
 } 
  
 function 
  
 createMarker 
 ( 
 map 
 , 
  
 AdvancedMarkerElement 
 , 
  
 PinElement 
 ) 
  
 { 
  
  
 const 
  
 pinElement 
  
 = 
  
 new 
  
 PinElement 
 (); 
  
 const 
  
 content 
  
 = 
  
 pinElement 
 . 
 element 
 ; 
  
 const 
  
 advancedMarker 
  
 = 
  
 new 
  
 AdvancedMarkerElement 
 ({ 
  
 position 
 : 
  
 getRandomPosition 
 ( 
 map 
 ), 
  
 map 
 : 
  
 map 
 , 
  
 content 
 : 
  
 content 
 , 
  
 }); 
  
 content 
 . 
 style 
 . 
 opacity 
  
 = 
  
 '0' 
 ; 
  
  
 content 
 . 
 addEventListener 
 ( 
 'animationend' 
 , 
  
 ( 
 event 
 ) 
  
 = 
>  
 { 
  
  
 content 
 . 
 classList 
 . 
 remove 
 ( 
 'drop' 
 ); 
  
 content 
 . 
 style 
 . 
 opacity 
  
 = 
  
 '1' 
 ; 
  
 }); 
  
 const 
  
 time 
  
 = 
  
 2 
  
 + 
  
 Math 
 . 
 random 
 (); 
  
 // 2s delay for easy to see the animation 
  
 content 
 . 
 style 
 . 
 setProperty 
 ( 
 '--delay-time' 
 , 
  
 time 
  
 + 
 's' 
 ); 
  
 intersectionObserver 
 . 
 observe 
 ( 
 content 
 ); 
  
 } 
  
 function 
  
 refreshMap 
 () 
  
 { 
  
 // Refresh the map. 
  
 const 
  
 mapContainer 
  
 = 
  
 document 
 . 
 getElementById 
 ( 
 'mapContainer' 
 ); 
  
 const 
  
 map 
  
 = 
  
 document 
 . 
 getElementById 
 ( 
 'map' 
 ); 
  
 map 
 ! 
 . 
 remove 
 (); 
  
 const 
  
 mapDiv 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 'div' 
 ); 
  
 mapDiv 
 . 
 id 
  
 = 
  
 'map' 
 ; 
  
 mapContainer 
 ! 
 . 
 appendChild 
 ( 
 mapDiv 
 ); 
  
 initMap 
 (); 
  
 } 
 initMap 
 (); 
  

JavaScript

 /** 
 * Returns a random lat lng position within the map bounds. 
 * @param {!google.maps.Map} map 
 * @return {!google.maps.LatLngLiteral} 
 */ 
 function 
  
 getRandomPosition 
 ( 
 map 
 ) 
  
 { 
  
 const 
  
 bounds 
  
 = 
  
 map 
 . 
 getBounds 
 (); 
  
 const 
  
 minLat 
  
 = 
  
 bounds 
 . 
 getSouthWest 
 (). 
 lat 
 (); 
  
 const 
  
 minLng 
  
 = 
  
 bounds 
 . 
 getSouthWest 
 (). 
 lng 
 (); 
  
 const 
  
 maxLat 
  
 = 
  
 bounds 
 . 
 getNorthEast 
 (). 
 lat 
 (); 
  
 const 
  
 maxLng 
  
 = 
  
 bounds 
 . 
 getNorthEast 
 (). 
 lng 
 (); 
  
 const 
  
 latRange 
  
 = 
  
 maxLat 
  
 - 
  
 minLat 
 ; 
  
 // Note: longitude can span from a positive longitude in the west to a 
  
 // negative one in the east. e.g. 150lng (150E) <-> -30lng (30W) is a large 
  
 // span that covers the whole USA. 
  
 let 
  
 lngRange 
  
 = 
  
 maxLng 
  
 - 
  
 minLng 
 ; 
  
 if 
  
 ( 
 maxLng 
 < 
 minLng 
 ) 
  
 { 
  
 lngRange 
  
 += 
  
 360 
 ; 
  
 } 
  
 return 
  
 { 
  
 lat 
 : 
  
 minLat 
  
 + 
  
 Math 
 . 
 random 
 () 
  
 * 
  
 latRange 
 , 
  
 lng 
 : 
  
 minLng 
  
 + 
  
 Math 
 . 
 random 
 () 
  
 * 
  
 lngRange 
 , 
  
 }; 
 } 
 const 
  
 total 
  
 = 
  
 100 
 ; 
 const 
  
 intersectionObserver 
  
 = 
  
 new 
  
 IntersectionObserver 
 (( 
 entries 
 ) 
  
 = 
>  
 { 
  
 for 
  
 ( 
 const 
  
 entry 
  
 of 
  
 entries 
 ) 
  
 { 
  
 if 
  
 ( 
 entry 
 . 
 isIntersecting 
 ) 
  
 { 
  
 entry 
 . 
 target 
 . 
 classList 
 . 
 add 
 ( 
 'drop' 
 ); 
  
 intersectionObserver 
 . 
 unobserve 
 ( 
 entry 
 . 
 target 
 ); 
  
 } 
  
 } 
 }); 
 async 
  
 function 
  
 initMap 
 () 
  
 { 
  
 // Request needed libraries. 
  
 const 
  
 { 
  
 Map 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "maps" 
 ); 
  
 const 
  
 { 
  
 AdvancedMarkerElement 
 , 
  
 PinElement 
  
 } 
  
 = 
  
 await 
  
 google 
 . 
 maps 
 . 
 importLibrary 
 ( 
 "marker" 
 ); 
  
 const 
  
 position 
  
 = 
  
 { 
  
 lat 
 : 
  
 37.4242011827985 
 , 
  
 lng 
 : 
  
 - 
 122.09242296450893 
  
 }; 
  
 const 
  
 map 
  
 = 
  
 new 
  
 Map 
 ( 
 document 
 . 
 getElementById 
 ( 
 "map" 
 ), 
  
 { 
  
 zoom 
 : 
  
 14 
 , 
  
 center 
 : 
  
 position 
 , 
  
 mapId 
 : 
  
 '4504f8b37365c3d0' 
 , 
  
 }); 
  
 // Create 100 markers to animate. 
  
 google 
 . 
 maps 
 . 
 event 
 . 
 addListenerOnce 
 ( 
 map 
 , 
  
 'idle' 
 , 
  
 () 
  
 = 
>  
 { 
  
 for 
  
 ( 
 let 
  
 i 
  
 = 
  
 0 
 ; 
  
 i 
 < 
 100 
 ; 
  
 i 
 ++ 
 ) 
  
 { 
  
 createMarker 
 ( 
 map 
 , 
  
 AdvancedMarkerElement 
 , 
  
 PinElement 
 ); 
  
 } 
  
 }); 
  
 // Add a button to reset the example. 
  
 const 
  
 controlDiv 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 "div" 
 ); 
  
 const 
  
 controlUI 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 "button" 
 ); 
  
 controlUI 
 . 
 classList 
 . 
 add 
 ( 
 "ui-button" 
 ); 
  
 controlUI 
 . 
 innerText 
  
 = 
  
 "Reset the example" 
 ; 
  
 controlUI 
 . 
 addEventListener 
 ( 
 "click" 
 , 
  
 () 
  
 = 
>  
 { 
  
 // Reset the example by reloading the map iframe. 
  
 refreshMap 
 (); 
  
 }); 
  
 controlDiv 
 . 
 appendChild 
 ( 
 controlUI 
 ); 
  
 map 
 . 
 controls 
 [ 
 google 
 . 
 maps 
 . 
 ControlPosition 
 . 
 TOP_CENTER 
 ]. 
 push 
 ( 
 controlDiv 
 ); 
 } 
 function 
  
 createMarker 
 ( 
 map 
 , 
  
 AdvancedMarkerElement 
 , 
  
 PinElement 
 ) 
  
 { 
  
 const 
  
 pinElement 
  
 = 
  
 new 
  
 PinElement 
 (); 
  
 const 
  
 content 
  
 = 
  
 pinElement 
 . 
 element 
 ; 
  
 const 
  
 advancedMarker 
  
 = 
  
 new 
  
 AdvancedMarkerElement 
 ({ 
  
 position 
 : 
  
 getRandomPosition 
 ( 
 map 
 ), 
  
 map 
 : 
  
 map 
 , 
  
 content 
 : 
  
 content 
 , 
  
 }); 
  
 content 
 . 
 style 
 . 
 opacity 
  
 = 
  
 '0' 
 ; 
  
 content 
 . 
 addEventListener 
 ( 
 'animationend' 
 , 
  
 ( 
 event 
 ) 
  
 = 
>  
 { 
  
 content 
 . 
 classList 
 . 
 remove 
 ( 
 'drop' 
 ); 
  
 content 
 . 
 style 
 . 
 opacity 
  
 = 
  
 '1' 
 ; 
  
 }); 
  
 const 
  
 time 
  
 = 
  
 2 
  
 + 
  
 Math 
 . 
 random 
 (); 
  
 // 2s delay for easy to see the animation 
  
 content 
 . 
 style 
 . 
 setProperty 
 ( 
 '--delay-time' 
 , 
  
 time 
  
 + 
  
 's' 
 ); 
  
 intersectionObserver 
 . 
 observe 
 ( 
 content 
 ); 
 } 
 function 
  
 refreshMap 
 () 
  
 { 
  
 // Refresh the map. 
  
 const 
  
 mapContainer 
  
 = 
  
 document 
 . 
 getElementById 
 ( 
 'mapContainer' 
 ); 
  
 const 
  
 map 
  
 = 
  
 document 
 . 
 getElementById 
 ( 
 'map' 
 ); 
  
 map 
 . 
 remove 
 (); 
  
 const 
  
 mapDiv 
  
 = 
  
 document 
 . 
 createElement 
 ( 
 'div' 
 ); 
  
 mapDiv 
 . 
 id 
  
 = 
  
 'map' 
 ; 
  
 mapContainer 
 . 
 appendChild 
 ( 
 mapDiv 
 ); 
  
 initMap 
 (); 
 } 
 initMap 
 (); 
  

CSS

 /* 
 * Always set the map height explicitly to define the size of the div element 
 * that contains the map. 
 */ 
 # 
 map 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
 } 
 /* 
 * Optional: Makes the sample page fill the window. 
 */ 
 html 
 , 
 body 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
  
 margin 
 : 
  
 0 
 ; 
  
 padding 
 : 
  
 0 
 ; 
 } 
 /* set the default transition time */ 
 : 
 root 
  
 { 
  
 --delay-time 
 : 
  
 .5 
 s 
 ; 
 } 
 # 
 map 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
 } 
 # 
 mapContainer 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
 } 
 html 
 , 
 body 
  
 { 
  
 height 
 : 
  
 100 
 % 
 ; 
  
 margin 
 : 
  
 0 
 ; 
  
 padding 
 : 
  
 0 
 ; 
 } 
 @ 
 keyframes 
  
 drop 
  
 { 
  
 0 
 % 
  
 { 
  
 transform 
 : 
  
 translateY 
 ( 
 -200 
 px 
 ) 
  
 scaleY 
 ( 
 0.9 
 ); 
  
 opacity 
 : 
  
 0 
 ; 
  
 } 
  
 5 
 % 
  
 { 
  
 opacity 
 : 
  
 0.7 
 ; 
  
 } 
  
 50 
 % 
  
 { 
  
 transform 
 : 
  
 translateY 
 ( 
 0 
 px 
 ) 
  
 scaleY 
 ( 
 1 
 ); 
  
 opacity 
 : 
  
 1 
 ; 
  
 } 
  
 65 
 % 
  
 { 
  
 transform 
 : 
  
 translateY 
 ( 
 -17 
 px 
 ) 
  
 scaleY 
 ( 
 0.9 
 ); 
  
 opacity 
 : 
  
 1 
 ; 
  
 } 
  
 75 
 % 
  
 { 
  
 transform 
 : 
  
 translateY 
 ( 
 -22 
 px 
 ) 
  
 scaleY 
 ( 
 0.9 
 ); 
  
 opacity 
 : 
  
 1 
 ; 
  
 } 
  
 100 
 % 
  
 { 
  
 transform 
 : 
  
 translateY 
 ( 
 0 
 px 
 ) 
  
 scaleY 
 ( 
 1 
 ); 
  
 opacity 
 : 
  
 1 
 ; 
  
 } 
 } 
 . 
 drop 
  
 { 
  
 animation 
 : 
  
 drop 
  
 0.3 
 s 
  
 linear 
  
 forwards 
  
 var 
 ( 
 --delay-time 
 ); 
 } 
 . 
 ui-button 
  
 { 
  
 background-color 
 : 
  
 #fff 
 ; 
  
 border 
 : 
  
 0 
 ; 
  
 border-radius 
 : 
  
 2 
 px 
 ; 
  
 box-shadow 
 : 
  
 0 
  
 1 
 px 
  
 4 
 px 
  
 -1 
 px 
  
 rgba 
 ( 
 0 
 , 
  
 0 
 , 
  
 0 
 , 
  
 0.3 
 ); 
  
 margin 
 : 
  
 10 
 px 
 ; 
  
 padding 
 : 
  
 0 
  
 0.5 
 em 
 ; 
  
 font 
 : 
  
 400 
  
 18 
 px 
  
 Roboto 
 , 
  
 Arial 
 , 
  
 sans-serif 
 ; 
  
 overflow 
 : 
  
 hidden 
 ; 
  
 height 
 : 
  
 40 
 px 
 ; 
  
 cursor 
 : 
  
 pointer 
 ; 
 } 
 . 
 ui-button 
 : 
 hover 
  
 { 
  
 background 
 : 
  
 rgb 
 ( 
 235 
 , 
  
 235 
 , 
  
 235 
 ); 
 } 
  

HTML

<html>
  <head>
    <title>Advanced Markers CSS Animation</title>

    <link rel="stylesheet" type="text/css" href="./style.css" />
    <script type="module" src="./index.js"></script>
  </head>
  <body>
    <div id="mapContainer">
      <div id="map" style="height: 100%"></div>
    </div>

    <!-- 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>
  </body>
</html>  

Try Sample

Create a Mobile Website
View Site in Mobile | Classic
Share by: