יצירת סמנים באמצעות HTML ו-CSS

באמצעות סמנים מתקדמים, אפשר להשתמש ב-HTML וב-CSS בהתאמה אישית כדי ליצור סמנים עם השפעה חזותית גבוהה, שיכולים לכלול אינטראקטיביות ואנימציה. כל המופעים של AdvancedMarkerElement מתווספים ל-DOM כרכיבי HTML, שאפשר לגשת אליהם דרך המאפיין element ולשנות אותם כמו כל רכיב אחר ב-DOM. מכיוון ש-AdvancedMarkerElement הוא רכיב DOM, אפשר להחיל ישירות סגנונות CSS על סמן ברירת המחדל וליצור סמנים מותאמים אישית מאפס באמצעות HTML ו-CSS.

סמן HTML פשוט

במפה לדוגמה הזו מוצג תהליך היצירה של סמן HTML פשוט בהתאמה אישית:

צפייה במקור

בדוגמה הבאה מוצג תהליך של יצירת רכיב DIV חדש, הקצאת מחלקת CSS ותוכן טקסט לרכיב ה-DIV, ואז העברת רכיב ה-DIV כערך של 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: 8px;   color: #FFFFFF;   font-size: 14px;   padding: 10px 15px;   position: relative;   transform: translateY(-8px); }  .price-tag::after {   content: "";   position: absolute;   left: 50%;   top: 100%;   transform: translate(-50%, 0);   width: 0;   height: 0;   border-left: 8px solid transparent;   border-right: 8px solid transparent;   border-top: 8px 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>

לניסיון

סמנים אינטראקטיביים

בדוגמה הזו מוצג תהליך של יצירת קבוצה של סמנים אינטראקטיביים שמציגים מידע בדיוני כשלוחצים עליהם. רוב הפונקציות בדוגמה הזו כלולות ב-CSS.

צפייה במקור

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: 14px;   gap: 15px;   height: 30px;   justify-content: center;   padding: 4px;   position: relative;   position: relative;   transition: all 0.3s ease-out;   width: 30px;   transform: translateY(-9px); }  .property::after {   border-left: 9px solid transparent;   border-right: 9px solid transparent;   border-top: 9px solid #FFFFFF;   content: "";   height: 0;   left: 50%;   position: absolute;   top: 95%;   transform: translate(-50%, 0);   transition: all 0.3s ease-out;   width: 0;   z-index: 1; }  .property .icon {   align-items: center;   display: flex;   justify-content: center;   color: #FFFFFF; }  .property .icon svg {   height: 20px;   width: auto; }  .property .details {   display: none;   flex-direction: column;   flex: 1; }  .property .address {   color: #9E9E9E;   font-size: 10px;   margin-bottom: 10px;   margin-top: 5px; }  .property .features {   align-items: flex-end;   display: flex;   flex-direction: row;   gap: 10px; }  .property .features > div {   align-items: center;   background: #F5F5F5;   border-radius: 5px;   border: 1px solid #ccc;   display: flex;   font-size: 10px;   gap: 5px;   padding: 5px; }  /*  * Property styles in highlighted state.  */ .property.highlight {   background-color: #FFFFFF;   border-radius: 8px;   box-shadow: 10px 10px 5px rgba(0, 0, 0, 0.2);   height: 80px;   padding: 8px 15px;   width: auto; }  .property.highlight::after {   border-top: 9px solid #FFFFFF; }  .property.highlight .details {   display: flex; }  .property.highlight .icon svg {   width: 50px;   height: 50px; }  .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: 9px 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: 9px 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: 9px 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: 9px 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>

לניסיון

סמנים מונפשים

בדוגמה הזו נוצרת אנימציית 'קפיצה ונפילה' מסורתית באמצעות CSS וסמנים מתקדמים. ב-IntersectionObserver, מתווסף סגנון ה-CSS‏ drop. הפונקציה IntersectionObserverבודקת מתי כל סמן נכנס לאזור התצוגה ומוסיפה את הסגנון. לאחר מכן, מאזין האירועים animationend שהפונקציה createMarker() הוסיפה לכל סמן מסיר את הסגנון.

צפייה במקור

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: .5s; }  #map {   height: 100%; }  #mapContainer {   height: 100%; }  html, body {   height: 100%;   margin: 0;   padding: 0; }  @keyframes drop {   0% {     transform: translateY(-200px) scaleY(0.9);     opacity: 0;   }   5% {     opacity: 0.7;   }   50% {     transform: translateY(0px) scaleY(1);     opacity: 1;   }   65% {     transform: translateY(-17px) scaleY(0.9);     opacity: 1;   }   75% {     transform: translateY(-22px) scaleY(0.9);     opacity: 1;   }   100% {     transform: translateY(0px) scaleY(1);     opacity: 1;   } } .drop {   animation: drop 0.3s linear forwards var(--delay-time); }  .ui-button {   background-color: #fff;   border: 0;   border-radius: 2px;   box-shadow: 0 1px 4px -1px rgba(0, 0, 0, 0.3);   margin: 10px;   padding: 0 0.5em;   font: 400 18px Roboto, Arial, sans-serif;   overflow: hidden;   height: 40px;   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>

לניסיון