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