סוגי מפות

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

במסמך הזה מפורט על סוגי המפות שאפשר להציג באמצעות API של JavaScript של מפות Google. ה-API משתמש באובייקט MapType כדי לשמור מידע על המפות האלה. MapType הוא ממשק שמגדיר את התצוגה של קטעי המפה והשימוש בהם ואת התרגום של מערכות הקואורדינטות מקואורדינטות במסך לקואורדינטות עולם (במפה). כל MapType צריך לכלול כמה שיטות לטיפול באחזור ובשחרור של משבצות, ומאפיינים שמגדירים את ההתנהגות החזותית שלו.

התהליך הפנימי של סוגי מפות ב-API של JavaScript של מפות Google הוא נושא מתקדם. רוב המפתחים יכולים להשתמש ב סוגי המפות הבסיסיים שמפורטים בהמשך. עם זאת, תוכל גם לשנות את ההצגה של סוגי מפות קיימים באמצעות מפות סגנונות או להגדיר קטעי מפה משלך באמצעות סוגי מפות מותאמים אישית. כשמספקים סוגי מפות מותאמים אישית, צריך להבין איך לשנות את מרשם סוגי המפה של המפה.

סוגי מפה בסיסיים

קיימים ארבעה סוגי מפות הזמינים ב-Maps JavaScript API. בנוסף לקטעי המפה ה "צבועים" המוכרים של מפת הדרכים, JavaScript API של מפות Google תומך גם בסוגי מפות אחרים.

סוגי המפות הבאים זמינים ב-Maps JavaScript API:

  • roadmap מציג את תצוגת ברירת המחדל של מפת הדרכים. זהו סוג המפה שמוגדר כברירת מחדל.
  • satellite מציג תמונות לוויין של Google Earth.
  • ב-hybrid מוצג שילוב של תצוגות רגילות וצילומי לוויין.
  • terrain מציג מפה פיזית על סמך מידע על פני השטח.

כדי לשנות את סוג המפה שבשימוש על ידי Map, אתם יכולים להגדיר את המאפיין mapTypeId של המפה בתוך ה-constructor, או להגדיר את האובייקט Map options שלו, או לשלוח קריאה ל-method 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°

ה-JavaScript API של מפות Google תומך בתמונות מיוחדות ב-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 במפה ולאחר מכן מסירים את 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, אפשר לעיין במדריך למפות מעוצבות.

סוגי מפה מותאמים אישית

הממשק JavaScript API של מפות Google תומך בהצגה ובניהול של סוגי מפות מותאמים אישית, כדי שתוכלו להטמיע תמונות מפה או שכבות-על של משבצות.

ב-Maps JavaScript API יש כמה הטמעות אפשריות של סוגי מפה:

  • ערכות אריחים רגילות שמכילות תמונות שיחד מהוות מפות קרטוגרפיות מלאות. קבוצות המשבצות האלה נקראות גם סוגי מפות בסיס. סוגי המפות האלה פועלים ומתנהגים כמו סוגי המפות הקיימים שמוגדרים כברירת מחדל: roadmap, satellite, hybrid ו-terrain. תוכלו להוסיף את סוג המפה המותאמת אישית למערך mapTypes של Map כדי לאפשר לממשק המשתמש ב-Maps JavaScript API להתייחס לסוג המפה המותאמת אישית שלכם כסוג מפה סטנדרטי (על ידי הכללתה בפקד MapType, לדוגמה).
  • שכבות-על של אריח תמונה שמוצגות מעל סוגי המפה הבסיסית הקיימים. באופן כללי, סוגי המפה האלה משמשים כדי להרחיב סוג מפה קיים ולהציג מידע נוסף, ולעיתים קרובות הם מוגבלים למיקומים ספציפיים ו/או לרמות מרחק התצוגה. חשוב לזכור שהמשבצות האלה עשויות להיות שקופות, ולאפשר לך להוסיף תכונות למפות קיימות.
  • סוגים של מפות שאינן תמונות, שמאפשרים לך להשפיע על הצגת המידע במפה ברמה הבסיסית ביותר שלו.

כל אחת מהאפשרויות האלה תלויה ביצירת מחלקה שמטמיעה את הממשק של MapType. בנוסף, המחלקה ImageMapType מספקת התנהגות מובנית כדי לפשט את תהליך היצירה של סוגי מפות של תמונות.

הממשק של MapType

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

בסוגי מפות מותאמים אישית חייבים להטמיע את הממשק של MapType. בממשק הזה מצוינים מאפיינים ושיטות מסוימים שמאפשרים ל-API לשלוח בקשות לסוגי המפה שלך כאשר ה-API קובע שהוא צריך להציג קטעי מפה באזור התצוגה וברמת הזום הנוכחית. אתם תטפלו בבקשות האלה כדי להחליט איזה כרטיס מידע לטעון.

הערה: אתם יכולים ליצור מחלקה משלכם כדי להטמיע את הממשק הזה. לחלופין, אם יש לכם תמונות תואמות, אפשר להשתמש במחלקה ImageMapType שכבר מוטמעת בממשק הזה.

במחלקות שמטמיעות את הממשק של MapType צריך להגדיר ולאכלס את המאפיינים הבאים:

  • tileSize (חובה) מציין את גודל המשבצת (מסוג google.maps.Size). המידות צריכות להיות מלבניות, אבל לא חייבות להיות ריבועיות.
  • maxZoom (חובה) מציין את רמת הזום המקסימלית שבה יוצגו המשבצות מסוג המפה הזה.
  • minZoom (אופציונלי) מציין את רמת הזום המינימלית שבה יוצג משבצת מסוג המפה הזה. כברירת מחדל, הערך הזה הוא 0, שמציין שלא קיימת רמת זום מינימלית.
  • name (אופציונלי) מציין את השם של סוג המפה הזה. המאפיין הזה נדרש רק אם רוצים שניתן יהיה לבחור את סוג המפה הזה בפקד MapType. (ראו הוספת פקדים של MapType בהמשך).
  • alt (אופציונלי) מציין את הטקסט החלופי של סוג המפה הזה, שמוצג כטקסט כשמציבים את סמן העכבר. המאפיין הזה נדרש רק אם רוצים שניתן יהיה לבחור את סוג המפה הזה בפקד MapType. (ראו הוספת פקדים של MapType בהמשך).

בנוסף, מחלקות שמטמיעות את הממשק MapType צריכות להטמיע את השיטות הבאות:

  • מתבצעת קריאה אל getTile() (חובה) בכל פעם שה-API קובע שהמפה צריכה להציג משבצות חדשות עבור אזור התצוגה הנתון. ה-method getTile() חייב לכלול את החתימה הבאה:

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

    ה-API קובע אם הוא צריך לקרוא ל-getTile() על סמך המאפיינים tileSize, minZoom ו-maxZoom של MapType ורמת התצוגה והזום הנוכחית של המפה. ה-handler של השיטה הזו צריך להחזיר רכיב 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;
להצגת דוגמה

כדאי לנסות דוגמה

תחזיות

כדור הארץ הוא כדור תלת-ממדי (בקירוב), ומפה היא פני שטח שטוחים ודו-ממדיים. המפה שרואים ב-API JavaScript של מפות Google, כמו כל מפה שטוחה של כדור הארץ, היא היטל של הכדור הזה על משטח ישר. במונחים הפשוטים ביותר, אפשר להגדיר היטל כמיפוי של ערכי קווי אורך ורוחב לקואורדינטות במפה של ההיטל.

החיזויים ב-API JavaScript של מפות Google חייבים להטמיע את הממשק של Projection. הטמעה של Projection חייבת לספק לא רק מיפוי ממערכת קואורדינטות אחת לאחרת, אלא גם מיפוי דו-כיווני. כלומר צריך להגדיר איך לתרגם מקואורדינטות של Earth (אובייקטים מסוג LatLng) למערכת הקואורדינטות בעולם של המחלקה Projection, ולהפך. במפות Google נעשה שימוש בהיטל של Mercator כדי ליצור את המפות שלו מנתונים גיאוגרפיים, ולהמיר אירועים במפה לקואורדינטות גיאוגרפיות. אפשר לקבל את התחזית הזו על ידי קריאה ל-getProjection() ב-Map (או בכל אחד מסוגי הבסיס הסטנדרטי MapType). לרוב השימושים יספיק Projection הרגיל הזה, אבל אפשר גם להגדיר תחזיות בהתאמה אישית ולהשתמש בהן.

יישום תחזית

כשמטמיעים היטל מותאם אישית, צריך להגדיר מספר דברים:

  • הנוסחה למיפוי קואורדינטות של קווי רוחב ואורך למישור קרטזי ולהפך. (הממשק Projection תומך רק בטרנספורמציות לקואורדינטות ישר).
  • גודל אריח הבסיס. כל המשבצות חייבות להיות מלבניות.
  • 'גודל העולם' של מפה באמצעות משבצת הבסיס שמוגדרת ברמת הזום 0. חשוב לשים לב שלמפות שמורכבות ממשבצת אחת בזום 0, גודל העולם וגודל אריח הבסיס זהים.

תיאום טרנספורמציות בתחזיות

כל היטל מספק שתי שיטות שמתורגמות בין שתי מערכות הקואורדינטות האלה, וכך אפשר להמיר בין קואורדינטות גיאוגרפיות וקואורדינטות עולמיות:

  • ה-method Projection.fromLatLngToPoint() ממירה ערך LatLng לקואורדינטה עולמית. השיטה הזו משמשת למיקום של שכבות-על במפה (ולמיקום המפה עצמה).
  • ה-method Projection.fromPointToLatLng() ממירה קואורדינטות עולמיות לערך LatLng. השיטה הזו משמשת כדי להמיר אירועים כמו קליקים שמתרחשים במפה לקואורדינטות גיאוגרפיות.

ההנחה במפות Google היא שהתחזיות הן ליניאריות.

באופן כללי, אפשר להשתמש בהיטל לשני מקרים: כדי ליצור מפת העולם או כדי ליצור מפה של אזור מקומי. במקרה הקודם, צריך לוודא שההיטל הוא גם ישר ורגיל בכל קווי האורך. תחזיות מסוימות (במיוחד תחזיות חרוטות) עשויות להיות "נורמליות באופן מקומי" (כלומר, הכיוון הצפוני) אבל סטיות מהצפון האמיתי. לדוגמה, ככל שהמפה ממוקמת רחוק יותר ביחס לקו אורך מסוים להתייחסות. אפשר להשתמש בהיטל כזה באופן מקומי, אבל חשוב לזכור שההיטל הוא בהכרח לא מדויק, וככל הנראה שגיאות הטרנספורמציה יתרחקו ככל שקו האורך בהתייחסות לסטייה רחוק יותר.

בחירת אריחי מפה בהקרנות

ההיטלים שימושיים לא רק לקביעת המיקומים של מיקומים או שכבות-על, אלא גם לצורך מיקום אריחי המפה עצמם. ה-API של JavaScript של מפות Google מעבד מפות בסיסיות באמצעות ממשק MapType, שחייב להצהיר גם על המאפיין projection כדי לזהות את ההיטל של המפה וגם על השיטה getTile() לאחזור המפה על סמך ערכי קואורדינטות של משבצות. הקואורדינטות של המשבצות מבוססות על גודל המשבצת הבסיסי (שחייב להיות מלבני) ועל 'גודל העולם' במפה, שהוא גודל הפיקסלים של העולם במפה ברמת מרחק מ-0. (למפות שמורכבות מאריח אחד בזום 0, גודל המשבצת וגודל העולם זהים).

הגודל של משבצת הבסיס מוגדר בנכס tileSize של MapType. מגדירים את גודל העולם במרומז ב-methods 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;
להצגת דוגמה

כדאי לנסות דוגמה