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.

Wewnętrzne działanie typów map w interfejsie Maps JavaScript API to zaawansowany temat. 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ą typów map niestandardowych. 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” kafelkó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 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.

Ustawianie mapTypeId podczas tworzenia:

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

Modyfikowanie mapTypeId dynamicznie:

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 pod kątem 45°

Interfejs Maps JavaScript API obsługuje specjalne zdjęcia pod kątem 45° w przypadku niektórych lokalizacji. Te zdjęcia w wysokiej rozdzielczości zawierają widoki perspektywiczne w każdym kierunku geograficznym (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ą widoki 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 18 lub większym wyświetlana jest mapa bazowa 45°, chyba że parametr tilt ma wartość 0.
  • Element sterujący obrotem staje się widoczny. Element sterujący obracaniem umożliwia użytkownikowi przełączanie przechylenia oraz obracanie widoku o 90° w dowolnym kierunku. Aby ukryć element sterujący obrotem, ustaw parametr rotateControl na false.

Powiększenie obrazu z mapy wyświetlającej obrazy pod kątem 45° spowoduje cofnięcie wszystkich tych zmian i przywrócenie pierwotnych typów map.

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

Możesz wyłączyć obrazy w kącie 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 tilt, a potem usuniesz tę wartość (np. przez oddalenie mapy), metoda getTilt() mapy zwróci wartość 0.tilt

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 na danej mapie. 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 powiązując je z wybranym przez siebie ciągiem znaków. 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

Poniższy kod powoduje, że na mapie będą widoczne tylko 2 typy map w układzie mapTypeControlOptions mapy i zmodyfikuje 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

Opcja StyledMapType umożliwia dostosowywanie wyświetlania standardowych map bazowych Google, zmieniając wizualny wygląd takich elementów, jak drogi, parki i obszary zabudowane, tak aby odzwierciedlał inny styl niż ten 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 zachowują się tak samo 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 elementach sterujących MapType).
  • Nakładki z kafelkami obrazu, które wyświetlają się na wierzchu istniejących typów map bazowych. 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 płytki mogą być przezroczyste, co pozwoli Ci dodawać funkcje do istniejących map.
  • Typy map bez obrazu, które umożliwiają manipulowanie 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 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, na którym ma być wyświetlana płytka 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 sterowania).
  • 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 był dostępny do wyboru 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.tileSize 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 kafelka.

  • 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 elementy mają być wczytane w danym widocznym obszarze.

Typy mapy podstawowej

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 niestandardowy element MapType do usługi mapTypes w kontekście usługi Map. Ta usługa jest typu MapTypeRegistry.

Poniższy kod tworzy bazę MapType, aby wyświetlać współrzędne płytki mapy, i rysuje kontur 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

Wypróbuj próbkę

Typy nakładek mapy

Niektóre typy map są przeznaczone do stosowania na istniejących mapach. Takie mapy mogą zawierać przezroczyste warstwy wskazujące punkty zainteresowania lub dodatkowe dane dla użytkownika.

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ącej MapType bezpośrednio za pomocą właściwości overlayMapTypes usługi Map. Ta usługa zawiera MVCArray elementów MapType. Wszystkie typy map (podstawowa i nakładka) są renderowane w warstwie mapPane. Typy map nakładek będą 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 większych wartościach indeksu będą wyświetlane przed nakładkami o mniejszych 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 mapy obrazkowej

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.

Ta klasa, klasa ImageMapType, jest tworzona za pomocą specyfikacji obiektu ImageMapTypeOptions, która definiuje 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ę, 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 to płaska, dwuwymiarowa powierzchnia. 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 projekcji.

Projekcje w interfejsie 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 używają 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 projekcja Projection, ale możesz też zdefiniować i stosować własne projekcje niestandardowe.

Implementacja 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ń 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 płytki 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 składających się z 1 płytki przy powiększeniu 0 rozmiar świata i rozmiar płytki podstawowej 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 projekcje są prostoliniowe.

Projekcję można zastosować w 2 przypadkach: do tworzenia mapy świata lub mapy lokalnego obszaru. W pierwszym przypadku musisz zadbać o to, aby projekcja była też prostoliniowa i normalna 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 koordynat elementu mapy. współrzędne klocka są określane na podstawie zarówno podstawowego rozmiaru klocka (który musi być prostokątny), jak i „wielkości świata” mapy, czyli rozmiaru w pikselach świata mapy na 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.

W tym przykładzie definiujemy ImageMapType za pomocą rzutowania Gall-Petersa:

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ę