การวางซ้อนที่กําหนดเอง

เลือกแพลตฟอร์ม: Android iOS JavaScript

เกริ่นนำ

การวางซ้อนคือวัตถุบนแผนที่ที่เชื่อมโยงกับพิกัดละติจูด/ลองจิจูด ดังนั้นวัตถุเหล่านี้จะเคลื่อนที่เมื่อคุณลากหรือซูมแผนที่ ดูข้อมูลเกี่ยวกับประเภทการวางซ้อนที่กำหนดไว้ล่วงหน้าได้ที่การวาดบนแผนที่

Maps JavaScript API มีคลาส OverlayView สำหรับสร้างการวางซ้อนที่กำหนดเอง OverlayView เป็นคลาสพื้นฐานที่มีวิธีต่างๆ ที่คุณต้องใช้เมื่อสร้างการวางซ้อน ชั้นเรียนนี้ยังบอกวิธีการบางอย่างที่ทำให้แปลระหว่างพิกัดหน้าจอกับตำแหน่งบนแผนที่ได้

เพิ่มการวางซ้อนที่กำหนดเอง

สรุปขั้นตอนที่จำเป็นในการสร้างการวางซ้อนที่กำหนดเองมีดังนี้

  • ตั้งค่า prototype ของออบเจ็กต์การวางซ้อนที่กำหนดเองเป็นอินสแตนซ์ใหม่ของ google.maps.OverlayView() ผลก็คือการดำเนินการดังกล่าวจะคลาสย่อยของคลาส โฆษณาซ้อนทับ
  • สร้างตัวสร้างสำหรับการวางซ้อนที่กำหนดเอง และตั้งค่าพารามิเตอร์การเริ่มต้น
  • ใช้เมธอด onAdd() ภายในต้นแบบและแนบโอเวอร์เลย์ลงในแผนที่ ระบบจะเรียก OverlayView.onAdd() เมื่อแผนที่พร้อมสำหรับการแนบซ้อนทับ
  • ใช้เมธอด draw() ภายในต้นแบบและจัดการการแสดงผลแบบภาพของออบเจ็กต์ ระบบจะเรียก OverlayView.draw() เมื่อ แสดงออบเจ็กต์เป็นครั้งแรก
  • และคุณควรใช้วิธีการ onRemove() เพื่อล้างองค์ประกอบที่คุณเพิ่มไว้ภายในโฆษณาซ้อนทับด้วย

รายละเอียดเพิ่มเติมในแต่ละขั้นตอนมีดังนี้ คุณดูโค้ดตัวอย่างแบบเต็มที่ใช้งานได้ ซึ่งก็คือ ดูตัวอย่างโค้ด

คลาสย่อยการวางซ้อน

ตัวอย่างด้านล่างใช้ OverlayView เพื่อสร้างการวางซ้อนภาพแบบง่าย

ตอนนี้เราสร้างตัวสร้างสำหรับคลาส USGSOverlay และเริ่มต้นพารามิเตอร์ที่ส่งผ่านเป็นพร็อพเพอร์ตี้ของออบเจ็กต์ใหม่

TypeScript

/**
 * The custom USGSOverlay object contains the USGS image,
 * the bounds of the image, and a reference to the map.
 */
class USGSOverlay extends google.maps.OverlayView {
  private bounds: google.maps.LatLngBounds;
  private image: string;
  private div?: HTMLElement;

  constructor(bounds: google.maps.LatLngBounds, image: string) {
    super();

    this.bounds = bounds;
    this.image = image;
  }

JavaScript

/**
 * The custom USGSOverlay object contains the USGS image,
 * the bounds of the image, and a reference to the map.
 */
class USGSOverlay extends google.maps.OverlayView {
  bounds;
  image;
  div;
  constructor(bounds, image) {
    super();
    this.bounds = bounds;
    this.image = image;
  }

เรายังไม่สามารถแนบการวางซ้อนนี้เข้ากับแผนที่ในตัวสร้างของการวางซ้อน ก่อนอื่น เราต้องตรวจสอบให้แน่ใจว่าแผงทั้งหมดของแผนที่ใช้งานได้ เนื่องจากแผงเหล่านี้ระบุลำดับการแสดงวัตถุบนแผนที่ API จะมีเมธอดเป็นตัวช่วยเพื่อระบุว่าเกิดปัญหานี้ขึ้น เราจะพูดถึงวิธีการดังกล่าวในส่วนถัดไป

เริ่มต้นการวางซ้อน

เมื่อมีการสร้างอินสแตนซ์ครั้งแรกและพร้อมที่จะแสดง เราต้องแนบการซ้อนทับกับแผนที่ผ่าน DOM ของเบราว์เซอร์ API ระบุว่าได้เพิ่มการวางซ้อนลงในแผนที่แล้วโดยเรียกใช้เมธอด onAdd() ของการวางซ้อน ในการจัดการวิธีการนี้ เราสร้าง <div> เพื่อเก็บรูปภาพไว้ เพิ่มองค์ประกอบ <img> แนบเข้ากับ <div> แล้วแนบการวางซ้อนกับแผงรายการใดรายการหนึ่งของแผนที่ บานหน้าต่างคือโหนดภายในแผนผัง DOM

แผงประเภท MapPanes จะระบุลำดับการเรียงซ้อนของเลเยอร์ต่างๆ บนแผนที่ บานหน้าต่างต่อไปนี้ที่พร้อมใช้งานและจะแจกแจงตามลำดับที่เรียงซ้อนจากล่างขึ้นบน

  • mapPane คือแผงต่ำสุดและอยู่เหนือการ์ด ปุ่มนั้นอาจไม่ได้รับเหตุการณ์ DOM (Pane 0)
  • overlayLayer ประกอบด้วยเส้นประกอบ รูปหลายเหลี่ยม การวางซ้อนพื้น และเลเยอร์ไทล์ซ้อนทับ อาจไม่ได้รับเหตุการณ์ DOM (รูปที่ 1)
  • markerLayer มีเครื่องหมาย อาจไม่ได้รับเหตุการณ์ DOM (รูปที่ 2)
  • overlayMouseTarget มีองค์ประกอบที่ได้รับเหตุการณ์ DOM (หน้า 3)
  • floatPane มีหน้าต่างข้อมูล ซึ่งอยู่เหนือการวางซ้อนแผนที่ทั้งหมด (Pane 4)

เนื่องจากรูปภาพของเราเป็น "การวางซ้อนพื้น" เราจึงจะใช้แผง overlayLayer เมื่อมีบานหน้าต่างนั้นแล้ว เราจะแนบออบเจ็กต์กับแผงเป็นหน่วยย่อย

TypeScript

/**
 * onAdd is called when the map's panes are ready and the overlay has been
 * added to the map.
 */
onAdd() {
  this.div = document.createElement("div");
  this.div.style.borderStyle = "none";
  this.div.style.borderWidth = "0px";
  this.div.style.position = "absolute";

  // Create the img element and attach it to the div.
  const img = document.createElement("img");

  img.src = this.image;
  img.style.width = "100%";
  img.style.height = "100%";
  img.style.position = "absolute";
  this.div.appendChild(img);

  // Add the element to the "overlayLayer" pane.
  const panes = this.getPanes()!;

  panes.overlayLayer.appendChild(this.div);
}

JavaScript

/**
 * onAdd is called when the map's panes are ready and the overlay has been
 * added to the map.
 */
onAdd() {
  this.div = document.createElement("div");
  this.div.style.borderStyle = "none";
  this.div.style.borderWidth = "0px";
  this.div.style.position = "absolute";

  // Create the img element and attach it to the div.
  const img = document.createElement("img");

  img.src = this.image;
  img.style.width = "100%";
  img.style.height = "100%";
  img.style.position = "absolute";
  this.div.appendChild(img);

  // Add the element to the "overlayLayer" pane.
  const panes = this.getPanes();

  panes.overlayLayer.appendChild(this.div);
}

วาดการวางซ้อน

โปรดทราบว่าเรายังไม่ได้เรียกการแสดงผลภาพพิเศษในโค้ดด้านบน API จะเรียกใช้เมธอด draw() แยกต่างหากในการวางซ้อนเมื่อใดก็ตามที่ต้องการวาดการวางซ้อนบนแผนที่ รวมถึงเมื่อเพิ่มครั้งแรกด้วย

ดังนั้นเราจะใช้เมธอด draw() นี้ ดึงข้อมูล MapCanvasProjection ของการวางซ้อนโดยใช้ getProjection() และคำนวณพิกัดที่แน่นอนที่จะใช้จุดยึดตำแหน่งด้านขวาบนและด้านซ้ายล่างของวัตถุ จากนั้นเราจะปรับขนาด <div> ในกรณีนี้จะปรับขนาดภาพให้ตรงกับขอบเขตที่เราระบุไว้ในตัวสร้างการวางซ้อน

TypeScript

draw() {
  // We use the south-west and north-east
  // coordinates of the overlay to peg it to the correct position and size.
  // To do this, we need to retrieve the projection from the overlay.
  const overlayProjection = this.getProjection();

  // Retrieve the south-west and north-east coordinates of this overlay
  // in LatLngs and convert them to pixel coordinates.
  // We'll use these coordinates to resize the div.
  const sw = overlayProjection.fromLatLngToDivPixel(
    this.bounds.getSouthWest()
  )!;
  const ne = overlayProjection.fromLatLngToDivPixel(
    this.bounds.getNorthEast()
  )!;

  // Resize the image's div to fit the indicated dimensions.
  if (this.div) {
    this.div.style.left = sw.x + "px";
    this.div.style.top = ne.y + "px";
    this.div.style.width = ne.x - sw.x + "px";
    this.div.style.height = sw.y - ne.y + "px";
  }
}

JavaScript

draw() {
  // We use the south-west and north-east
  // coordinates of the overlay to peg it to the correct position and size.
  // To do this, we need to retrieve the projection from the overlay.
  const overlayProjection = this.getProjection();
  // Retrieve the south-west and north-east coordinates of this overlay
  // in LatLngs and convert them to pixel coordinates.
  // We'll use these coordinates to resize the div.
  const sw = overlayProjection.fromLatLngToDivPixel(
    this.bounds.getSouthWest(),
  );
  const ne = overlayProjection.fromLatLngToDivPixel(
    this.bounds.getNorthEast(),
  );

  // Resize the image's div to fit the indicated dimensions.
  if (this.div) {
    this.div.style.left = sw.x + "px";
    this.div.style.top = ne.y + "px";
    this.div.style.width = ne.x - sw.x + "px";
    this.div.style.height = sw.y - ne.y + "px";
  }
}

นำการวางซ้อนที่กำหนดเองออก

นอกจากนี้เรายังเพิ่มเมธอด onRemove() เพื่อลบการวางซ้อนออกจากแผนที่อย่างถาวร

TypeScript

/**
 * The onRemove() method will be called automatically from the API if
 * we ever set the overlay's map property to 'null'.
 */
onRemove() {
  if (this.div) {
    (this.div.parentNode as HTMLElement).removeChild(this.div);
    delete this.div;
  }
}

JavaScript

/**
 * The onRemove() method will be called automatically from the API if
 * we ever set the overlay's map property to 'null'.
 */
onRemove() {
  if (this.div) {
    this.div.parentNode.removeChild(this.div);
    delete this.div;
  }
}

ซ่อนและแสดงการวางซ้อนที่กำหนดเอง

หากต้องการซ่อนหรือแสดงการวางซ้อนแทนที่จะสร้างหรือนำออก คุณสามารถใช้เมธอด hide() และ show() ของคุณเองเพื่อปรับการมองเห็นของโฆษณาซ้อนทับ อีกวิธีหนึ่งคือ คุณสามารถปลดการซ้อนทับออกจาก DOM ของแผนที่ได้ แม้ว่าการดำเนินการนี้จะมีค่าใช้จ่ายสูงกว่าเล็กน้อยก็ตาม โปรดทราบว่าหากคุณแนบการวางซ้อนกับ DOM ของแผนที่อีกครั้ง ระบบจะเรียกใช้เมธอด onAdd() ของโฆษณาซ้อนทับอีกครั้ง

ตัวอย่างต่อไปนี้เพิ่มเมธอด hide() และ show() ลงในต้นแบบของการวางซ้อน ซึ่งจะสลับการเปิดเผยคอนเทนเนอร์ <div> นอกจากนี้ เรายังเพิ่มเมธอด toggleDOM() ซึ่งจะแนบหรือปลดการวางซ้อนออกจากแผนที่

TypeScript

/**
 *  Set the visibility to 'hidden' or 'visible'.
 */
hide() {
  if (this.div) {
    this.div.style.visibility = "hidden";
  }
}

show() {
  if (this.div) {
    this.div.style.visibility = "visible";
  }
}

toggle() {
  if (this.div) {
    if (this.div.style.visibility === "hidden") {
      this.show();
    } else {
      this.hide();
    }
  }
}

toggleDOM(map: google.maps.Map) {
  if (this.getMap()) {
    this.setMap(null);
  } else {
    this.setMap(map);
  }
}

JavaScript

/**
 *  Set the visibility to 'hidden' or 'visible'.
 */
hide() {
  if (this.div) {
    this.div.style.visibility = "hidden";
  }
}
show() {
  if (this.div) {
    this.div.style.visibility = "visible";
  }
}
toggle() {
  if (this.div) {
    if (this.div.style.visibility === "hidden") {
      this.show();
    } else {
      this.hide();
    }
  }
}
toggleDOM(map) {
  if (this.getMap()) {
    this.setMap(null);
  } else {
    this.setMap(map);
  }
}

เพิ่มการควบคุมปุ่ม

เพื่อทริกเกอร์เมธอด toggle และ toggleDom ระบบจะเพิ่มการควบคุมปุ่มลงในแผนที่

TypeScript

const toggleButton = document.createElement("button");

toggleButton.textContent = "Toggle";
toggleButton.classList.add("custom-map-control-button");

const toggleDOMButton = document.createElement("button");

toggleDOMButton.textContent = "Toggle DOM Attachment";
toggleDOMButton.classList.add("custom-map-control-button");

toggleButton.addEventListener("click", () => {
  overlay.toggle();
});

toggleDOMButton.addEventListener("click", () => {
  overlay.toggleDOM(map);
});

map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleDOMButton);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleButton);

JavaScript

const toggleButton = document.createElement("button");

toggleButton.textContent = "Toggle";
toggleButton.classList.add("custom-map-control-button");

const toggleDOMButton = document.createElement("button");

toggleDOMButton.textContent = "Toggle DOM Attachment";
toggleDOMButton.classList.add("custom-map-control-button");
toggleButton.addEventListener("click", () => {
  overlay.toggle();
});
toggleDOMButton.addEventListener("click", () => {
  overlay.toggleDOM(map);
});
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleDOMButton);
map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleButton);

กรอกโค้ดตัวอย่างให้เสร็จสมบูรณ์

โค้ดตัวอย่างแบบเต็มมีดังนี้

TypeScript

// This example adds hide() and show() methods to a custom overlay's prototype.
// These methods toggle the visibility of the container <div>.
// overlay to or from the map.

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 11,
      center: { lat: 62.323907, lng: -150.109291 },
      mapTypeId: "satellite",
    }
  );

  const bounds = new google.maps.LatLngBounds(
    new google.maps.LatLng(62.281819, -150.287132),
    new google.maps.LatLng(62.400471, -150.005608)
  );

  // The photograph is courtesy of the U.S. Geological Survey.
  let image = "https://developers.google.com/maps/documentation/javascript/";

  image += "examples/full/images/talkeetna.png";

  /**
   * The custom USGSOverlay object contains the USGS image,
   * the bounds of the image, and a reference to the map.
   */
  class USGSOverlay extends google.maps.OverlayView {
    private bounds: google.maps.LatLngBounds;
    private image: string;
    private div?: HTMLElement;

    constructor(bounds: google.maps.LatLngBounds, image: string) {
      super();

      this.bounds = bounds;
      this.image = image;
    }

    /**
     * onAdd is called when the map's panes are ready and the overlay has been
     * added to the map.
     */
    onAdd() {
      this.div = document.createElement("div");
      this.div.style.borderStyle = "none";
      this.div.style.borderWidth = "0px";
      this.div.style.position = "absolute";

      // Create the img element and attach it to the div.
      const img = document.createElement("img");

      img.src = this.image;
      img.style.width = "100%";
      img.style.height = "100%";
      img.style.position = "absolute";
      this.div.appendChild(img);

      // Add the element to the "overlayLayer" pane.
      const panes = this.getPanes()!;

      panes.overlayLayer.appendChild(this.div);
    }

    draw() {
      // We use the south-west and north-east
      // coordinates of the overlay to peg it to the correct position and size.
      // To do this, we need to retrieve the projection from the overlay.
      const overlayProjection = this.getProjection();

      // Retrieve the south-west and north-east coordinates of this overlay
      // in LatLngs and convert them to pixel coordinates.
      // We'll use these coordinates to resize the div.
      const sw = overlayProjection.fromLatLngToDivPixel(
        this.bounds.getSouthWest()
      )!;
      const ne = overlayProjection.fromLatLngToDivPixel(
        this.bounds.getNorthEast()
      )!;

      // Resize the image's div to fit the indicated dimensions.
      if (this.div) {
        this.div.style.left = sw.x + "px";
        this.div.style.top = ne.y + "px";
        this.div.style.width = ne.x - sw.x + "px";
        this.div.style.height = sw.y - ne.y + "px";
      }
    }

    /**
     * The onRemove() method will be called automatically from the API if
     * we ever set the overlay's map property to 'null'.
     */
    onRemove() {
      if (this.div) {
        (this.div.parentNode as HTMLElement).removeChild(this.div);
        delete this.div;
      }
    }

    /**
     *  Set the visibility to 'hidden' or 'visible'.
     */
    hide() {
      if (this.div) {
        this.div.style.visibility = "hidden";
      }
    }

    show() {
      if (this.div) {
        this.div.style.visibility = "visible";
      }
    }

    toggle() {
      if (this.div) {
        if (this.div.style.visibility === "hidden") {
          this.show();
        } else {
          this.hide();
        }
      }
    }

    toggleDOM(map: google.maps.Map) {
      if (this.getMap()) {
        this.setMap(null);
      } else {
        this.setMap(map);
      }
    }
  }

  const overlay: USGSOverlay = new USGSOverlay(bounds, image);

  overlay.setMap(map);

  const toggleButton = document.createElement("button");

  toggleButton.textContent = "Toggle";
  toggleButton.classList.add("custom-map-control-button");

  const toggleDOMButton = document.createElement("button");

  toggleDOMButton.textContent = "Toggle DOM Attachment";
  toggleDOMButton.classList.add("custom-map-control-button");

  toggleButton.addEventListener("click", () => {
    overlay.toggle();
  });

  toggleDOMButton.addEventListener("click", () => {
    overlay.toggleDOM(map);
  });

  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleDOMButton);
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleButton);
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example adds hide() and show() methods to a custom overlay's prototype.
// These methods toggle the visibility of the container <div>.
// overlay to or from the map.
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 11,
    center: { lat: 62.323907, lng: -150.109291 },
    mapTypeId: "satellite",
  });
  const bounds = new google.maps.LatLngBounds(
    new google.maps.LatLng(62.281819, -150.287132),
    new google.maps.LatLng(62.400471, -150.005608),
  );
  // The photograph is courtesy of the U.S. Geological Survey.
  let image = "https://developers.google.com/maps/documentation/javascript/";

  image += "examples/full/images/talkeetna.png";
  /**
   * The custom USGSOverlay object contains the USGS image,
   * the bounds of the image, and a reference to the map.
   */
  class USGSOverlay extends google.maps.OverlayView {
    bounds;
    image;
    div;
    constructor(bounds, image) {
      super();
      this.bounds = bounds;
      this.image = image;
    }
    /**
     * onAdd is called when the map's panes are ready and the overlay has been
     * added to the map.
     */
    onAdd() {
      this.div = document.createElement("div");
      this.div.style.borderStyle = "none";
      this.div.style.borderWidth = "0px";
      this.div.style.position = "absolute";

      // Create the img element and attach it to the div.
      const img = document.createElement("img");

      img.src = this.image;
      img.style.width = "100%";
      img.style.height = "100%";
      img.style.position = "absolute";
      this.div.appendChild(img);

      // Add the element to the "overlayLayer" pane.
      const panes = this.getPanes();

      panes.overlayLayer.appendChild(this.div);
    }
    draw() {
      // We use the south-west and north-east
      // coordinates of the overlay to peg it to the correct position and size.
      // To do this, we need to retrieve the projection from the overlay.
      const overlayProjection = this.getProjection();
      // Retrieve the south-west and north-east coordinates of this overlay
      // in LatLngs and convert them to pixel coordinates.
      // We'll use these coordinates to resize the div.
      const sw = overlayProjection.fromLatLngToDivPixel(
        this.bounds.getSouthWest(),
      );
      const ne = overlayProjection.fromLatLngToDivPixel(
        this.bounds.getNorthEast(),
      );

      // Resize the image's div to fit the indicated dimensions.
      if (this.div) {
        this.div.style.left = sw.x + "px";
        this.div.style.top = ne.y + "px";
        this.div.style.width = ne.x - sw.x + "px";
        this.div.style.height = sw.y - ne.y + "px";
      }
    }
    /**
     * The onRemove() method will be called automatically from the API if
     * we ever set the overlay's map property to 'null'.
     */
    onRemove() {
      if (this.div) {
        this.div.parentNode.removeChild(this.div);
        delete this.div;
      }
    }
    /**
     *  Set the visibility to 'hidden' or 'visible'.
     */
    hide() {
      if (this.div) {
        this.div.style.visibility = "hidden";
      }
    }
    show() {
      if (this.div) {
        this.div.style.visibility = "visible";
      }
    }
    toggle() {
      if (this.div) {
        if (this.div.style.visibility === "hidden") {
          this.show();
        } else {
          this.hide();
        }
      }
    }
    toggleDOM(map) {
      if (this.getMap()) {
        this.setMap(null);
      } else {
        this.setMap(map);
      }
    }
  }

  const overlay = new USGSOverlay(bounds, image);

  overlay.setMap(map);

  const toggleButton = document.createElement("button");

  toggleButton.textContent = "Toggle";
  toggleButton.classList.add("custom-map-control-button");

  const toggleDOMButton = document.createElement("button");

  toggleDOMButton.textContent = "Toggle DOM Attachment";
  toggleDOMButton.classList.add("custom-map-control-button");
  toggleButton.addEventListener("click", () => {
    overlay.toggle();
  });
  toggleDOMButton.addEventListener("click", () => {
    overlay.toggleDOM(map);
  });
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleDOMButton);
  map.controls[google.maps.ControlPosition.TOP_RIGHT].push(toggleButton);
}

window.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;
}

.custom-map-control-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;
}
.custom-map-control-button:hover {
  background: rgb(235, 235, 235);
}

HTML

<html>
  <head>
    <title>Showing/Hiding Overlays</title>
    <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>

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

    <!-- 
      The `defer` attribute causes the callback to execute after the full HTML
      document has been parsed. For non-blocking uses, avoiding race conditions,
      and consistent behavior across browsers, consider loading using Promises.
      See https://developers.google.com/maps/documentation/javascript/load-maps-js-api
      for more information.
      -->
    <script
      src="https://maps.googleapis.com/maps/api/js?key=AIzaSyB41DRUbKWJHPxaFjMAwdrzWzbVKartNGg&callback=initMap&v=weekly"
      defer
    ></script>
  </body>
</html>

ลองใช้ตัวอย่าง