סוגי מפות

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

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

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

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

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

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

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

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

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

התמונה הבאה מציגה נקודת מבט של 45° על העיר ניו יורק:

סוגי המפות satellite ו-hybrid תומכים בתמונות ב-45° ברמות זום גבוהות (12 ומעלה) במקומות שבהם הן זמינות. אם המשתמש מגדיל את התצוגה ובמיקום שעבורו קיימות תמונות כאלה, סוגי המפות האלה משנים את התצוגות באופן אוטומטי באופן הבא:

  • תמונות הלוויין או ההיברידיות מוחלפות בזווית של 45 מעלות, תוך התמקדות במיקום הנוכחי. כברירת מחדל, התצוגות האלה מופנות לכיוון צפון. אם המשתמש מקטין את התצוגה, תמונת הלוויין או תמונת הלוויין שמוגדרת כברירת מחדל מוצגת שוב. ההתנהגות משתנה בהתאם לרמת הזום ולערך של tilt:
    • בין רמות זום 12 ו-18, המפה הבסיסית מלמעלה למטה (0°) מוצגת כברירת מחדל, אלא אם הערך של tilt מוגדר ל-45.
    • המפה הבסיסית ב-45° מוצגת ברמות זום של 18 או יותר, אלא אם השדה 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 של Map.

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

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

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. (פרטים נוספים בקטע הוספת MapType פקדים בהמשך).
  • alt (אופציונלי) מציין את הטקסט החלופי של סוג המפה הזה, שמוצג כטקסט מרחף. המאפיין הזה נדרש רק אם רוצים שניתן יהיה לבחור את סוג המפה הזה בפקד MapType. (פרטים נוספים בקטע הוספת MapType פקדים בהמשך).

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

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

השיטה 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, הגודל בעולם וגודל אריח הבסיס זהים.

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

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

  • השיטה 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"),
      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;
להצגת דוגמה

רוצה לנסות דוגמה?