במסמך הזה מוסבר על סוגי המפות שאפשר להציג באמצעות Maps JavaScript API. ה-API משתמש באובייקט MapType
כדי לאחסן מידע על המפות האלה. MapType
הוא ממשק שמגדיר את התצוגה והשימוש של משבצות המפה, ואת התרגום של מערכות קואורדינטות מקואורדינטות מסך לקווי אורך ורוחב בעולם (במפה). כל MapType
חייב לכלול כמה שיטות לטיפול באחזור ובשחרור של המשבצות, ומאפיינים שמגדירים את ההתנהגות החזותית שלו.
האופן שבו פועלים סוגי המפות ב-Maps JavaScript API הוא נושא מתקדם. רוב המפתחים יכולים להשתמש ב סוגים הבסיסיים של מפות שמפורטים בהמשך. עם זאת, אפשר גם לשנות את הצגת סוגי המפות הקיימים באמצעות מפות בסגנון או להגדיר משבצות מפה משלכם באמצעות סוגי מפה מותאמים אישית. כשאתם מספקים סוגי מפות בהתאמה אישית, עליכם להבין איך לשנות את מאגר סוגי המפות של המפה.
סוגי מפות בסיסיים
יש ארבעה סוגים של מפות שזמינים בממשק API של JavaScript במפות Google. בנוסף לאריחי מפת הדרכים המוכרים 'המצוירים', ממשק API של JavaScript במפות Google תומך גם בסוגים אחרים של מפות.
סוגי המפות הבאים זמינים בממשק API של JavaScript במפות Google:
roadmap
מציג את תצוגת המפה הראשית כברירת מחדל. זהו סוג המפה שמוגדר כברירת מחדל.satellite
מציג תמונות לוויין של Google Earth.hybrid
מציגה שילוב של תצוגה רגילה ותצוגת לוויין.terrain
מציג מפה פיזית על סמך נתוני פני השטח.
כדי לשנות את סוג המפה שבה Map
משתמש, מגדירים את המאפיין mapTypeId
שלו. אפשר לעשות זאת בתוך ה-constructor על ידי הגדרת האובייקט Map options
שלו, או על ידי קריאה לשיטה setMapTypeId()
של המפה. ערך ברירת המחדל של המאפיין mapTypeID
הוא roadmap
.
הגדרת mapTypeId
במהלך היצירה:
var myLatlng = new google.maps.LatLng(-34.397, 150.644); var mapOptions = { zoom: 8, center: myLatlng, mapTypeId: 'satellite' }; var map = new google.maps.Map(document.getElementById('map'), mapOptions);
שינוי של mapTypeId
באופן דינמי:
map.setMapTypeId('terrain');
שימו לב שלא מגדירים את סוג המפה ישירות, אלא מגדירים את mapTypeId
כך שיפנה ל-MapType
באמצעות מזהה.
כדי לנהל את ההפניות האלה, בממשק API של JavaScript במפות Google נעשה שימוש במרשם של סוגי מפות, כפי שמוסבר בהמשך.
תמונות בזווית של 45°
ב-Maps JavaScript API יש תמיכה בתמונות מיוחדות בזווית של 45° למיקומים מסוימים. התמונות ברזולוציה גבוהה מספקות תצוגות תלת-ממדיות של כל אחד מכיווני המצפן (צפון, דרום, מזרח ומערב). התמונות האלה זמינות ברמות זום גבוהות יותר בסוגי המפות הנתמכים.
בתמונה הבאה מוצגת תצוגה של ניו יורק בפרספקטיבה של 45°:
סוגי המפות satellite
ו-hybrid
תומכים בתמונות בזווית של 45° ברמות זום גבוהות (12 ומעלה), אם הן זמינות. אם המשתמש מגדיל את התצוגה של מיקום שכולל תמונות כאלה, תצוגות המפה האלה משתנות באופן אוטומטי באופן הבא:
- התמונות מהלוויין או מהמיקום המשולב מוחלפות בתמונות עם נקודת מבט של 45°, שמתמקדות במיקום הנוכחי. כברירת מחדל, התצוגות האלה מכוונות לצפון. אם המשתמש מקטין את התצוגה, תמונת הלוויין או התמונה המשולבת שמוגדרות כברירת מחדל מופיעות שוב. ההתנהגות משתנה בהתאם לרמת הזום ולערך של
tilt
: - בין רמות הזום 12 ל-18, מפת הבסיס מלמעלה למטה (0°) מוצגת כברירת מחדל, אלא אם הערך של
tilt
מוגדר כ-45. - ברמות זום של 18 ומעלה, מפת הבסיס בזווית של 45° מוצגת, אלא אם הערך של
tilt
מוגדר כ-0. - אמצעי הבקרה לסיבוב יופיע. באמצעות לחצן הכיוון אפשר להזיז את המכשיר למעלה או למטה, ולסובב את התצוגה ב-90° בכל כיוון. כדי להסתיר את פקדי הסיבוב, מגדירים את
rotateControl
לערךfalse
.
כשמרחיבים את התצוגה מסוג מפה שמוצגת בה תמונה בזווית של 45°, כל השינויים האלה מתבטלים וסוג המפה המקורי מופיע מחדש.
הפעלה והשבתה של תמונות בזווית של 45°
כדי להשבית את התכונה 'תמונות בזווית של 45 מעלות', צריך להפעיל את הפונקציה setTilt(0)
באובייקט Map
. כדי להפעיל תמונות בזווית של 45° בסוגי מפות נתמכים, צריך להתקשר למספר setTilt(45)
. השיטה getTilt()
של Map
תמיד תשקף את tilt
הנוכחי שמוצג במפה. אם מגדירים tilt
במפה ומסירים אותו מאוחר יותר (למשל, על ידי הגדלת התצוגה של המפה), השיטה getTilt()
של המפה תחזיר את הערך 0
.tilt
חשוב: אפשר להשתמש בתמונות בזווית של 45° רק במפות רסטר. אי אפשר להשתמש בתמונות האלה במפות וקטורים.
בדוגמה הבאה מוצגת תצוגה של ניו יורק בזווית של 45°:
TypeScript
function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", } ); map.setTilt(45); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
function initMap() { const map = new google.maps.Map(document.getElementById("map"), { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", }); map.setTilt(45); } window.initMap = initMap;
ניסיון של דוגמה
סיבוב תמונות ב-45°
התמונות בזווית של 45° מורכבות למעשה מאוסף של תמונות לכל אחד מכיווניי המצפן (צפון, דרום, מזרח ומערב). אחרי שהתמונות במפה מוצגות בזווית של 45°, אפשר לכוון את התמונות לאחד מכיווני הספירה הראשיים על ידי קריאה ל-setHeading()
באובייקט Map
, והעברת ערך מספרי שמבוטא בספרות של מעלות מצפון.
בדוגמה הבאה מוצגת מפה אווירית והמפה מסתובבת באופן אוטומטי כל 3 שניות כשלוחצים על הלחצן:
TypeScript
let map: google.maps.Map; function initMap(): void { map = new google.maps.Map(document.getElementById("map") as HTMLElement, { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", heading: 90, tilt: 45, }); // add listener to button document.getElementById("rotate")!.addEventListener("click", autoRotate); } function rotate90(): void { const heading = map.getHeading() || 0; map.setHeading(heading + 90); } function autoRotate(): void { // Determine if we're showing aerial imagery. if (map.getTilt() !== 0) { window.setInterval(rotate90, 3000); } } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
let map; function initMap() { map = new google.maps.Map(document.getElementById("map"), { center: { lat: 40.76, lng: -73.983 }, zoom: 15, mapTypeId: "satellite", heading: 90, tilt: 45, }); // add listener to button document.getElementById("rotate").addEventListener("click", autoRotate); } function rotate90() { const heading = map.getHeading() || 0; map.setHeading(heading + 90); } function autoRotate() { // Determine if we're showing aerial imagery. if (map.getTilt() !== 0) { window.setInterval(rotate90, 3000); } } window.initMap = initMap;
ניסיון של דוגמה
שינוי של מאגר הסוגים של המפות
השדה mapTypeId
במיפוי הוא מזהה מחרוזת שמשמש לשיוך של MapType
לערך ייחודי. לכל אובייקט Map
יש MapTypeRegistry
שמכיל את האוסף של MapType
הזמינים למפה הזו. למשל, הרשומה הזו משמשת לבחירת סוגי המפות שזמינים בבורר MapType של המפה.
לא קוראים ישירות מרישום סוגי המפות. במקום זאת, משנים את הרישום על ידי הוספת סוגי מפות בהתאמה אישית ושיוכים שלהם למזהה מחרוזת לבחירתכם. אי אפשר לשנות את סוגי המפה הבסיסיים (אבל אפשר להסיר אותם מהמפה על ידי שינוי המראה של mapTypeControlOptions
המשויך למפה).
הקוד הבא מגדיר שהמפה תציג רק שני סוגי מפות ב-mapTypeControlOptions
של המפה, ומשנה את הרישום כדי להוסיף את השיוך למזהה הזה להטמעה בפועל של ממשק MapType
.
// Modify the control to only display two maptypes, the // default ROADMAP and the custom 'mymap'. // Note that because this is an association, we // don't need to modify the MapTypeRegistry beforehand. var MY_MAPTYPE_ID = 'mymaps'; var mapOptions = { zoom: 12, center: brooklyn, mapTypeControlOptions: { mapTypeIds: ['roadmap', MY_MAPTYPE_ID] }, mapTypeId: MY_MAPTYPE_ID }; // Create our map. This creation will implicitly create a // map type registry. map = new google.maps.Map(document.getElementById('map'), mapOptions); // Create your custom map type using your own code. // (See below.) var myMapType = new MyMapType(); // Set the registry to associate 'mymap' with the // custom map type we created, and set the map to // show that map type. map.mapTypes.set(MY_MAPTYPE_ID, myMapType);
מפות מסוגננות
בעזרת StyledMapType
אפשר להתאים אישית את הצגת המפות הבסיסיות הרגילות של Google, ולשנות את התצוגה החזותית של רכיבים כמו כבישים, פארקים ואזורים בנויים, כך שישקפו סגנון שונה מזה שמופיע בסוג המפה שמוגדר כברירת מחדל.
למידע נוסף על StyledMapType
, ראו שימוש בהצהרות סגנון מוטמעות של JSON.
סוגי מפות בהתאמה אישית
Maps JavaScript API תומך בתצוגה ובניהול של סוגים מותאמים אישית של מפות, ומאפשר להטמיע תמונות מפה או שכבות-על של משבצות משלכם.
יש כמה הטמעות אפשריות של סוגים של מפות ב-Maps JavaScript API:
- קבוצות של משבצות רגילות, המורכבות מתמונות שמרכיבות יחד מפות קרטוגרפיות מלאות. קבוצות האריחים האלה נקראות גם סוגים של מפות בסיס. סוגי המפות האלה פועלים ומתנהגים כמו סוגי המפות הקיימים שמוגדרים כברירת מחדל:
roadmap
, satellite
,hybrid
ו-terrain
. אפשר להוסיף את סוג המפה המותאם אישית למערךmapTypes
של המפה כדי לאפשר לממשק המשתמש ב-Maps JavaScript API להתייחס לסוג המפה המותאם אישית כסוג מפה רגיל (למשל, על ידי הכללה שלו ברכיב הבקרה MapType). - שכבות-על של משבצות תמונה שמוצגות מעל סוגי מפות בסיס קיימות. בדרך כלל, סוגי המפות האלה משמשים להוספת מידע למפה קיימת, ולרוב הם מוגבלים למיקומים ספציפיים ו/או לרמות זום ספציפיות. שימו לב שאפשר להגדיר את המשבצות האלה כשקופפות, כדי להוסיף תכונות למפות קיימות.
- סוגי מפות שאינם תמונות, שמאפשרים לשנות את הצגת המידע במפה ברמה הבסיסית ביותר.
כל אחת מהאפשרויות האלה מבוססת על יצירת מחלקה שמטמיעה את הממשק MapType
. בנוסף, הכיתה
ImageMapType
מספקת התנהגות מובנית מסוימת כדי לפשט את היצירה של סוגי מפות תמונה.
ממשק MapType
לפני שיוצרים כיתות שמטמיעות את MapType
, חשוב להבין איך מפות Google קובעות את הקואורדינטות ומחליטות אילו חלקים של המפה להציג. צריך להטמיע לוגיקה דומה לכל סוגי המפות הבסיסיות או המפות שכבת-העל.
מומלץ לקרוא את המדריך בנושא קואורדינטות של מפה ושל משבצת.
סוגים של מפות בהתאמה אישית חייבים להטמיע את הממשק MapType
. בממשק הזה מצוינים מאפיינים ושיטות מסוימים שמאפשרים ל-API להתחיל בקשות לסוגי המפה שלכם כשה-API קובע שהוא צריך להציג משבצות מפה בתוך אזור התצוגה הנוכחי וברמת הזום הנוכחית. אתם מטפלים בבקשות האלה כדי לקבוע איזה משבצת לטעון.
הערה: אפשר ליצור מחלקה משלכם כדי להטמיע את הממשק הזה. לחלופין, אם יש לכם תמונות תואמות, תוכלו להשתמש במחלקה
ImageMapType
שכבר מטמיעה את הממשק הזה.
כדי להטמיע את הממשק MapType
בכיתות, צריך להגדיר ולאכלס את המאפיינים הבאים:
tileSize
(חובה) מציין את גודל המשבצת (מסוגgoogle.maps.Size
). הגדלים חייבים להיות מלבניים, אבל הם לא חייבים להיות ריבועיים.maxZoom
(חובה) מציין את רמת הזום המקסימלית שבה יוצגו משבצות של סוג המפה הזה.minZoom
(אופציונלי) מציין את רמת הזום המינימלית שבה מוצגת משבצת של סוג המפה הזה. ערך ברירת המחדל של השדה הזה הוא0
, שמציין שאין רמת זום מינימלית.name
(אופציונלי) מציין את השם של סוג המפה. צריך להגדיר את המאפיין הזה רק אם רוצים שאפשר יהיה לבחור את סוג המפה הזה באמצעות אמצעי בקרה של MapType. ( אפשרויות בקרה)alt
(אופציונלי) מציין את הטקסט החלופי לסוג המפה הזה, שיוצג כטקסט מרחף. צריך להגדיר את המאפיין הזה רק אם רוצים שאפשר יהיה לבחור את סוג המפה הזה באמצעות אמצעי בקרה של MapType. (לעיון באפשרויות הבקרה)
בנוסף, מחלקות שמטמיעות את הממשק MapType
צריכות להטמיע את השיטות הבאות:
-
getTile()
(חובה) נקראת בכל פעם שה-API קובע שצריך להציג במפה משבצות חדשות עבור אזור התצוגה הנתון. לשיטהgetTile()
צריכה להיות החתימה הבאה:getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Node
ה-API קובע אם צריך להפעיל את
getTile()
על סמך המאפייניםtileSize
,minZoom
ו-maxZoom
שלMapType
ורמת הזום והתצוגה הנוכחית של המפה. הטיפולן של השיטה הזו צריך להחזיר אלמנט HTML לפי קואורדינטה, רמת זום ואלמנט DOM שדרכם מצרפים את תמונת הפסיפס. -
releaseTile()
(אופציונלי) נקראת בכל פעם שה-API קובע שצריך להסיר משבצת מהמפה כי היא לא מוצגת. לחתימה של השיטה הזו צריך להיות הפורמט הבא:releaseTile(tile:Node)
בדרך כלל צריך להסיר את כל הרכיבים שצורפו לאריחי המפה כשהוספו למפה. לדוגמה, אם צירפתם מאזינים לאירועים לשכבות-על של משבצות מפה, עליכם להסיר אותם כאן.
השיטה getTile()
משמשת כבקר הראשי לקביעת האריחים שצריך לטעון באזור תצוגה נתון.
סוגי מפות בסיסיות
סוגי המפות שיוצרים באופן הזה יכולים לעמוד בפני עצמם או לשלב אותם עם סוגי מפות אחרים כשכבות-על. סוגי המפות העצמאיים נקראים סוגי מפות בסיס. יכול להיות שתרצו שה-API יטפל ב-MapType
בהתאמה אישית כפי שהוא מטפל בכל סוג אחר של מפת בסיס קיימת (ROADMAP
, TERRAIN
וכו'). לשם כך, מוסיפים את MapType
המותאם אישית למאפיין mapTypes
של Map
. המאפיין הזה הוא מסוג MapTypeRegistry
.
הקוד הבא יוצר בסיס MapType
כדי להציג את קואורדינטות המשבצות של המפה, ומצייר קו מתאר של המשבצות:
TypeScript
/* * This demo demonstrates how to replace default map tiles with custom imagery. * In this case, the CoordMapType displays gray tiles annotated with the tile * coordinates. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize: google.maps.Size; maxZoom = 19; name = "Tile #s"; alt = "Tile Coordinate Map Type"; constructor(tileSize: google.maps.Size) { this.tileSize = tileSize; } getTile( coord: google.maps.Point, zoom: number, ownerDocument: Document ): HTMLElement { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; div.style.backgroundColor = "#E5E3DF"; return div; } releaseTile(tile: HTMLElement): void {} } function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 10, center: { lat: 41.85, lng: -87.65 }, streetViewControl: false, mapTypeId: "coordinate", mapTypeControlOptions: { mapTypeIds: ["coordinate", "roadmap"], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, }, } ); map.addListener("maptypeid_changed", () => { const showStreetViewControl = (map.getMapTypeId() as string) !== "coordinate"; map.setOptions({ streetViewControl: showStreetViewControl, }); }); // Now attach the coordinate map type to the map's registry. map.mapTypes.set( "coordinate", new CoordMapType(new google.maps.Size(256, 256)) ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * This demo demonstrates how to replace default map tiles with custom imagery. * In this case, the CoordMapType displays gray tiles annotated with the tile * coordinates. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize; maxZoom = 19; name = "Tile #s"; alt = "Tile Coordinate Map Type"; constructor(tileSize) { this.tileSize = tileSize; } getTile(coord, zoom, ownerDocument) { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; div.style.backgroundColor = "#E5E3DF"; return div; } releaseTile(tile) {} } function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: { lat: 41.85, lng: -87.65 }, streetViewControl: false, mapTypeId: "coordinate", mapTypeControlOptions: { mapTypeIds: ["coordinate", "roadmap"], style: google.maps.MapTypeControlStyle.DROPDOWN_MENU, }, }); map.addListener("maptypeid_changed", () => { const showStreetViewControl = map.getMapTypeId() !== "coordinate"; map.setOptions({ streetViewControl: showStreetViewControl, }); }); // Now attach the coordinate map type to the map's registry. map.mapTypes.set( "coordinate", new CoordMapType(new google.maps.Size(256, 256)), ); } window.initMap = initMap;
ניסיון של דוגמה
סוגי מפות שכבת-על
חלק מסוגי המפות מיועדים לפעול מעל סוגי מפות קיימים. לסוגים כאלה של מפות יכולות להיות שכבות שקופות שמציינות נקודות עניין או מציגות נתונים נוספים למשתמש.
במקרים כאלה, לא רוצים שהמערכת תתייחס לסוג המפה כישות נפרדת, אלא כשכבה-על.
כדי לעשות זאת, מוסיפים את סוג המפה ל-MapType
קיים ישירות באמצעות המאפיין overlayMapTypes
של Map
. המאפיין הזה מכיל MVCArray
של MapType
. כל סוגי המפות (בסיסיות ועליונות) מוצגות בשכבה mapPane
. סוגי המפות של שכבות-העל יוצגו מעל למפה הבסיסית שאליה הן מצורפות, בסדר שבו הן מופיעות במערך Map.overlayMapTypes
(שכבות-על עם ערכי אינדקס גבוהים יותר יוצגו לפני שכבות-על עם ערכי אינדקס נמוכים יותר).
הדוגמה הבאה זהה לדוגמה הקודמת, אלא שיצרנו שכבת-על של משבצות MapType
מעל סוג המפה ROADMAP
:
TypeScript
/* * This demo illustrates the coordinate system used to display map tiles in the * API. * * Tiles in Google Maps are numbered from the same origin as that for * pixels. For Google's implementation of the Mercator projection, the origin * tile is always at the northwest corner of the map, with x values increasing * from west to east and y values increasing from north to south. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType implements google.maps.MapType { tileSize: google.maps.Size; alt: string|null = null; maxZoom: number = 17; minZoom: number = 0; name: string|null = null; projection: google.maps.Projection|null = null; radius: number = 6378137; constructor(tileSize: google.maps.Size) { this.tileSize = tileSize; } getTile( coord: google.maps.Point, zoom: number, ownerDocument: Document ): HTMLElement { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; return div; } releaseTile(tile: Element): void {} } function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 10, center: { lat: 41.85, lng: -87.65 }, } ); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. const coordMapType = new CoordMapType(new google.maps.Size(256, 256)) map.overlayMapTypes.insertAt( 0, coordMapType ); } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
/* * This demo illustrates the coordinate system used to display map tiles in the * API. * * Tiles in Google Maps are numbered from the same origin as that for * pixels. For Google's implementation of the Mercator projection, the origin * tile is always at the northwest corner of the map, with x values increasing * from west to east and y values increasing from north to south. * * Try panning and zooming the map to see how the coordinates change. */ class CoordMapType { tileSize; alt = null; maxZoom = 17; minZoom = 0; name = null; projection = null; radius = 6378137; constructor(tileSize) { this.tileSize = tileSize; } getTile(coord, zoom, ownerDocument) { const div = ownerDocument.createElement("div"); div.innerHTML = String(coord); div.style.width = this.tileSize.width + "px"; div.style.height = this.tileSize.height + "px"; div.style.fontSize = "10"; div.style.borderStyle = "solid"; div.style.borderWidth = "1px"; div.style.borderColor = "#AAAAAA"; return div; } releaseTile(tile) {} } function initMap() { const map = new google.maps.Map(document.getElementById("map"), { zoom: 10, center: { lat: 41.85, lng: -87.65 }, }); // Insert this overlay map type as the first overlay map type at // position 0. Note that all overlay map types appear on top of // their parent base map. const coordMapType = new CoordMapType(new google.maps.Size(256, 256)); map.overlayMapTypes.insertAt(0, coordMapType); } window.initMap = initMap;
ניסיון של דוגמה
סוגי מפות תמונה
הטמעת MapType
כסוג של מפה בסיסית יכולה להיות משימה ממושכת וקשה. ה-API מספק סיווג מיוחד שמטמיע את הממשק MapType
לסוגי המפות הנפוצים ביותר: סוגי מפות שמכילים משבצות שמתבססות על קובצי תמונה בודדים.
הכיתה הזו, הכיתה ImageMapType
, נוצרת באמצעות מפרט של אובייקט ImageMapTypeOptions
שמגדיר את המאפיינים הנדרשים הבאים:
tileSize
(חובה) מציין את גודל המשבצת (מסוגgoogle.maps.Size
). הגדלים חייבים להיות מלבניים, אבל הם לא חייבים להיות ריבועיים.getTileUrl
(חובה) מציין את הפונקציה, שבדרך כלל ניתנת כפונקציה לינרית, שמטפלת בבחירת המשבצת המתאימה של התמונה על סמך רמת הזום והקואורדינטות בעולם שסופקו.
הקוד הבא מיישם ImageMapType
בסיסי באמצעות המשבצות של Google Moon. בדוגמה הזו נעשה שימוש בפונקציית נורמליזציה כדי לוודא שהמשבצות חוזרות על עצמן בציר x, אבל לא בציר y של המפה.
TypeScript
function initMap(): void { const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { center: { lat: 0, lng: 0 }, zoom: 1, streetViewControl: false, mapTypeControlOptions: { mapTypeIds: ["moon"], }, } ); const moonMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom): string { const normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return ""; } const bound = Math.pow(2, zoom); return ( "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" + "/" + zoom + "/" + normalizedCoord.x + "/" + (bound - normalizedCoord.y - 1) + ".jpg" ); }, tileSize: new google.maps.Size(256, 256), maxZoom: 9, minZoom: 0, // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions' radius: 1738000, name: "Moon", }); map.mapTypes.set("moon", moonMapType); map.setMapTypeId("moon"); } // Normalizes the coords that tiles repeat across the x axis (horizontally) // like the standard Google map tiles. function getNormalizedCoord(coord, zoom) { const y = coord.y; let x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc const tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = ((x % tileRange) + tileRange) % tileRange; } return { x: x, y: y }; } declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
function initMap() { const map = new google.maps.Map(document.getElementById("map"), { center: { lat: 0, lng: 0 }, zoom: 1, streetViewControl: false, mapTypeControlOptions: { mapTypeIds: ["moon"], }, }); const moonMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { const normalizedCoord = getNormalizedCoord(coord, zoom); if (!normalizedCoord) { return ""; } const bound = Math.pow(2, zoom); return ( "https://mw1.google.com/mw-planetary/lunar/lunarmaps_v1/clem_bw" + "/" + zoom + "/" + normalizedCoord.x + "/" + (bound - normalizedCoord.y - 1) + ".jpg" ); }, tileSize: new google.maps.Size(256, 256), maxZoom: 9, minZoom: 0, // @ts-ignore TODO 'radius' does not exist in type 'ImageMapTypeOptions' radius: 1738000, name: "Moon", }); map.mapTypes.set("moon", moonMapType); map.setMapTypeId("moon"); } // Normalizes the coords that tiles repeat across the x axis (horizontally) // like the standard Google map tiles. function getNormalizedCoord(coord, zoom) { const y = coord.y; let x = coord.x; // tile range in one direction range is dependent on zoom level // 0 = 1 tile, 1 = 2 tiles, 2 = 4 tiles, 3 = 8 tiles, etc const tileRange = 1 << zoom; // don't repeat across y-axis (vertically) if (y < 0 || y >= tileRange) { return null; } // repeat across x-axis if (x < 0 || x >= tileRange) { x = ((x % tileRange) + tileRange) % tileRange; } return { x: x, y: y }; } window.initMap = initMap;
ניסיון של דוגמה
תחזיות
כדור הארץ הוא כדור תלת-ממדי (בערך), ואילו מפה היא משטח דו-ממדי שטוח. המפה שמוצגת ב-Maps JavaScript API, כמו כל מפה שטוחה של כדור הארץ, היא הקרנה של הכדור הזה על משטח שטוח. במילים פשוטות, אפשר להגדיר הקרנה כמיפוי של ערכי קו רוחב/אורך לקואורדינטות במפה של ההקרנה.
תצוגות פרויקציה ב-Maps JavaScript API חייבות ליישם את הממשק Projection
. הטמעה של Projection
חייבת לספק לא רק מיפוי ממערכת קואורדינטות אחת למערכת אחרת, אלא מיפוי דו-כיווני. כלומר, צריך להגדיר איך לתרגם מקואורדינטות של כדור הארץ (אובייקטים מסוג LatLng
) למערכת הקואורדינטות הגלובליות של הכיתה Projection
, וממערכת הקואורדינטות הגלובליות חזרה לקווי הרוחב והאורך של כדור הארץ.
במפות Google נעשה שימוש בתצוגה פרויקטיבית של Mercator כדי ליצור את המפות מנתונים גיאוגרפיים ולהמיר אירועים במפה לקואורדינטות גיאוגרפיות. אפשר לקבל את ההצגה הזו על ידי קריאה ל-getProjection()
על Map
(או על כל אחד מסוגי הבסיס הרגילים MapType
). ברוב השימושים, Projection
הסטנדרטי יספיק, אבל אפשר גם להגדיר תחזיות מותאמות אישית משלכם ולהשתמש בהן.
הטמעת תחזית
כשמטמיעים הקרנה בהתאמה אישית, צריך להגדיר כמה דברים:
- הנוסחאות למיפוי קואורדינטות של קווי רוחב ואורך למישן קרטזי, והנוסחאות התואמות למיפוי ממישן קרטזי לקווי רוחב ואורך. (ממשק
Projection
תומך רק בהמרות לקווי קואורדינטות ישרים). - גודל המשבצת הבסיסית. כל המשבצות צריכות להיות מלבניות.
- 'גודל העולם' של מפה באמצעות המשבצת הבסיסית שמוגדרת ברמת התצוגה 0. שימו לב שבמפות שמכילות אריח אחד ברמת התצוגה 0, גודל העולם זהה לגודל של אריח הבסיס.
טרנספורמציות של קואורדינטות בתחזיות
לכל הקרנה יש שתי שיטות לתרגום בין שתי מערכות הקואורדינטות האלה, שמאפשרות להמיר בין קואורדינטות גיאוגרפיות לבין קואורדינטות גלובאליות:
- השיטה
Projection.fromLatLngToPoint()
ממירה ערךLatLng
לקואורדינטה גלובלית. השיטה הזו משמשת למיקום שכבות-על במפה (ולמיקום המפה עצמה). - השיטה
Projection.fromPointToLatLng()
ממירה קואורדינטה של העולם לערךLatLng
. השיטה הזו משמשת להמרת אירועים כמו קליקים שמתרחשים במפה לקואורדינטות גאוגרפיות.
במפות Google, ההנחה היא שהתצוגות הן ישרות.
באופן כללי, אפשר להשתמש בתצוגה פרויקטיבית בשני מקרים: כדי ליצור מפה של העולם או כדי ליצור מפה של אזור מקומי. במקרה הראשון, צריך לוודא שהמישור גם ישר ותקין בכל קוי האורך. ייתכן שחלק מהמיפויים (במיוחד מיפויים חרוטיים) יהיו "רגילים באופן מקומי" (כלומר, יפנו צפונה) אבל יחרגו מצפון האמיתי. לדוגמה, ככל שהמפה ממוקמת רחוק יותר ביחס לקו האורך של נקודת ייחוס מסוימת. אפשר להשתמש בתצוגה כזו באופן מקומי, אבל חשוב לזכור שהיא תמיד לא מדויקת וששגיאות הטרנספורמציה יהיו ברורות יותר ככל שתתרחקו ממיקום האורך של נקודת העזר.
בחירת משבצות מפה בתצוגות 'תחזיות'
הקרנות הן שימושיות לא רק לקביעת המיקומים של מיקומים או שכבות-על, אלא גם למיקום של משבצות המפה עצמן.
ממשק ה-API של JavaScript במפות Google יוצר תצוגה של מפות בסיס באמצעות ממשק MapType
, שבו צריך להצהיר על מאפיין projection
לזיהוי הקרנה של המפה ועל שיטת getTile()
לאחזור משבצות מפה על סמך ערכי קואורדינטות של משבצות. קואורדינטות האריחים מבוססות גם על גודל האריחים הבסיסי (שחייב להיות מלבני) וגם על 'גודל העולם' של המפה, שהוא גודל העולם במפה בפיקסלים ברמת הזום 0. (במפות שמכילות משבצת אחת ברמת התצוגה 0, גודל המשבצת זהה לגודל העולם).
מגדירים את גודל המשבצת הבסיסית במאפיין tileSize
של MapType
. מגדירים את גודל העולם באופן משתמע בתוך השיטות fromLatLngToPoint()
ו-fromPointToLatLng()
של התצוגה.
מאחר שבחירת התמונה תלויה בערכים המועברים האלה, מומלץ לתת שמות לתמונות שאפשר לבחור באופן פרוגרמטי על סמך הערכים המועברים האלה, כמו map_zoom_tileX_tileY.png
.
בדוגמה הבאה מוגדר ImageMapType
באמצעות הקרנה של
Gall-Peters:
TypeScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection function initMap(): void { // Create a map. Use the Gall-Peters map type. const map = new google.maps.Map( document.getElementById("map") as HTMLElement, { zoom: 0, center: { lat: 0, lng: 0 }, mapTypeControl: false, } ); initGallPeters(); map.mapTypes.set("gallPeters", gallPetersMapType); map.setMapTypeId("gallPeters"); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById("coords") as HTMLElement; map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv); map.addListener("mousemove", (event: google.maps.MapMouseEvent) => { coordsDiv.textContent = "lat: " + Math.round(event.latLng!.lat()) + ", " + "lng: " + Math.round(event.latLng!.lng()); }); // Add some markers to the map. map.data.setStyle((feature) => { return { title: feature.getProperty("name") as string, optimized: false, }; }); map.data.addGeoJson(cities); } let gallPetersMapType; function initGallPeters() { const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. gallPetersMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { const scale = 1 << zoom; // Wrap tiles horizontally. const x = ((coord.x % scale) + scale) % scale; // Don't wrap tiles vertically. const y = coord.y; if (y < 0 || y >= scale) return ""; return ( "https://developers.google.com/maps/documentation/" + "javascript/examples/full/images/gall-peters_" + zoom + "_" + x + "_" + y + ".png" ); }, tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y), minZoom: 0, maxZoom: 1, name: "Gall-Peters", }); // Describe the Gall-Peters projection used by these tiles. gallPetersMapType.projection = { fromLatLngToPoint: function (latLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new google.maps.Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)) ); }, fromPointToLatLng: function (point, noWrap) { const x = point.x / GALL_PETERS_RANGE_X; const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y)); return new google.maps.LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap ); }, }; } // GeoJSON, describing the locations and names of some cities. const cities = { type: "FeatureCollection", features: [ { type: "Feature", geometry: { type: "Point", coordinates: [-87.65, 41.85] }, properties: { name: "Chicago" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-149.9, 61.218] }, properties: { name: "Anchorage" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-99.127, 19.427] }, properties: { name: "Mexico City" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-0.126, 51.5] }, properties: { name: "London" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [28.045, -26.201] }, properties: { name: "Johannesburg" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [15.322, -4.325] }, properties: { name: "Kinshasa" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [151.207, -33.867] }, properties: { name: "Sydney" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [0, 0] }, properties: { name: "0°N 0°E" }, }, ], }; declare global { interface Window { initMap: () => void; } } window.initMap = initMap;
JavaScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection function initMap() { // Create a map. Use the Gall-Peters map type. const map = new google.maps.Map(document.getElementById("map"), { zoom: 0, center: { lat: 0, lng: 0 }, mapTypeControl: false, }); initGallPeters(); map.mapTypes.set("gallPeters", gallPetersMapType); map.setMapTypeId("gallPeters"); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById("coords"); map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv); map.addListener("mousemove", (event) => { coordsDiv.textContent = "lat: " + Math.round(event.latLng.lat()) + ", " + "lng: " + Math.round(event.latLng.lng()); }); // Add some markers to the map. map.data.setStyle((feature) => { return { title: feature.getProperty("name"), optimized: false, }; }); map.data.addGeoJson(cities); } let gallPetersMapType; function initGallPeters() { const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. gallPetersMapType = new google.maps.ImageMapType({ getTileUrl: function (coord, zoom) { const scale = 1 << zoom; // Wrap tiles horizontally. const x = ((coord.x % scale) + scale) % scale; // Don't wrap tiles vertically. const y = coord.y; if (y < 0 || y >= scale) return ""; return ( "https://developers.google.com/maps/documentation/" + "javascript/examples/full/images/gall-peters_" + zoom + "_" + x + "_" + y + ".png" ); }, tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y), minZoom: 0, maxZoom: 1, name: "Gall-Peters", }); // Describe the Gall-Peters projection used by these tiles. gallPetersMapType.projection = { fromLatLngToPoint: function (latLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new google.maps.Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)), ); }, fromPointToLatLng: function (point, noWrap) { const x = point.x / GALL_PETERS_RANGE_X; const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y)); return new google.maps.LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap, ); }, }; } // GeoJSON, describing the locations and names of some cities. const cities = { type: "FeatureCollection", features: [ { type: "Feature", geometry: { type: "Point", coordinates: [-87.65, 41.85] }, properties: { name: "Chicago" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-149.9, 61.218] }, properties: { name: "Anchorage" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-99.127, 19.427] }, properties: { name: "Mexico City" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [-0.126, 51.5] }, properties: { name: "London" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [28.045, -26.201] }, properties: { name: "Johannesburg" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [15.322, -4.325] }, properties: { name: "Kinshasa" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [151.207, -33.867] }, properties: { name: "Sydney" }, }, { type: "Feature", geometry: { type: "Point", coordinates: [0, 0] }, properties: { name: "0°N 0°E" }, }, ], }; window.initMap = initMap;