Typy map

Wybierz platformę: Android iOS JavaScript

W tym dokumencie omawiamy typy map, które możesz wyświetlać za pomocą interfejsu Maps JavaScript API. Do przechowywania informacji na temat tych map w interfejsie API używany jest obiekt MapType. MapTypeto interfejs, który definiuje wyświetlanie i używanie kafelków mapy oraz przekształcanie układów współrzędnych z układu ekranowego na układ globalny (na mapie). Każdy obiekt MapType musi zawierać kilka metod służących do pobierania i zwalniania płytek oraz właściwości określających ich zachowanie wizualne.

Zagadnienie działania typów map w interfejsie Maps JavaScript API jest zaawansowane. Większość deweloperów może korzystać z podstawowych typów map wymienionych poniżej. Możesz jednak zmodyfikować prezentację istniejących typów map za pomocą map stylizowanych lub zdefiniować własne płytki 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 „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. Jest to domyślny typ mapy.
  • satellite wyświetla zdjęcia satelitarne Google Earth.
  • hybrid wyświetla widok normalny i satelitarny.
  • terrain wyświetla mapę fizyczną opartą na informacjach o terenie.

Aby zmienić typ mapy używany przez Map, ustaw właściwość mapTypeId, ustawiając obiekt Map options w konstruktorze lub wywołując metodę setMapTypeId() mapy. Właściwość mapTypeID ma domyślnie wartość 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 nie ustawiasz bezpośrednio typu mapy, ale zamiast tego ustawiasz jej mapTypeId, aby odwoływać się do MapType za pomocą identyfikatora. Aby zarządzać tymi odwołaniami, interfejs Maps JavaScript API korzysta z rejestru typów map, którego opis znajdziesz poniżej.

Obrazy w kącie 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 głównych (północ, południe, wschód, zachód). Te obrazy są dostępne na wyższych poziomach powiększenia w przypadku obsługiwanych typów map.

Na tym obrazie widać Nowy Jork z perspektywy 45°:

Typy map satellitehybrid obsługują obrazy o kącie 45° przy dużych poziomach powiększenia (12 i większych), jeśli są dostępne. Jeśli użytkownik przybliży widok w miejscu, w którym dostępne są takie obrazy, te typy map automatycznie zmienią widok w ten sposób:

  • Zdjęcia satelitarne lub hybrydowe są zastępowane obrazami z perspektywy 45°, które są wyśrodkowane na bieżącej lokalizacji. Domyślnie takie widoki są zorientowane na północ. Jeśli użytkownik oddali obraz, ponownie pojawi się domyślny widok satelitarny lub hybrydowy. Zachowanie zależy od poziomu powiększenia i wartości tilt:
    • Na poziomach powiększenia 12–18 domyślnie wyświetlana jest mapa bazowa z lotu ptaka (0°), chyba że tilt jest ustawiony na 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.
  • Element sterujący obrotem staje się widoczny. Element sterujący obracaniem umożliwia użytkownikowi przełączanie pochylenia i obracanie widoku o 90° w dowolnym kierunku. Aby ukryć element sterujący obrotem, ustaw parametr 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ęć pod kątem 45°

Możesz wyłączyć obrazy pod kątem 45°, wywołując funkcję setTilt(0) obiektu Map. Aby włączyć obrazy pod kątem 45° w przypadku obsługiwanych typów map, zadzwoń pod numer setTilt(45). Metoda getTilt() obiektu Map zawsze odzwierciedla bieżącą wartość tilt wyświetlaną na mapie. Jeśli na mapie ustawisz wartość tilt, a potem ją usuniesz (np. przez oddalenie mapy), metoda getTilt() mapy zwróci wartość 0.

Ważne: obrazy o kącie 45° są obsługiwane tylko na mapach rastrowych. Nie można ich używać na mapach wektorowych.

Na przykładowym obrazie 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 próbkę

Zobacz przykład

Obracanie o 45°

Zdjęcia w kącie 45° to w istocie zbiór zdjęć dla każdego kierunku świata (północ, południe, wschód, zachód). Gdy mapa wyświetla obrazy pod kątem 45°, możesz ustawić kierunek obrazów, wywołując funkcję setHeading() obiektu Map, podając wartość liczbową wyrażoną w stopniach od północy.

Ten przykład pokazuje mapę lotniczą i automatyczne obracanie mapy 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 próbkę

Zobacz przykład

Modyfikowanie rejestru typów map

Identyfikator mapTypeId mapy to ciąg znaków służący do powiązania MapType z wartością unikalną. Każdy obiekt Map ma obiekt MapTypeRegistry, który zawiera zbiór dostępnych MapType dla danej mapy. Ten rejestr służy do wybierania typów map, które są dostępne na przykład w elemencie sterującym MapType mapy.

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żesz modyfikować ani zmieniać podstawowych typów map (chociaż możesz usunąć je z mapy, zmieniając wygląd powiązanego z nią elementu).mapTypeControlOptions

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 artykule Używanie wbudowanych deklaracji stylu JSON.

Niestandardowe typy map

Interfejs Maps JavaScript API obsługuje wyświetlanie i zarządzanie niestandardowymi typami map, co umożliwia implementowanie własnych obrazów mapy lub nakładek płytek.

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

  • standardowe zestawy kafli, które składają się z obrazów stanowiących razem pełne mapy kartograficzne; Te zestawy płytek są też nazywane podstawowymi typami map. 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 obiektu Map, aby umożliwić interfejsowi użytkownika w Maps JavaScript API traktowanie niestandardowego typu mapy jako standardowego typu mapy (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. Zazwyczaj te typy map służą do rozszerzenia istniejącego typu mapy o dodatkowe informacje i często są ograniczone do określonych lokalizacji lub poziomów powiększenia. Pamiętaj, że te elementy mogą być przezroczyste, co pozwoli Ci dodawać funkcje do istniejących map.
  • Typy map bez obrazu, które umożliwiają manipulowanie wyświetlaniem informacji na mapie na najbardziej podstawowym poziomie.

Każda z tych opcji wymaga utworzenia klasy, która implementuje interfejs MapType. Dodatkowo klasa ImageMapType zawiera wbudowane zachowanie, które upraszcza tworzenie map obrazkowych.

Interfejs MapType

Zanim utworzysz klasy, które implementują MapType, musisz zrozumieć, jak Mapy Google określają współrzędne i decydują, które części mapy mają być widoczne. Musisz zaimplementować podobną logikę dla wszystkich typów map bazowych lub nakładowych. Przeczytaj przewodnik dotyczący współrzędnych mapy i płytek.

Niestandardowe typy map muszą implementować interfejs MapType. Ten interfejs określa pewne właściwości i metody, które umożliwiają interfejsowi API inicjowanie żądań do Twojego typu mapy, gdy interfejs API stwierdzi, że musi wyświetlić elementy mapy w ramach bieżącego widoku i poziomu powiększenia. Przetwarzasz te żądania, aby zdecydować, która karta ma zostać załadowana.

Uwaga: aby zaimplementować ten interfejs, możesz utworzyć własną klasę. Jeśli masz zgodne obrazy, możesz 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, na 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ść to 0, co oznacza, że nie ma minimalnego poziomu powiększenia.
  • name (opcjonalnie) określa nazwę tego typu mapy. Ta właściwość jest wymagana tylko wtedy, gdy chcesz, aby ten typ mapy był dostępny do wyboru w elemencie sterującym MapType. Zobacz Opcje kontroli.
  • alt (opcjonalnie) określa tekst alternatywny dla tego typu mapy, wyświetlany jako tekst najechania 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 Opcje sterowania).

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

  • getTile() (wymagany) jest wywoływany za każdym razem, gdy interfejs API stwierdzi, że mapa musi wyświetlić nowe płytki dla danego widoku. Metoda getTile() musi mieć taki 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 MapType, minZoommaxZoom oraz bieżącego widoku mapy i poziomu powiększenia. Obsługa tej metody powinna zwracać element HTML na podstawie przekazanych współrzędnych, poziomu powiększenia i elementu DOM, do którego ma zostać dołączony obraz płytki.

  • releaseTile() (opcjonalnie) jest wywoływany za każdym razem, gdy interfejs API stwierdzi, że mapa musi usunąć kafelek, ponieważ zniknął z pola widzenia. Ta metoda musi mieć następującą sygnaturę:

    releaseTile(tile:Node)

    Zwykle należy usunąć wszystkie elementy, które zostały dołączone do elementów mapy po jej dodaniu. Jeśli na przykład dołączysz detektory zdarzeń do nakładek kafelków mapy, musisz je usunąć.

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

Typy map podstawowych

Typy map utworzone w ten sposób mogą występować samodzielnie lub w połączeniu z innymi typami map jako nakładki. Typy map samodzielnych to typy map podstawowych. Możesz chcieć, aby interfejs API traktował takie niestandardowe MapType jak dowolny inny istniejący typ mapy bazowej (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 bazę MapType, aby wyświetlać współrzędne płytki mapy i rysować kontury płytek:

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ładek mapy

Niektóre typy map są przeznaczone do stosowania na istniejących mapach. Takie mapy mogą mieć przezroczyste warstwy wskazujące ciekawe miejsca lub zawierające dodatkowe dane.

W takich przypadkach nie chcesz, aby typ mapy był traktowany jako osobny 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 usługa zawiera MVCArray elementów MapType. Wszystkie typy map (podstawowa i nakładka) są renderowane w warstwie mapPane. Typy nakładanych map są wyświetlane nad mapą podstawową, 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).

Ten przykład jest identyczny jak poprzedni, z tym że na mapie typu ROADMAP utworzyliśmy nakładkę płytek 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 próbkę

Typy map obrazów

Wdrożenie MapType jako mapy podstawowej może być czasochłonne i wymagające dużego nakładu pracy. Interfejs API udostępnia specjalną klasę, która implementuje interfejs MapType do najczęściej używanych typów map: typów map, które składają się z płytek utworzonych z pojedynczych plików z obrazami.

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ę, która zwykle jest podawana jako litera funkcji wbudowanej, aby umożliwić wybór odpowiedniej karty obrazu na podstawie podanych współrzędnych świata i poziomu powiększenia.

Poniższy kod implementuje podstawowy ImageMapType za pomocą kafelków księżyca Google. Przykład korzysta z funkcji normalizacji, aby zapewnić powtarzanie się płytek na osi x, ale nie na 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 próbkę

Prognozy

Ziemia jest kulą trójwymiarową (w przybliżeniu), a mapa jest płaską dwuwymiarową powierzchnią. Mapa wyświetlana w interfejsie Maps JavaScript API, podobnie jak każda płaska mapa Ziemi, jest projekcją kuli ziemskiej na płaską powierzchnię. Najprościej mówiąc, projekcja to mapowanie wartości szerokości i długości geograficznej na współrzędne na mapie.

Prognozy w Maps JavaScript API muszą implementować interfejs Projection. Implementacja Projection musi zapewniać nie tylko mapowanie z jednego układu współrzędnych na inny, ale też w obie strony. Oznacza to, że musisz zdefiniować sposób przekształcania współrzędnych Ziemi (obiekty LatLng) na system współrzędnych klasy Projection oraz z systemu współrzędnych światowych z powrotem na współrzędne Ziemi. Mapy Google korzystają z projekcji Mercatora do tworzenia map na podstawie danych geograficznych i przekształcania zdarzeń na mapie w współrzędne geograficzne. Możesz uzyskać tę projekcję, wywołując funkcję getProjection() w ramach Map (lub dowolnego standardowego typu bazy MapType). W większości przypadków wystarczy standardowa Projection, ale możesz też zdefiniować i używać własnych projekcji niestandardowych.

Wdrażanie prognozy

Podczas wdrażania projekcji niestandardowej musisz określić kilka kwestii:

  • wzory na mapowanie współrzędnych szerokości i długości geograficznej na płaszczyznę kartezjańską oraz odpowiadające im wzory na mapowanie z płaszczyzny kartezjańskiej na współrzędne szerokości i długości geograficznej; (interfejs Projection obsługuje tylko transformacje do współrzędnych prostokątnych).
  • Podstawowy rozmiar kafelka. Wszystkie kafelki muszą być prostokątne.
  • „Rozmiar świata” mapy przy użyciu podstawowego zestawu płytek 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.

Przekształcenia współrzędnych w projekcjach

Każda projekcja zawiera 2 metody, które umożliwiają przekształcanie między tymi dwoma systemami współrzędnych, co pozwala na konwersję współrzędnych geograficznych na współrzędne światowe i odwrotnie:

  • Metoda Projection.fromLatLngToPoint() konwertuje wartość LatLng na współrzędną świata. Ta metoda służy do umieszczania nakładek na mapie (oraz do umieszczania 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 projekcje (zwłaszcza projekcje stożkowe) mogą być „lokalnie normalne” (czyli wskazują na północ), ale odbiegają od prawdziwej północy; na przykład im dalej mapa jest umieszczona względem jakiejś długości geograficznej odniesienia. Możesz lokalnie używać takiej projekcji, ale pamiętaj, że jest ona nieprecyzyjna, a błędy związane z przekształceniem będą się zwiększać wraz z odchylaniem się od długości geograficznej odniesienia.

Wybór fragmentu mapy w prognozach

Projekcje są przydatne nie tylko do określania pozycji lokalizacji lub nakładek, ale też do pozycjonowania samych kafelków mapy. Interfejs Maps JavaScript API renderuje mapy podstawowe za pomocą interfejsu MapType, który musi deklarować zarówno właściwość projection do identyfikowania projekcji mapy, jak i metodę getTile() do pobierania elementów mapy na podstawie wartości pobranych współrzędnych. współrzędne kafelka są określane na podstawie podstawowego rozmiaru kafelka (który musi być prostokątny) oraz „wielkości świata” mapy, czyli rozmiaru świata mapy w poziomie powiększenia 0. (w przypadku map składających się z 1 płytki przy powiększeniu 0 rozmiar płytki i wielkość świata są identyczne).

Rozmiar podstawowej płytki definiujesz w przypadku właściwości tileSize w usługach MapType. Rozmiar świata jest zdefiniowany domyślnie w metodach fromLatLngToPoint()fromPointToLatLng() projekcji.

Ponieważ wybór obrazu zależy od tych wartości, warto nadać nazwy obrazom, które można wybrać programowo na podstawie tych wartości, np. map_zoom_tileX_tileY.png.

Poniższy przykład definiuje ImageMapType przy użyciu 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

Wypróbuj próbkę