Typy map

Wybierz platformę: Android iOS JavaScript

W tym dokumencie opisujemy typy 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 wyświetlanie i korzystanie z fragmentów mapy oraz tłumaczenie układów współrzędnych ze współrzędnych ekranu na współrzędne świata (na mapie). Każdy obiekt MapType musi zawierać kilka metod pobierania i zwalniania kafelków oraz właściwości, które definiują jego działanie wizualne.

Działanie typów map w interfejsie Maps JavaScript API to zaawansowany temat. Większość programistów używa wymienionych poniżej podstawowych typów map. Możesz jednak również zmodyfikować sposób wyświetlania istniejących typów map za pomocą stylowych map lub zdefiniować własne fragmenty mapy za pomocą niestandardowych typów map. Jeśli udostępniasz niestandardowe typy map, musisz wiedzieć, jak zmodyfikować rejestr typów map.

Podstawowe typy map

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

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

  • roadmap wyświetla domyślny widok mapy dróg. To jest domyślny typ mapy.
  • satellite wyświetla zdjęcia satelitarne z Google Earth.
  • hybrid wyświetla widok normalny i satelitarny.
  • terrain wyświetla fizyczną mapę na podstawie informacji o ukształtowaniu terenu.

Typ mapy używany przez Map możesz zmienić, ustawiając jego właściwość mapTypeId w konstruktorze, ustawiając obiekt Map options lub wywołując metodę setMapTypeId() mapy. Właściwość mapTypeID przyjmuje domyślnie wartość roadmap.

Ustawianie 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 bezpośrednio typu mapy mapy, ale zamiast tego ustawiasz jej mapTypeId tak, aby odwoływał się do MapType za pomocą identyfikatora. Interfejs Maps JavaScript API do zarządzania tymi odwołaniami wykorzystuje rejestr typów map, jak opisano 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ą widok z perspektywy każdego kierunku (północ, południe, wschód, zachód). W przypadku obsługiwanych typów map te obrazy są dostępne przy większym powiększeniu.

Poniższa ilustracja przedstawia Nowy Jork z perspektywy 45°:

Mapy typu satellite i hybrid obsługują zdjęcia pod kątem 45° przy dużym powiększeniu (12 i większym), o ile są dostępne. Jeśli użytkownik powiększy widok do lokalizacji, której dotyczą takie zdjęcia, typy map automatycznie zmienią widok w następujący sposób:

  • Zdjęcia satelitarne lub hybrydowe są zastępowane zdjęciami z perspektywy pod kątem 45° wyśrodkowanym na bieżącej lokalizacji. Widoki takie są domyślnie zorientowane w kierunku północnym. Jeśli użytkownik pomniejszy widok, pojawią się ponownie domyślne zdjęcia satelitarne lub hybrydowe. Działanie różni się w zależności od poziomu powiększenia i wartości tilt:
    • Pomiędzy poziomami powiększenia od 12 do 18 domyślnie wyświetlana jest mapa bazowa z góry (0°), chyba że tilt ma wartość 45.
    • Przy powiększeniu co najmniej 18 wyświetlana jest mapa bazowa pod kątem 45°, chyba że tilt ma wartość 0.
  • Element sterujący obracania staje się widoczny. Element sterujący obracaniem udostępnia opcje, które umożliwiają użytkownikowi przełączanie przechylenia oraz obracanie widoku o 90° w dowolnym kierunku. Aby ukryć element sterujący obrotem, ustaw rotateControl na false.

Pomniejszenie od typu mapy wyświetlającej zdjęcia pod kątem 45° cofa wszystkie te zmiany i przywraca pierwotne typy map.

Włączanie i wyłączanie zdjęć pod kątem 45°

Możesz wyłączyć zdjęcia pod kątem 45°, wywołując metodę setTilt(0) dla obiektu Map. Aby włączyć zdjęcia pod kątem 45° dla obsługiwanych typów map, zadzwoń pod numer setTilt(45). Metoda getTilt() obiektu Map zawsze odzwierciedla aktualną wartość tilt wyświetlaną na mapie. Jeśli ustawisz na mapie tilt, a później usuniesz ten tilt (na przykład przez powiększenie mapy), metoda getTilt() mapy zwróci wartość 0.

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

Następujący przykład obejmuje 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

Wypróbuj fragment

Zobacz przykład

Zdjęcia obracane o 45°

Widok 45° składa się z kolekcji obrazów dla każdego kierunku (północ, południe, wschód, zachód). Gdy na mapie wyświetlają się zdjęcia pod kątem 45°, możesz ustawić je w kierunku jednego z głównych kierunków, wywołując w obiekcie Map wartość liczbową setHeading(), podając wartość liczbową wyrażoną jako stopnie od północy.

Poniższy przykład przedstawia mapę lotniczą 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

Wypróbuj fragment

Zobacz przykład

Modyfikowanie rejestru typów map

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

Nie możesz odczytywać danych bezpośrednio z rejestru typów map. Zamiast tego możesz zmodyfikować rejestr, dodając niestandardowe typy map i kojarząc je z wybranym przez Ciebie identyfikatorem ciągu znaków. Nie możesz modyfikować podstawowych typów mapy (ale możesz je usunąć z mapy, zmieniając wygląd powiązanego z nią obiektu mapTypeControlOptions).

Poniższy kod ustawia mapę tak, aby wyświetlała tylko 2 typy map w jej obiekcie mapTypeControlOptions, i modyfikuje rejestr, aby dodać powiązanie z tym identyfikatorem do rzeczywistej 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 wyświetlania standardowych map podstawowych Google przez zmianę wyglądu takich elementów jak drogi, parki czy obszary zabudowane, aby odzwierciedlić inny styl niż używany w domyślnym typie mapy.

Więcej informacji na temat obszaru StyledMapType znajdziesz w przewodniku po mapach ze stylami.

Niestandardowe typy map

Interfejs Maps JavaScript API obsługuje wyświetlanie niestandardowych typów map i zarządzanie nimi, co pozwala implementować własne obrazy map lub nakładki z kafelkami.

W interfejsie Maps JavaScript API istnieje kilka możliwych implementacji typu mapy:

  • Standardowe zestawy kafelków składające się z obrazów, które razem tworzą pełne mapy kartograficzne. Te zestawy kafelków są też nazywane typami map podstawowych. Te typy map działają i zachowują się tak jak istniejące domyślne typy map: roadmap, satellite, hybrid i terrain. Możesz dodać własny typ mapy do tablicy mapTypes mapy, aby umożliwić interfejsowi interfejsu API JavaScript Map Google traktowanie niestandardowego typu mapy jako standardowego typu mapy (np. przez umieszczenie go w elemencie sterującym MapType).
  • Nakładki kafelków obrazów, które są wyświetlane nad istniejącymi typami map podstawowych. Ogólnie te typy map są używane do rozszerzania istniejącego typu mapy w celu wyświetlenia dodatkowych informacji. Często są ograniczone do konkretnych lokalizacji lub poziomów powiększenia. Pamiętaj, że te kafelki mogą być przezroczyste, co umożliwia dodawanie funkcji do istniejących map.
  • Typy map innych niż graficzne, które pozwalają manipulować wyświetlaniem informacji o mapie na najbardziej podstawowym poziomie.

Każda z tych opcji wymaga utworzenia klasy, która implementuje interfejs MapType. Dodatkowo klasa ImageMapType udostępnia wbudowane funkcje ułatwiające tworzenie typów map z obrazem.

Interfejs MapType

Zanim utworzysz klasy, które implementują obiekt MapType, warto wiedzieć, jak Mapy Google określają współrzędne i decydują, które fragmenty mapy wyświetlić. Podobną logikę musisz wdrożyć w przypadku każdego typu mapy podstawowej lub nakładki. 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ń do Twoich typów map, gdy interfejs API określi, że musi wyświetlać fragmenty mapy w bieżącym widocznym obszarze i na danym poziomie powiększenia. To Ty zajmujesz się tymi żądaniami, aby zdecydować, który kafelek wczytać.

Uwaga: aby wdrożyć ten interfejs, możesz utworzyć własną klasę. Jeśli masz zgodne obrazy, możesz też użyć klasy ImageMapType, która już implementuje 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 muszą być kwadratowe.
  • maxZoom (wymagany) określa maksymalny poziom powiększenia, przy którym wyświetlają się kafelki tego typu mapy.
  • minZoom (opcjonalny) określa minimalny poziom powiększenia, przy którym wyświetla się kafelek tego typu mapy. Domyślna wartość to 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, aby 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:

  • Element getTile() (wymagany) jest wywoływany za każdym razem, gdy interfejs API określi, że mapa musi wyświetlić nowe kafelki w danym widocznym obszarze. Metoda getTile() musi mieć taki podpis:

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

    Interfejs API określa, czy musi wywołać getTile() na podstawie właściwości tileSize, minZoom i maxZoom elementów 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 płytki.

  • Parametr releaseTile() (opcjonalny) jest wywoływany za każdym razem, gdy interfejs API ustali, że mapa musi usunąć kafelek, który zniknie z widoku. Ta metoda musi mieć następujący podpis:

    releaseTile(tile:Node)

    Zwykle musisz usunąć wszystkie elementy, które były dołączone do kafelków mapy, po dodaniu jej do mapy. Jeśli np. dołączyłeś detektory zdarzeń do mapowania nakładek kafelków, usuń je tutaj.

Metoda getTile() działa jako główny kontroler do określania, które kafelki wczytywać w danym widocznym obszarze.

Typy map podstawowych

Tworzone w ten sposób typy map mogą występować samodzielnie lub łączyć się z innymi typami map w postaci nakładek. Samodzielne typy map są nazywane typami map podstawowych. Możesz chcieć, aby interfejs API traktował takie niestandardowe MapType jak każdy inny istniejący typ mapy podstawowej (ROADMAP, TERRAIN itp.). Aby to zrobić, dodaj niestandardowy MapType do właściwości mapTypes obiektu Map. Typ właściwości: MapTypeRegistry.

Ten kod tworzy podstawowy element MapType, który wyświetla współrzędne kafelków mapy i rysuje ich kontury:

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

Wypróbuj fragment

Typy map nakładanych

Niektóre typy map zostały zaprojektowane tak, aby działać nad istniejącymi typami map. Tego typu mapy mogą mieć przezroczyste warstwy wskazujące ciekawe miejsca lub prezentujące użytkownikowi dodatkowe dane.

W takich przypadkach typ mapy nie powinien być traktowany jako osobny element, ale jako nakładka. Aby to zrobić, możesz dodać typ mapy bezpośrednio do istniejącego obiektu MapType za pomocą właściwości overlayMapTypes Map. Ta właściwość zawiera MVCArray o wartości MapType. Wszystkie typy map (podstawowa i nakładka) są renderowane w warstwie mapPane. Typy nakładek map są wyświetlane na górze mapy podstawowej, do których są dołączone, w kolejności, w jakiej występują w tablicy Map.overlayMapTypes (nakładki z wyższymi wartościami indeksu są wyświetlane przed nakładkami z niższymi wartościami indeksu).

Poniższy przykład jest taki sam jak poprzedni, ale u góry mapy typu ROADMAP utworzyliśmy nakładkę z kafelkami MapType:

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

Wypróbuj fragment

Typy map obrazu

Wdrożenie obiektu MapType jako mapy podstawowej może być czasochłonne i pracochłonne. Interfejs API ma specjalną klasę, która implementuje interfejs MapType dla najpopularniejszych typów map: typów map, które składają się z kafelków złożonych z pojedynczych plików graficznych.

Ta klasa (klasa ImageMapType) jest tworzona przy użyciu 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 muszą być kwadratowe.
  • getTileUrl (wymagany) określa funkcję, zwykle dostarczaną jako literał funkcji wbudowanej, która obsługuje wybór odpowiedniego kafelka obrazu na podstawie podanych współrzędnych świata i poziomu powiększenia.

Ten kod implementuje podstawowy obiekt ImageMapType przy użyciu księżycowych kafelków Google. W tym przykładzie korzystamy z funkcji normalizacji, aby kafelki powtarzały się 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

Wypróbuj fragment

Prognozy

Ziemia jest trójwymiarową sferą (w przybliżeniu), a mapa to płaska, dwuwymiarowa powierzchnia. Mapa widoczna w interfejsie Maps JavaScript API, podobnie jak każda płaska mapa Ziemi, jest odwzorowaniem tej kuli na płaskiej 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 odwzorowania.

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

Implementacja projekcji

Implementując odwzorowanie niestandardowe musisz określić kilka rzeczy:

  • Wzór do mapowania szerokości i długości geograficznej na płaszczyźnie kartezjańskie i odwrotnie. (Interfejs Projection obsługuje tylko przekształcenia na współrzędne prostokątne).
  • Rozmiar kafelka podstawowego. Wszystkie kafelki muszą być prostokątne.
  • „Rozmiar świata” mapy z kafelkiem podstawowym ustawionym przy powiększeniu 0. Pamiętaj, że w przypadku map składających się z 1 kafelka w powiększeniu 0 wymiary świata są identyczne.

Koordynuj transformacje w projekcjach

Każde odwzorowanie udostępnia 2 metody tłumaczenia między tymi dwoma układami współrzędnych, co umożliwia konwersję ze współrzędnymi geograficznymi i światowych:

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

W Mapach Google założono, że odwzorowania są prostoliniowe.

Odwzorowanie może być przydatne w 2 przypadkach: aby utworzyć mapę świata lub mapę lokalnego obszaru. W pierwszym przypadku sprawdź, czy projekcja jest również prostokątna i normalna dla wszystkich długości geograficznej. Niektóre odwzorowania (zwłaszcza stożkowe) mogą być „lokalnie normalne” (tj.w kierunku północnym), ale odbiegać od rzeczywistej północy. Na przykład im bardziej dalej znajduje się mapa w stosunku do długości referencyjnej. Możesz wykorzystać takie odwzorowanie lokalnie, ale pamiętaj, że jest ono niedokładne, a błędy przekształcania będą coraz bardziej zauważalne im dalej od długości referencyjnej, którą odbiegasz od długości referencyjnej.

Wybór kafelków mapy w projekcjach

Odwzorowania przydają się nie tylko do określania pozycji lokalizacji lub nakładek, ale także do określania pozycji samych kafelków mapy. Interfejs Maps JavaScript API renderuje mapy podstawowe za pomocą interfejsu MapType, który wymaga zadeklarowania zarówno właściwości projection do identyfikacji odwzorowania mapy, jak i metody getTile() do pobierania elementów mapy na podstawie wartości współrzędnych fragmentu. Współrzędne kafelków zależą od podstawowego rozmiaru obszaru (który musi być prostokątny) oraz od „globalnego rozmiaru” mapy, czyli rozmiaru mapy w pikselach przy powiększeniu 0. (W przypadku map składających się z 1 kafelka w powiększeniu 0 wymiary są identyczne i identyczne).

Rozmiar kafelka podstawowego określasz we właściwości tileSize obiektu MapType. Rozmiar świata określasz domyślnie w metodach fromLatLngToPoint() i fromPointToLatLng() projekcji.

Wybór obrazów zależy od przekazanych wartości, dlatego warto nadawać nazwy obrazom, które można wybrać automatycznie na podstawie przekazanych wartości, np. map_zoom_tileX_tileY.png.

Ten przykład zawiera definicję obiektu ImageMapType za pomocą rzutu 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;
Zobacz przykład

Wypróbuj fragment