סוגי מפות

בחירת פלטפורמה: Android iOS JavaScript

במסמך הזה מפורט על סוגי המפות שאפשר להציג באמצעות API של JavaScript של מפות Google. ה-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.

חשוב: תמונות ב-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 קובע שצריך להציג במפה משבצות חדשות עבור אזור התצוגה הנתון. ה-method getTile() חייב לכלול את החתימה הבאה:

    getTile(tileCoord:Point,zoom:number,ownerDocument:Document):Node

    ה-API קובע אם צריך להפעיל את getTile() על סמך המאפיינים tileSize, minZoom ו-maxZoom של MapType ורמת הזום והתצוגה הנוכחית של המפה. הטיפולן של השיטה הזו צריך להחזיר אלמנט HTML לפי קואורדינטה, רמת זום ואלמנט DOM שדרכם מצרפים את תמונת הפסיפס.

  • releaseTile() (אופציונלי) נקראת בכל פעם שה-API קובע שצריך להסיר משבצת מהמפה כי היא לא מוצגת. השיטה הזו חייבת לכלול את החתימה הבאה:

    releaseTile(tile:Node)

    בדרך כלל צריך להסיר את כל הרכיבים שצורפו לאריחי המפה כשהוספו למפה. לדוגמה, אם צירפת פונקציות event listener לשכבות-על של משבצות מפה, עליך להסיר אותן כאן.

ה-method 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 ליצירת מפות הירח. בדוגמה הזו נעשה שימוש בפונקציית נורמליזציה כדי לוודא שהמשבצות חוזרות על עצמן בציר 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, כמו כל מפה שטוחה של כדור הארץ, היא הקרנה של הכדור הזה על משטח שטוח. במילים פשוטות, אפשר להגדיר הקרנה כמיפוי של ערכי קו הרוחב/קו האורך לקואורדינטות במפה של ההקרנה.

התחזיות ב-API JavaScript של מפות Google חייבות להטמיע את הממשק Projection. הטמעה של Projection חייבת לספק לא רק מיפוי ממערכת קואורדינטות אחת לאחרת, אלא גם מיפוי דו-כיווני. כלומר צריך להגדיר איך לתרגם מקואורדינטות של Earth (אובייקטים מסוג 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;
להצגת דוגמה

ניסיון של דוגמה