Kartentypen

Plattform auswählen: Android iOS JavaScript

In diesem Dokument werden die Kartentypen erläutert, die Sie mit der Maps JavaScript API anzeigen lassen können. Die API verwendet ein MapType-Objekt, um Informationen über diese Karten zu speichern. Ein MapType ist eine Schnittstelle, die die Anzeige und Nutzung von Kartenkacheln und die Umwandlung von Bildschirmkoordinaten in Weltkoordinaten (auf der Karte) definiert. Jeder MapType muss Methoden zum Abrufen und Freigeben von Kacheln sowie Eigenschaften zum Definieren des visuellen Verhaltens enthalten.

Die Funktionsweise von Kartentypen in der Maps JavaScript API ist ein komplexes Thema. Die meisten Entwickler können einfach die unten aufgeführten Basiskartentypen verwenden. Es ist aber auch möglich, die Darstellung vorhandener Kartentypen mithilfe von Karten mit benutzerdefinierten Stilen anzupassen oder eigene Kartenkacheln mithilfe von benutzerdefinierten Kartentypen zu definieren. Wenn Sie benutzerdefinierte Kartentypen bereitstellen möchten, müssen Sie die Registry für Kartentypen ändern können.

Basiskartentypen

In der Maps JavaScript API sind vier Kartentypen verfügbar. Neben den bekannten „gezeichneten“ Straßenkartenkacheln unterstützt die Maps JavaScript API auch andere Kartentypen.

Die folgenden Kartentypen sind in der Maps JavaScript API verfügbar:

  • roadmap ist der Standardkartentyp und zeigt die standardmäßige Straßenkartenansicht an.
  • satellite zeigt Google Earth-Satellitenbilder an.
  • hybrid zeigt eine Mischung aus normalen und Satellitenbildern an.
  • terrain zeigt eine physische Karte an, die auf Geländedaten beruht.

Um den Kartentyp zu ändern, der von der Map verwendet wird, legen Sie die mapTypeId-Eigenschaft fest. Dazu müssen Sie entweder im Konstruktor das Map options-Objekt festlegen oder die Methode setMapTypeId() der Karte aufrufen. Die Eigenschaft mapTypeID ist standardmäßig auf roadmap gesetzt.

mapTypeId beim Erstellen festlegen:

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 dynamisch ändern:

map.setMapTypeId('terrain');

Hinweis: Sie legen den Kartentyp der Karte nicht direkt fest. Stattdessen verweisen Sie mit der mapTypeId auf einen MapType. Die Maps JavaScript API nutzt eine Registry (siehe unten), um diese Verweise zu verwalten.

45°-Bilder

Für bestimmte Orte unterstützt die Maps JavaScript API spezielle 45°-Bilder. Diese hochauflösenden Bilder ermöglichen perspektivische Ansichten für alle Himmelsrichtungen (Norden, Süden, Osten, Westen). Sie sind in höheren Zoomstufen für unterstützte Kartentypen verfügbar.

Die folgende Abbildung zeigt eine perspektivische 45°-Ansicht von New York City:

Die Kartentypen satellite und hybrid unterstützen 45°-Bilder bei hohen Zoomstufen (12 und höher), sofern verfügbar. Sind entsprechende Bilder verfügbar wird die Ansicht dieser Kartentypen beim Heranzoomen automatisch so angepasst:

  • Die Satelliten- oder Hybridbilder werden durch 45°-Bilder ersetzt, die auf den aktuellen Ort zentriert sind. Standardmäßig sind diese Bilder nach Norden ausgerichtet. Zoomt der Nutzer heraus, werden wieder die standardmäßigen Satelliten- oder Hybridbilder angezeigt. Das Verhalten variiert je nach Zoomstufe und dem Wert von tilt:
    • Zwischen den Zoomstufen 12 und 18 wird standardmäßig die Draufsichtbasiskarte (0°) angezeigt, außer tilt ist auf „45“ gesetzt.
    • Bei höheren Zoomstufen wird die 45°-Basiskarte angezeigt, außer tilt ist auf „0“ gesetzt.
  • Die Steuerung für die Rotation wird eingeblendet. Sie enthält Optionen, mit denen der Nutzer die Neigung aktivieren bzw. deaktivieren und die Ansicht in 90°-Schritten in beide Richtungen drehen kann. Wenn die Steuerung ausgeblendet werden soll, setzen Sie rotateControl auf false.

Beim Herauszoomen aus einem Kartentyp mit 45°-Bildern werden alle diese Änderungen rückgängig gemacht und die ursprünglichen Kartentypen wiederhergestellt.

45°-Bilder aktivieren und deaktivieren

Um 45°-Bilder zu deaktivieren, rufen Sie setTilt(0) im Map-Objekt auf. Um 45°-Bilder für unterstützte Kartentypen zu aktivieren, müssen Sie setTilt(45) aufrufen. Die getTilt()-Methode der Map spiegelt immer die aktuelle Neigung der Karte wider. Wenn Sie eine tilt für eine Karte festlegen und später entfernen (z. B. durch Herauszoomen aus der Karte), gibt die getTilt()-Methode der Karte 0 zurück.

Wichtig: 45°-Bilder werden nur auf Rasterkarten unterstützt. Sie können nicht für Vektorkarten verwendet werden.

Mit folgendem Beispiel wird eine 45°-Ansicht von New York City angezeigt:

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;
Beispiel ansehen

Testbeispiel

Beispiel ansehen

45°-Bilder drehen

45°-Bilder bestehen eigentlich aus einer Sammlung von Bildern für jede Himmelsrichtung (Norden, Süden, Osten, Westen). Sobald auf der Karte 45°-Bilder angezeigt werden, können Sie die Bilder an einer Himmelsrichtung ausrichten. Dazu rufen Sie setHeading() für das Map-Objekt auf und übergeben dabei einen Zahlenwert, der in Grad relativ zum Norden ausgedrückt wird.

Mit folgendem Beispiel wird eine Luftaufnahme angezeigt. Die Karte wird automatisch alle drei Sekunden gedreht, wenn auf die Schaltfläche geklickt wird:

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;
Beispiel ansehen

Testbeispiel

Beispiel ansehen

Registry für Kartentypen bearbeiten

Die mapTypeId einer Karte ist eine String-ID, mit der einem MapType ein eindeutiger Wert zugeordnet wird. Jedes Map-Objekt enthält eine MapTypeRegistry mit der Sammlung der verfügbaren MapTypes für die Karte. Mit dieser Registry werden beispielsweise die Kartentypen ausgewählt, die im Steuerelement „MapType“ der Karte verfügbar sind.

Sie können Daten nicht direkt aus der Registry auslesen. Stattdessen bearbeiten Sie die Registry, indem Sie benutzerdefinierte Kartentypen hinzufügen und ihnen eine String-ID Ihrer Wahl zuweisen. Sie können die grundlegenden Kartentypen nicht anpassen oder ändern, haben aber die Möglichkeit, sie aus der Karte zu entfernen. Dazu passen Sie die Darstellung der zugehörigen mapTypeControlOptions der Karte an.

Mit dem folgenden Code wird festgelegt, dass nur zwei Kartentypen in den mapTypeControlOptions der Karte angezeigt werden. Außerdem wird die Registry so geändert, dass die Verknüpfung mit dieser ID der eigentlichen Implementierung der MapType-Schnittstelle hinzugefügt wird.

// 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);

Karten mit benutzerdefinierten Stilen

Mit dem StyledMapType können Sie die Darstellung der standardmäßigen Google-Basiskarten anpassen. Dazu ändern Sie die visuelle Darstellung von Elementen wie Straßen, Parks und bebauten Gebieten, um einen anderen Stil als den des Standardkartentyps zu verwenden.

Weitere Informationen zum StyledMapType finden Sie unter Cloudbasiertes Gestalten von Karteninhalten.

Benutzerdefinierte Kartentypen

Die Maps JavaScript API unterstützt die Anzeige und Verwaltung benutzerdefinierter Kartentypen, sodass Sie eigene Kartenbilder oder Kachel-Overlays implementieren können.

In der Maps JavaScript API gibt es mehrere Implementierungsmöglichkeiten für Kartentypen:

  • Standardkachelsätze, die aus Bildern bestehen, die zusammen vollständige kartografische Karten ergeben. Diese Kachelsätze werden auch als Basiskartentypen bezeichnet. Sie verhalten sich wie die vorhandenen Standardkartentypen *roadmap, satellite, hybrid und terrain. Sie können Ihren benutzerdefinierten Kartentyp zum mapTypes-Array einer Karte hinzufügen, damit er von der UI innerhalb der Maps JavaScript API als Standardkartentyp verarbeitet und z. B. in das Steuerelement „MapType“ für den Kartentyp aufgenommen wird.
  • Bildkachel-Overlays, die über vorhandenen Basiskartentypen angezeigt werden. Im Allgemeinen werden diese Kartentypen verwendet, um einen bestehenden Kartentyp zu ergänzen und zusätzliche Informationen anzuzeigen. Sie sind oft auf bestimmte Orte und/oder Zoomstufen beschränkt. Diese Kacheln können transparent sein, damit Sie bestehenden Karten Features hinzufügen können.
  • Kartentypen ohne Bild, mit denen Sie die Anzeige von Karteninformationen auf der Grundebene steuern können.

Für jede dieser Optionen muss eine Klasse erstellt werden, die die MapType-Schnittstelle implementiert. Darüber hinaus bietet die Klasse ImageMapType einige integrierte Verhaltensweisen, um das Erstellen von Imagemap-Typen zu vereinfachen.

Die MapType-Schnittstelle

Bevor Sie Klassen erstellen, die MapType implementieren, müssen Sie verstehen, wie Google Maps Koordinaten berechnet und entscheidet, welche Teile der Karte angezeigt werden sollen. Für alle Basis- oder Overlay-Kartentypen muss eine ähnliche Logik implementiert werden. Weitere Informationen finden Sie im Leitfaden zu Karten- und Kachelkoordinaten.

Benutzerdefinierte Kartentypen müssen die MapType-Schnittstelle implementieren. Über diese Schnittstelle werden bestimmte Eigenschaften und Methoden festgelegt, mit denen die API Anfragen an Ihre Kartentypen initiieren kann, wenn Kartenkacheln im aktuellen Darstellungsbereich und mit der aktuellen Zoomstufe angezeigt werden müssen. Sie verarbeiten diese Anfragen, um zu entscheiden, welche Kachel geladen werden soll.

Hinweis: Sie können eine eigene Klasse erstellen, um die Schnittstelle zu implementieren. Falls Sie kompatible Bilder haben, können Sie alternativ die Klasse ImageMapType verwenden, die diese Schnittstelle bereits implementiert.

Bei Klassen, die die Schnittstelle MapType implementieren, müssen Sie die folgenden Eigenschaften definieren und Werte dafür angeben:

  • tileSize (erforderlich) gibt die Größe der Kachel vom Typ google.maps.Size an. Sie muss rechteckig, aber nicht zwangsläufig quadratisch sein.
  • maxZoom (erforderlich) gibt die maximale Zoomstufe für die Anzeige von Kacheln dieses Kartentyps an.
  • minZoom (optional) gibt die minimale Zoomstufe für die Anzeige von Kacheln dieses Kartentyps an. Standardmäßig ist der Wert auf 0 gesetzt. Das bedeutet, dass keine minimale Zoomstufe vorhanden ist.
  • name (optional) gibt den Namen des Kartentyps an. Diese Eigenschaft ist nur erforderlich, wenn Nutzer den Kartentyp über das entsprechende Steuerelement auswählen können sollen. Weitere Informationen finden Sie im Abschnitt MapType-Steuerelemente hinzufügen.
  • alt (optional) gibt den alternativen Text für diesen Kartentyp an. Er wird als Hover-Text angezeigt. Diese Eigenschaft ist nur erforderlich, wenn Nutzer den Kartentyp über das entsprechende Steuerelement auswählen können sollen. Weitere Informationen finden Sie im Abschnitt MapType-Steuerelemente hinzufügen.

Außerdem müssen Klassen zur Implementierung der MapType-Schnittstelle die folgenden Methoden implementieren:

  • getTile() (erforderlich) wird immer dann aufgerufen, wenn die API ermittelt, dass die Karte neue Kacheln für den Darstellungsbereich anzeigen muss. Die Methode getTile() muss folgende Signatur haben:

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

    Anhand der Eigenschaften tileSize, minZoom und maxZoom der MapType, des aktuellen Darstellungsbereichs und der aktuellen Zoomstufe ermittelt die API, ob sie getTile() aufrufen muss. Der Handler für diese Methode sollte ein HTML-Element mit den übergebenen Koordinaten, der Zoomstufe und dem DOM-Element zurückgeben, an das das Kachelbild angefügt wird.

  • releaseTile() (optional) wird immer dann aufgerufen, wenn die API ermittelt, dass eine Kachel entfernt werden muss, da sie nicht mehr im Darstellungsbereich sichtbar ist. Die Methode muss folgende Signatur haben:

    releaseTile(tile:Node)

    Normalerweise sollten Sie alle Elemente entfernen, die nach dem Hinzufügen zur Karte an die Kartenkacheln angehängt wurden. Wenn Sie beispielsweise Ereignis-Listener an Kartenkachel-Overlays angehängt haben, sollten Sie sie hier entfernen.

Mit der Methode getTile() wird bestimmt, welche Kacheln in einem bestimmten Darstellungsbereich zu laden sind.

Basiskartentypen

Kartentypen, die Sie auf diese Weise erstellen, können entweder allein oder in Verbindung mit anderen Kartentypen als Overlays eingesetzt werden. Eigenständige Kartentypen werden als Basiskartentypen bezeichnet. Wenn Sie möchten, dass die API solche benutzerdefinierten MapTypes genauso behandelt wie die vorhandenen Basiskartentypen (ROADMAP, TERRAIN usw.), müssen Sie den benutzerdefinierten MapType der mapTypes-Eigenschaft der Map hinzufügen. Das ist eine Eigenschaft des Typs MapTypeRegistry.

Mit dem folgenden Code wird ein Basis-MapType erstellt, mit dem die Kachelkoordinaten einer Karte angezeigt werden und ein Umriss der Kacheln gezeichnet wird:

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;
Beispiel ansehen

Testbeispiel

Overlay-Kartentypen

Einige Kartentypen sind dazu vorgesehen, über vorhandenen Kartentypen verwendet zu werden. Sie können transparente Ebenen haben, die POIs anzeigen oder dem Nutzer zusätzliche Informationen zur Verfügung stellen.

In diesen Fällen sollte der Kartentyp nicht als separate Einheit, sondern als Overlay eingesetzt werden. Dazu fügen Sie den Kartentyp über die Eigenschaft overlayMapTypes der Map direkt einem vorhandenen MapType hinzu. Diese Eigenschaft enthält ein MVCArray mit MapTypes. Alle Kartentypen (Basis- und Overlay-Karten) werden innerhalb der mapPane-Ebene gerendert. Overlay-Kartentypen werden über der Basiskarte angezeigt, der sie zugeordnet sind, und zwar in der Reihenfolge, in der sie im Map.overlayMapTypes-Array erscheinen. Overlays mit höheren Indexwerten werden vor Overlays mit niedrigeren Indexwerten angezeigt.

Das folgende Beispiel ist mit dem letzten Beispiel identisch, aber es wurde ein Kachel-Overlay-MapType über dem ROADMAP-Kartentyp erstellt:

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;
Beispiel ansehen

Testbeispiel

Imagemap-Typen

Die Implementierung eines MapType als Basiskartentyp kann zeit- und arbeitsintensiv sein. In der API ist eine besondere Klasse verfügbar, mit der die MapType-Schnittstelle für die gängigsten Kartentypen implementiert wird: Kartentypen, die aus Kacheln bestehen, die wiederum aus einzelnen Bilddateien zusammengesetzt sind.

Diese Klasse, die ImageMapType-Klasse, wird mithilfe einer ImageMapTypeOptions-Objektspezifikation erstellt, die die folgenden erforderlichen Properties definiert:

  • tileSize (erforderlich) gibt die Größe der Kachel vom Typ google.maps.Size an. Sie muss rechteckig, aber nicht zwangsläufig quadratisch sein.
  • getTileUrl (erforderlich) gibt die Funktion an, normalerweise als Inline-Funktionsliteral, mit der die Auswahl der richtigen Bildkachel anhand der übergebenen Weltkoordinaten und Zoomstufe verarbeitet wird.

Mit folgendem Code wird ein Basis-ImageMapType implementiert, der die Mondkacheln von Google verwendet. In diesem Beispiel wird eine Normalisierungsfunktion verwendet, damit sich die Kacheln auf der X-Achse, aber nicht auf der Y-Achse der Karte wiederholen.

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;
Beispiel ansehen

Testbeispiel

Projektionen

Die Erde ist eine (annähernd) dreidimensionale Kugel, während eine Karte eine flache, zweidimensionale Fläche ist. Die Maps JavaScript API projiziert diese Kugel (wie jede andere flache Karte der Erde) auf eine flache Oberfläche. Stark vereinfacht kann man eine Projektion als Zuordnung von Breiten- und Längengradwerten zu den Koordinaten der projizierten Karte definieren.

Für Projektionen in der Maps JavaScript API muss die Schnittstelle Projection implementiert werden. Die Projection-Implementierung muss nicht nur eine Abbildung eines Koordinatensystems auf ein anderes bieten, sondern auch eine bidirektionale Zuordnung. Sie müssen also definieren, wie die Erdkoordinaten (LatLng-Objekte) in das Weltkoordinatensystem der Projection-Klasse übersetzt werden sollen und umgekehrt. In Google Maps wird die Mercator-Projektion verwendet, um Karten aus geografischen Daten zu erstellen und Ereignisse auf der Karte in geografische Koordinaten umzuwandeln. Um die Projektion abzurufen, müssen Sie getProjection() für die Map (oder einen der standardmäßigen Basis-MapTypes) aufrufen. In den meisten Fällen reicht diese Standard-Projection aus. Sie können aber auch eigene benutzerdefinierte Projektionen definieren und verwenden.

Projektionen implementieren

Wenn Sie eine benutzerdefinierte Projektion implementieren, müssen Sie einige Dinge definieren:

  • Die Formeln für die Abbildung von Breiten- und Längenkoordinaten auf einer kartesischen Ebene und andersherum. Die Projection-Schnittstelle unterstützt nur Umrechnungen in geradlinige Koordinaten.
  • Die Basiskachelgröße. Alle Kacheln müssen rechteckig sein.
  • Die „Weltgröße“ einer Karte unter Verwendung des Basiskachelsatzes bei Zoomstufe 0. Bei Karten, die bei Zoomstufe 0 aus einer Kachel bestehen, sind Weltgröße und Basiskachelgröße identisch.

Umwandlung von Koordinaten in Projektionen

Für jede Projektion gibt es zwei Methoden zur Umrechnung zwischen geografischen und Weltkoordinaten:

  • Bei der Projection.fromLatLngToPoint()-Methode wird ein LatLng-Wert in eine Weltkoordinate umgewandelt. Diese Methode wird verwendet, um Overlays auf der Karte sowie die Karte selbst zu positionieren.
  • Die Projection.fromPointToLatLng()-Methode wandelt eine Weltkoordinate in einen LatLng-Wert um. Sie wird verwendet, um Ereignisse auf der Karte (z. B. Klicks) in geografische Koordinaten umzuwandeln.

Google Maps geht davon aus, dass Projektionen geradlinig sind.

Im Allgemeinen können Sie eine Projektion für zwei Zwecke verwenden: um eine Weltkarte zu erstellen oder um eine Karte eines lokalen Gebiets zu erstellen. Für die Weltkarte muss die Projektion für alle Längengrade geradlinig und normal sein. Einige Projektionen, insbesondere konische Projektionen, können „lokal normal“ sein (also nach Norden zeigen), aber vom geografischen Norden abweichen. Das ist z. B. der Fall, wenn die Karte weiter relativ zu einem Referenzlängenpunkt positioniert ist. Sie können eine solche Projektion lokal verwenden, müssen sich aber bewusst sein, dass die Projektion zwangsläufig ungenau ist und Umwandlungsfehler immer offensichtlicher werden, je weiter Sie sich vom Referenzlängengrad entfernen.

Auswahl von Kartenkacheln in Projektionen

Mit Projektionen lassen sich nicht nur die Positionen von Orten oder Overlays bestimmen, sondern auch die Kartenkacheln selbst positionieren. Die Maps JavaScript API rendert Basiskarten über eine MapType-Schnittstelle, die sowohl eine projection-Eigenschaft zum Identifizieren der Kartenprojektion als auch eine getTile()-Methode zum Abrufen der Kartenkacheln anhand der Kachelkoordinatenwerte deklarieren muss. Kachelkoordinaten basieren auf der Größe der Basiskachel (die rechteckig sein muss) und der „Weltgröße“ Ihrer Karte (entspricht der Größe in Pixeln Ihrer Kartenwelt bei Zoomstufe 0). Bei Karten, die bei Zoomstufe 0 aus einer Kachel bestehen, sind Weltgröße und Kachelgröße identisch.

Sie legen die Basiskachelgröße in der tileSize-Eigenschaft des MapType fest. Die Weltgröße wird implizit in den fromLatLngToPoint()- und fromPointToLatLng()-Methoden Ihrer Projektion definiert.

Da die Bildauswahl auf diesen übergebenen Werten beruht, ist es empfehlenswert, Bilder so zu benennen, dass sie programmatisch ausgewählt werden können, z. B. map_zoom_tileX_tileY.png.

Im folgenden Beispiel wird mithilfe der Peters-Projektion ein ImageMapType definiert:

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;
Beispiel ansehen

Testbeispiel