บทนำ
การวางซ้อนคือออบเจ็กต์บนแผนที่ที่เชื่อมโยงกับพิกัดละติจูด/ลองจิจูด จึงเคลื่อนที่เมื่อคุณลากหรือซูมแผนที่ ดูข้อมูลเกี่ยวกับประเภทการวางซ้อนที่กำหนดไว้ล่วงหน้า ได้ที่ การวาดบนแผนที่
Maps JavaScript API มีคลาส
OverlayView สำหรับ
สร้างการวางซ้อนที่กำหนดเอง OverlayView เป็นคลาสพื้นฐานที่มีเมธอดหลายรายการที่คุณต้องใช้เมื่อสร้างการวางซ้อน นอกจากนี้ คลาสยังมีเมธอด 2-3 รายการที่ช่วยให้คุณแปลพิกัดหน้าจอเป็นสถานที่บนแผนที่ได้
เพิ่มการวางซ้อนที่กำหนดเอง
ต่อไปนี้เป็นสรุปขั้นตอนที่ต้องใช้ในการสร้างการวางซ้อนที่กำหนดเอง
- ตั้งค่า
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 (บานหน้าต่าง 0)overlayLayerมีเส้นหลายเส้น รูปหลายเหลี่ยม การวางซ้อนบนพื้น และการวางซ้อนเลเยอร์ไทล์ ซึ่งอาจไม่ได้รับเหตุการณ์ DOM (บานหน้าต่าง 1)markerLayerมีมาร์กเกอร์ ซึ่งอาจไม่ได้รับเหตุการณ์ DOM (บานหน้าต่าง 2)overlayMouseTargetมีองค์ประกอบที่ได้รับเหตุการณ์ DOM (บานหน้าต่าง 3)floatPaneมีหน้าต่างข้อมูล ซึ่งอยู่เหนือการวางซ้อนทั้งหมดของแผนที่ (บานหน้าต่าง 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>
<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 script 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>