المقدّمة
التراكبات عبارة عن كائنات على الخريطة مرتبطة بإحداثيات خطوط الطول/العرض، لذلك تتحرك عند سحب الخريطة أو تكبيرها/تصغيرها. للحصول على معلومات حول أنواع التراكب المحددة مسبقًا، راجع الرسم على الخريطة.
توفر واجهة برمجة تطبيقات JavaScript للخرائط فئة
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; }
لا يمكننا حتى الآن إرفاق هذا التراكب بالخريطة في الدالة الإنشائية للتراكب. أولاً، نحتاج إلى التأكد من توفر جميع أجزاء الخريطة، لأنها تحدد الترتيب الذي تظهر به الكائنات على الخريطة. توفر واجهة برمجة التطبيقات طريقة مساعدة تشير إلى حدوث ذلك. سنتعامل مع هذه الطريقة في القسم التالي.
تهيئة التراكب
عندما يتم إنشاء مثيل للتراكب لأول مرة ويكون جاهزًا للعرض، نحتاج إلى إرفاقه بالخريطة عبر نموذج كائن المستند (DOM) للمتصفح. تشير واجهة برمجة التطبيقات إلى أنه تمت إضافة التراكب إلى الخريطة من خلال استدعاء طريقة 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); }
رسم التراكب
تجدر الإشارة إلى أنّنا لم تستدعي أي عرض مرئي خاص في الرمز الوارد أعلاه. تستدعي واجهة برمجة التطبيقات طريقة 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>