Typy map

Wybierz platformę: Android iOS JavaScript

W tym dokumencie opisujemy rodzaje map, które możesz wyświetlać za pomocą interfejsu Maps JavaScript API. Do przechowywania informacji o tych mapach interfejs API używa obiektu MapType. MapType to interfejs, który określa sposób wyświetlania i zastosowania fragmentów mapy oraz tłumaczenie układów współrzędnych ze współrzędnych ekranowych na współrzędne świata (na mapie). Każdy element MapType musi zawierać kilka metod pobierania i zwalniania kafelków oraz właściwości definiujące jego wygląd.

Wewnętrzne działanie typów map w Maps JavaScript API to zaawansowany temat. Większość deweloperów może używać wymienionych poniżej podstawowych typów map. Możesz jednak również modyfikować sposób wyświetlania istniejących typów map za pomocą stylizowanych map lub definiować własne fragmenty map za pomocą niestandardowych typów map. Gdy dostarczasz niestandardowe typy map, musisz dowiedzieć się, jak zmodyfikować rejestr typów map.

Podstawowe typy map

W Maps JavaScript API dostępne są 4 typy map. Oprócz znanych „namalowanych” fragmentów mapy drogowej interfejs Maps JavaScript API obsługuje również inne typy map.

W Maps JavaScript API dostępne są te typy map:

  • roadmap wyświetla domyślny widok mapy drogowej. To jest domyślny typ mapy.
  • satellite wyświetla zdjęcia satelitarne z Google Earth.
  • hybrid wyświetla zarówno widok normalny, jak i widok satelitarny.
  • terrain wyświetla mapę fizyczną na podstawie informacji o terenie.

Typ mapy używany przez Map możesz zmienić, ustawiając właściwość mapTypeId w konstruktorze, ustawiając obiekt Map options, albo wywołując metodę setMapTypeId() mapy. Domyślna wartość właściwości mapTypeID to roadmap.

Ustawiam mapTypeId podczas budowy:

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

Dynamiczna zmiana parametru mapTypeId:

map.setMapTypeId('terrain');

Pamiętaj, że w rzeczywistości nie ustawiasz typu mapy bezpośrednio, tylko ustawiasz jej mapTypeId tak, aby odwoływał się do MapType za pomocą identyfikatora. Do zarządzania tymi odwołaniami interfejs Maps JavaScript API wykorzystuje rejestr typów map, opisany poniżej.

Zdjęcia pod kątem 45°

Interfejs Maps JavaScript API obsługuje specjalne zdjęcia pod kątem 45° w niektórych lokalizacjach. Te zdjęcia o wysokiej rozdzielczości umożliwiają pokazanie z perspektywy każdego z kierunków świata (północ, południe, wschód, zachód). Te obrazy są dostępne przy wyższych poziomach powiększenia w przypadku obsługiwanych typów map.

Poniższa ilustracja przedstawia widok z perspektywy Nowego Jorku pod kątem 45°:

Typy map satellite i hybrid obsługują zdjęcia w zakresie 45° przy dużym powiększeniu (12 i więcej), jeśli są dostępne. Jeśli użytkownik powiększy widok lokalizacji, w której znajdują się takie zdjęcia, mapy tego typu automatycznie zmieniają widok w taki sposób:

  • Zdjęcia satelitarne lub hybrydowe są zastępowane zdjęciami zapewniającymi perspektywę 45°, wyśrodkowaną w bieżącej lokalizacji. Domyślnie takie widoki są kierowane w kierunku północnym. Jeśli użytkownik pomniejszy obraz, ponownie pojawi się domyślny obraz satelitarny lub hybrydowy. Działanie różni się w zależności od poziomu powiększenia i wartości tilt:
    • Pomiędzy poziomami powiększenia 12–18 domyślnie wyświetlana jest mapa bazowa z góry (0°), chyba że opcja tilt ma wartość 45.
    • Przy powiększeniu równym 18 lub większym mapa bazowa jest wyświetlana pod kątem 45°, chyba że tilt ma wartość 0.
  • Pojawi się element sterujący obrotem. Sterowanie obracaniem udostępnia opcje, które umożliwiają przełączanie przechylenia i obracanie widoku w wybranym kierunku co 90°. Aby ukryć element sterujący obrotem, ustaw rotateControl na false.

Pomniejszanie z typu mapy wyświetlającego zdjęcia pod kątem 45° powoduje cofnięcie każdej z tych zmian i przywrócenie oryginalnych typów map.

Włączanie i wyłączanie zdjęć 45°

Możesz wyłączyć zdjęcia pod kątem 45°, wywołując funkcję setTilt(0) w obiekcie Map. Aby włączyć zdjęcia 45° dla obsługiwanych typów map, wywołaj setTilt(45). Metoda getTilt() obiektu Map zawsze będzie odzwierciedlać aktualną wartość tilt wyświetlaną na mapie. Jeśli ustawisz na mapie obiekt tilt, a następnie usuniesz ten element tilt (np. pomniejszając mapę), metoda getTilt() mapy zwróci wartość 0.

Ważne: zdjęcia 45° są obsługiwane tylko w przypadku map rastrowych. Nie można ich używać z mapami wektorowymi.

Poniższy przykład przedstawia widok Nowego Jorku pod kątem 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;
Zobacz przykład

Zobacz próbkę

Zobacz przykład

Obracanie zdjęć pod kątem 45°

Zdjęcia pod kątem 45° w rzeczywistości składają się z kolekcji zdjęć przedstawiających każdy kierunek kardynalny (północ, południe, wschód, zachód). Gdy na Twojej mapie są wyświetlane zdjęcia pod kątem 45°, możesz ustawić zdjęcia w kierunku jednego z kierunków głównych, wywołując w obiekcie Map funkcję setHeading() i przekazując wartość liczbową wyrażoną w stopniach od północy.

Poniższy przykład przedstawia mapę powietrzną i automatycznie obraca ją co 3 sekundy po kliknięciu przycisku:

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;
Zobacz przykład

Zobacz próbkę

Zobacz przykład

Modyfikowanie rejestru typów map

mapTypeId mapy to identyfikator w postaci ciągu używany do powiązania elementu MapType z unikalną wartością. Każdy obiekt Map zawiera obiekt MapTypeRegistry, który zawiera zbiór zasobów MapType dostępnych dla danej mapy. Ten rejestr służy na przykład do wyboru typów map, które są dostępne w ustawieniu MapType.

Nie odczytujesz bezpośrednio z rejestru typów map. Zamiast tego modyfikujesz rejestr, dodając niestandardowe typy map i wiążąc je z wybranym identyfikatorem ciągu. Nie można modyfikować podstawowych typów map (ale możesz je usunąć z mapy, zmieniając wygląd powiązanych mapTypeControlOptions map).

Ten kod ustawia w mapie tylko 2 typy map w atrybucie mapTypeControlOptions mapy i modyfikuje rejestr, aby dodać powiązanie z tym identyfikatorem do faktycznej implementacji interfejsu 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);

Stylizowane Mapy Google

StyledMapType umożliwia dostosowanie wyglądu standardowych map podstawowych Google przez zmianę sposobu wyświetlania takich elementów, jak drogi, parki czy obszary zabudowane, w taki sposób, aby odzwierciedlały inny styl niż używany w domyślnym typie mapy.

Więcej informacji o StyledMapType znajdziesz w przewodniku po mapach z określonym stylem.

Typy map niestandardowych

Interfejs Maps JavaScript API obsługuje wyświetlanie niestandardowych typów map i zarządzanie nimi, umożliwiając implementowanie własnych obrazów map lub nakładek z kafelkami.

W Maps JavaScript API istnieje kilka możliwych implementacji typów map:

  • Standardowe zestawy kafelków składające się z obrazów, które łącznie stanowią pełne mapy kartograficzne. Te zestawy kafelków są również nazywane typami map podstawowych. Te typy map działają i działają tak jak istniejące domyślne typy map: roadmap, satellite, hybrid i terrain. Możesz dodać niestandardowy typ mapy do tablicy mapTypes mapy, aby umożliwić interfejsowi użytkownika interfejsu Maps JavaScript API traktowanie Twojego niestandardowego typu mapy jako standardowego (np. przez uwzględnienie go w elemencie sterującym MapType).
  • Nakładki z kafelkami obrazów, które są wyświetlane nad istniejącymi typami map podstawowych. Te typy map są zwykle używane do rozszerzania istniejącego typu mapy w celu wyświetlenia dodatkowych informacji. Często są ograniczone do określonych lokalizacji lub poziomów powiększenia. Pamiętaj, że te kafelki mogą być przezroczyste, co pozwala dodawać funkcje do istniejących map.
  • Typy map inne niż graficzne, które umożliwiają manipulowanie wyświetlaniem informacji na mapach na najbardziej podstawowym poziomie.

Każda z tych opcji wymaga utworzenia klasy implementującej interfejs MapType. Dodatkowo klasa ImageMapType udostępnia wbudowane działanie, które upraszcza tworzenie typów map obrazów.

Interfejs MapType

Zanim utworzysz zajęcia, które stosują MapType, dowiedz się, jak Mapy Google określają współrzędne i decydują, które części mapy wyświetlić. W przypadku wszystkich typów mapy podstawowej lub nakładki musisz zastosować podobną logikę. Przeczytaj przewodnik po współrzędnych mapach i kafelkach.

Niestandardowe typy map muszą implementować interfejs MapType. Ten interfejs określa pewne właściwości i metody, które pozwalają interfejsowi API na inicjowanie żądań typów map, gdy interfejs API określi, że musi wyświetlać fragmenty mapy w bieżącym widoku i na poziomie powiększenia. Ty obsługujesz te żądania i decydujesz, który kafelek do wczytania.

Uwaga: aby wdrożyć ten interfejs, możesz utworzyć własną klasę. Jeśli masz zgodne zdjęcia, możesz też użyć klasy ImageMapType, która implementuje już ten interfejs.

Klasy implementujące interfejs MapType wymagają zdefiniowania i wypełnienia tych właściwości:

  • tileSize (wymagany) określa rozmiar kafelka (typu google.maps.Size). Rozmiary muszą być prostokątne, ale nie mogą być kwadratowe.
  • maxZoom (wymagany) określa maksymalny poziom powiększenia, przy którym mają być wyświetlane kafelki tego typu mapy.
  • minZoom (opcjonalnie) określa minimalny poziom powiększenia, przy którym wyświetlany jest kafelek tego typu mapy. Domyślnie ta wartość wynosi 0, co oznacza, że nie ma minimalnego poziomu powiększenia.
  • name (opcjonalny) określa nazwę tego typu mapy. Ta właściwość jest wymagana tylko wtedy, gdy chcesz, aby ten typ mapy można było wybierać w elemencie sterującym MapType. (Zobacz Dodawanie elementów sterujących MapType poniżej).
  • alt (opcjonalny) określa tekst alternatywny dla tego typu mapy wyświetlany jako tekst po najechaniu kursorem. Ta właściwość jest wymagana tylko wtedy, gdy chcesz, by ten typ mapy można było wybierać w elemencie sterującym MapType. (Zobacz Dodawanie elementów sterujących MapType poniżej).

Dodatkowo klasy implementujące interfejs MapType muszą implementować te metody:

  • Pole getTile() (wymagane) jest wywoływane za każdym razem, gdy interfejs API ustali, że mapa musi wyświetlić nowe kafelki dla danego widocznego obszaru. Metoda getTile() musi mieć ten podpis:

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

    Interfejs API określa, czy musi wywołać funkcję getTile(), na podstawie właściwości tileSize, minZoom i maxZoom obiektu MapType oraz bieżącego widocznego obszaru i poziomu powiększenia mapy. Moduł obsługi tej metody powinien zwracać element HTML z przekazaną współrzędną, poziomem powiększenia i elementem DOM, do którego ma zostać dołączony obraz kafelka.

  • Funkcja releaseTile() (opcjonalna) jest wywoływana za każdym razem, gdy interfejs API ustali, że mapa musi usunąć kafelek, gdy zniknie on z widoku. Ta metoda musi mieć następujący podpis:

    releaseTile(tile:Node)

    Usunięcie wszystkich elementów, które zostały dołączone do kafelków mapy, należy zwykle usunąć przy dodawaniu mapy. Jeśli na przykład do nakładek kafelków mapy zostały dołączone detektory zdarzeń, usuń je tutaj.

Metoda getTile() działa jako główny kontroler określający, które kafelki zostaną wczytane w danym widocznym obszarze.

Typy map podstawowych

Typy map, które tworzysz w ten sposób, mogą występować samodzielnie lub być połączone z innymi typami map jako nakładki. Samodzielne typy map są nazywane typami map podstawowych. Możesz zdecydować, aby interfejs API traktował takie niestandardowe obiekty MapType tak jak każdy inny istniejący typ mapy podstawowej (ROADMAP, TERRAIN itp.). Aby to zrobić, dodaj niestandardową właściwość MapType do właściwości mapTypes elementu Map. Typ tej właściwości to MapTypeRegistry.

Poniższy kod tworzy obiekt podstawowy MapType wyświetlający współrzędne kafelków na mapie i rysuje kontur tych fragmentów:

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;
Zobacz przykład

Zobacz próbkę

Typy nakładanych map

Niektóre typy map są zaprojektowane do działania na istniejących typach map. Takie mapy mogą mieć przezroczyste warstwy wskazujące ciekawe miejsca lub zawierające dodatkowe dane.

W takich przypadkach nie chcesz, aby dany typ mapy był traktowany jako oddzielny element, ale jako nakładka. Możesz to zrobić, dodając typ mapy do istniejącego MapType bezpośrednio za pomocą właściwości overlayMapTypes Map. Ta właściwość zawiera element MVCArray z MapType. Wszystkie typy map (podstawowa i nakładka) są renderowane w warstwie mapPane. Typy map nad powierzchnią są wyświetlane na mapie podstawowej, do której są dołączone, w kolejności, w jakiej występują w tablicy Map.overlayMapTypes (nakładki o wyższych wartościach indeksu są wyświetlane przed nakładkami o niższych wartościach indeksu).

Poniższy przykład jest taki sam jak poprzedni, ale utworzyliśmy nakładkę z kafelkami MapType na mapę typu 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;
Zobacz przykład

Zobacz próbkę

Typy map obrazów

Zaimplementowanie MapType jako typu mapy podstawowej może być czasochłonne i pracochłonne. Interfejs API udostępnia specjalną klasę, która implementuje interfejs MapType w przypadku najpopularniejszych typów map: typów map składających się z kafelków złożonych z plików z pojedynczym obrazem.

Tę klasę (ImageMapType) tworzy się za pomocą specyfikacji obiektu ImageMapTypeOptions definiującej te wymagane właściwości:

  • tileSize (wymagany) określa rozmiar kafelka (typu google.maps.Size). Rozmiary muszą być prostokątne, ale nie mogą być kwadratowe.
  • getTileUrl (wymagany) określa funkcję, zwykle dostarczaną jako literał funkcji wbudowanej, która służy do wyboru odpowiedniego kafelka obrazu na podstawie podanych współrzędnych świata i poziomu powiększenia.

Ten kod implementuje podstawowy element ImageMapType za pomocą kafelków księżyca Google. W tym przykładzie wykorzystano funkcję normalizacji, aby mieć pewność, że fragmenty będą powtarzane wzdłuż osi X, ale nie wzdłuż osi Y mapy.

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;
Zobacz przykład

Zobacz próbkę

Prognozy

Ziemia jest trójwymiarową kulą (w przybliżeniu), a mapa to płaska, dwuwymiarowa powierzchnia. Mapa widoczna w Maps JavaScript API, podobnie jak każda płaska mapa Ziemi, to odwzorowanie tej kuli na płaską powierzchnię. Mówiąc najprościej, odwzorowanie można zdefiniować jako mapowanie wartości szerokości i długości geograficznej na współrzędne na mapie wyświetlania.

Prognozy w Maps JavaScript API muszą implementować interfejs Projection. Implementacja Projection musi zapewniać nie tylko mapowanie z jednego układu współrzędnych do drugiego, ale też mapowanie dwukierunkowe. Musisz określić sposób tłumaczenia ze współrzędnych Ziemi (obiekty LatLng) na układ współrzędnych światowych klasy Projection i odwrotnie. Mapy Google wykorzystują odwzorowanie Merkatora do tworzenia map na podstawie danych geograficznych i przekształcania zdarzeń na mapie na współrzędne geograficzne. Możesz uzyskać tę prognozę, wywołując funkcję getProjection() w Map (lub dowolnym standardowym, podstawowym typie MapType). W większości zastosowań wystarczy standardowy Projection, ale możesz też zdefiniować i zastosować własne prognozy niestandardowe.

Wdrażanie prognozy

Podczas wdrażania niestandardowej prognozy musisz zdefiniować kilka rzeczy:

  • Wzór na mapowanie współrzędnych szerokości i długości geograficznej na płaszczyznę kartezjańską i odwrotnie. (Interfejs Projection obsługuje tylko przekształcenia w współrzędne prostokątne).
  • Rozmiar kafelka podstawowego. Wszystkie kafelki muszą być prostokątne.
  • „Rozmiar świata” mapy używającej kafelka podstawowego ustawionego na poziomie powiększenia 0. Pamiętaj, że w przypadku map złożonych z 1 kafelka przy powiększeniu 0 rozmiar świata i rozmiar kafelka podstawowego są identyczne.

Skoordynuj transformacje w prognozach

Każde rzutowanie udostępnia 2 metody tłumaczenia między tymi dwoma systemami współrzędnych, co pozwala na konwersję między współrzędnymi geograficznymi i światowymi:

  • Metoda Projection.fromLatLngToPoint() konwertuje wartość LatLng we współrzędne świata. Ta metoda służy do umieszczania nakładek na mapie (oraz określania pozycji samej mapy).
  • Metoda Projection.fromPointToLatLng() konwertuje współrzędną świata na wartość LatLng. Ta metoda służy do konwertowania zdarzeń takich jak kliknięcia na mapie na współrzędne geograficzne.

Mapy Google zakładają, że rzuty są prostoliniowe.

Odwzorowanie może być na ogół wystarczające w 2 przypadkach: utworzenia mapy świata lub mapy lokalnego obszaru. W pierwszym przypadku upewnij się, że rzutowanie jest prostokątne i normalne na wszystkich długościach geograficznych. Niektóre rzuty (zwłaszcza odwzorowania stożkowe) mogą być „normalne lokalnie” (tzn. wskazywać północ), ale odbiegają od rzeczywistej północy; na przykład im bardziej położenie mapy jest względem określonej długości geograficznej. Możesz korzystać z takich odwzorowań lokalnie, ale pamiętaj, że rzut jest zawsze niedokładny, a błędy przekształcenia będą się stawać w miarę oddalania się od odchylenia długości geograficznej.

Wybór kafelków mapy w odwzorowaniach

Odwzorowania przydają się nie tylko do określania pozycji lokalizacji lub nakładek, ale też do określania pozycji fragmentów mapy. Interfejs Maps JavaScript API renderuje mapy podstawowe za pomocą interfejsu MapType, który musi zadeklarować właściwość projection do identyfikowania odwzorowania mapy i metodę getTile() pobierania fragmentów mapy na podstawie wartości współrzędnych kafelków. Współrzędne kafelków zależą zarówno od podstawowego rozmiaru kafelka (musi być prostokątnym), jak i od „wielkości świata” mapy, czyli rozmiaru świata mapy w pikselach na poziomie powiększenia 0. (W przypadku map złożonych z jednego kafelka przy powiększeniu 0 rozmiar kafelka i rozmiar świata są identyczne).

Rozmiar podstawowego kafelka określasz we właściwości tileSize w: MapType. Rozmiar świata określa się domyślnie w metodach fromLatLngToPoint() i fromPointToLatLng() prognozy.

Wybór obrazu zależy od tych przekazywanych wartości, dlatego warto nadać obrazom nazwy, które można wybierać automatycznie na podstawie przekazanych wartości, np. map_zoom_tileX_tileY.png.

Poniższy przykład definiuje ImageMapType z użyciem odwzorowania 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;
Zobacz przykład

Zobacz próbkę