مقدمة
التراكبات هي عناصر على الخريطة مرتبطة بإحداثيات خطوط الطول والعرض، لذا تتحرك عند سحب الخريطة أو تكبيرها أو تصغيرها. للحصول على معلومات عن أنواع التراكبات المحددة مسبقًا ، يُرجى الاطّلاع على مقالة الرسم على الخريطة.
توفر 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; }
لا يمكننا بعد إرفاق هذا التراكب بالخريطة في دالة إنشاء التراكب. أولاً، علينا التأكّد من توفّر جميع لوحات الخريطة، لأنّها تحدّد ترتيب عرض الكائنات على الخريطة. توفّر واجهة برمجة التطبيقات طريقة مساعدة تشير إلى حدوث ذلك. سنتناول هذه الطريقة في القسم التالي.
تهيئة التراكب
عند إنشاء التراكب لأول مرة وجعله جاهزًا للعرض، علينا إرفاقه بالخريطة من خلال نموذج العناصر في المستند (DOM) للمتصفح. تشير واجهة برمجة التطبيقات إلى أنّه تمّت إضافة التراكب إلى الخريطة من خلال استدعاء طريقة onAdd() للتراكب. للتعامل مع هذه
الطريقة، ننشئ عنصر <div> لعرض الصورة، ونضيف عنصر <img>، ونرفقه
بعنصر <div>، ثم نرفق التراكب بإحدى لوحات الخريطة. اللوحة هي عقدة ضمن شجرة نموذج العناصر في المستند.
تحدّد اللوحات، من النوع
MapPanes، ترتيب التراص للطبقات المختلفة على الخريطة. تتوفّر اللوحات التالية، ويتم تعدادها بالترتيب الذي يتم به تراصها من الأسفل إلى الأعلى:
mapPaneهي اللوحة الأدنى وتقع فوق المربّعات. قد لا تتلقّى أحداث نموذج العناصر في المستند. (اللوحة 0).overlayLayerتحتوي على الخطوط المتعددة والأشكال المضلّعة والتراكبات الأرضية وتراكبات طبقة المربّعات. قد لا تتلقّى أحداث نموذج العناصر في المستند. (اللوحة 1).markerLayerتحتوي على العلامات. قد لا تتلقّى أحداث نموذج العناصر في المستند. (اللوحة 2).overlayMouseTargetتحتوي على العناصر التي تتلقّى أحداث نموذج العناصر في المستند. (اللوحة 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) للخريطة، على الرغم من أنّ هذه العملية أكثر تكلفة قليلاً. يُرجى العِلم أنّه إذا أعدت إرفاق التراكب بنموذج العناصر في المستند للخريطة، سيتم استدعاء طريقة 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>