Tipi di mappa

Seleziona la piattaforma: Android iOS JavaScript

Questo documento illustra i tipi di mappe che puoi visualizzare utilizzando l'API Maps JavaScript. L'API utilizza un oggetto MapType per conservare le informazioni su queste mappe. Un'MapType è un'interfaccia che definisce la visualizzazione e l'utilizzo dei riquadri della mappa e la traduzione dei sistemi di coordinate dalle coordinate sullo schermo alle coordinate del mondo (sulla mappa). Ogni MapType deve contenere alcuni metodi per gestire il recupero e il rilascio di riquadri e proprietà che ne definiscono il comportamento visivo.

I meccanismi interni dei tipi di mappa all'interno dell'API Maps JavaScript è un argomento avanzato. La maggior parte degli sviluppatori può utilizzare i tipi di mappe di base indicati di seguito. Tuttavia, puoi anche modificare la presentazione dei tipi di mappe esistenti utilizzando Mappe con stili applicati o definire riquadri di mappe personalizzati utilizzando i tipi di mappe personalizzate. Quando fornisci tipi di mappe personalizzati, devi capire come modificare il registro dei tipi di mappa della mappa.

Tipi di mappe di base

Nell'API Maps JavaScript sono disponibili quattro tipi di mappe. Oltre ai noti riquadri di mappe stradali "dipinte", l'API Maps JavaScript supporta anche altri tipi di mappe.

Nell'API Maps JavaScript sono disponibili i seguenti tipi di mappe:

  • roadmap mostra la visualizzazione della mappa stradale predefinita. Questo è il tipo di mappa predefinito.
  • satellite mostra immagini satellitari di Google Earth.
  • hybrid mostra una combinazione di viste normale e satellitare.
  • terrain mostra una mappa fisica basata su informazioni del rilievo.

Puoi modificare il tipo di mappa utilizzato da Map impostandone la proprietà mapTypeId all'interno del costruttore impostando l'oggetto Map options o chiamando il metodo setMapTypeId() della mappa. Per impostazione predefinita, la proprietà mapTypeID è roadmap.

Impostazione di mapTypeId al momento della costruzione:

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

Modifica di mapTypeId in modo dinamico:

map.setMapTypeId('terrain');

Tieni presente che in realtà non imposti direttamente il tipo di mappa della mappa, ma ne imposti invece mapTypeId in modo che faccia riferimento a un MapType utilizzando un identificatore. L'API Maps JavaScript utilizza un registro dei tipi di mappe, descritto di seguito, per gestire questi riferimenti.

Immagini a 45°

L'API Maps JavaScript supporta immagini speciali a 45° per determinate località. Queste immagini ad alta risoluzione forniscono viste prospettiche di ciascuna direzione cardinale (nord, sud, est, ovest). Queste immagini sono disponibili a livelli di zoom più elevati per i tipi di mappe supportati.

La seguente immagine mostra una vista in prospettiva a 45° di New York:

I tipi di mappe satellite e hybrid supportano immagini a 45° a livelli di zoom elevati (12 e superiori), se disponibili. Se l'utente aumenta lo zoom su una località per la quale sono presenti queste immagini, questi tipi di mappe alterano automaticamente la visualizzazione nel seguente modo:

  • Le immagini satellitari o ibride vengono sostituite da immagini con una prospettiva di 45° centrata sulla posizione corrente. Per impostazione predefinita, queste viste sono orientate verso il nord. Se l'utente diminuisce lo zoom, vengono visualizzate di nuovo le immagini satellitari o ibride predefinite. Il comportamento varia a seconda del livello di zoom e del valore di tilt:
    • Tra i livelli di zoom 12 e 18, per impostazione predefinita viene visualizzata la mappa base dall'alto verso il basso (0°), a meno che tilt non sia impostato su 45.
    • A livelli di zoom pari o superiori a 18, viene visualizzata la mappa base a 45°, a meno che tilt non sia impostato su 0.
  • Il controllo di rotazione diventa visibile. Il controllo Ruota fornisce opzioni che consentono all'utente di attivare/disattivare l'inclinazione e di ruotare la vista con incrementi di 90° in entrambe le direzioni. Per nascondere il controllo di rotazione, imposta rotateControl su false.

Lo zoom indietro su un tipo di mappa che mostra immagini a 45° annulla ognuna di queste modifiche, ripristinando i tipi di mappa originali.

Attivazione e disattivazione delle immagini a 45°

Puoi disattivare le immagini a 45° richiamando setTilt(0) sull'oggetto Map. Per attivare le immagini a 45° per i tipi di mappe supportati, chiama setTilt(45). Il metodo getTilt() di Map rispecchierà sempre l'attuale tilt mostrato sulla mappa; se imposti tilt su una mappa e poi rimuovi quel tilt (ad esempio riducendo lo zoom della mappa), il metodo getTilt() della mappa restituirà 0.

Importante: le immagini a 45° sono supportate solo sulle mappe raster; queste immagini non possono essere utilizzate con le mappe vettoriali.

L'esempio seguente mostra una vista a 45° di New York:

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;
Visualizza esempio

Prova Sample

Visualizza esempio.

Rotazione delle immagini di 45°

Le immagini a 45° sono in realtà una raccolta di immagini per ogni direzione cardinale (Nord, Sud, Est, Ovest). Una volta che la mappa mostra immagini a 45°, puoi orientarle verso una delle sue direzioni cardinali chiamando setHeading() sull'oggetto Map, passando un valore numerico espresso in gradi dal nord.

L'esempio seguente mostra una mappa aerea e la ruota automaticamente ogni 3 secondi quando si fa clic sul pulsante:

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;
Visualizza esempio

Prova Sample

Visualizza esempio.

Modifica del registro dei tipi di mappa

L'elemento mapTypeId di una mappa è un identificatore di stringa utilizzato per associare MapType a un valore univoco. Ogni oggetto Map mantiene un MapTypeRegistry contenente la raccolta di MapType disponibili per la mappa. Questo registro viene utilizzato per selezionare i tipi di mappe disponibili, ad esempio, nel controllo MapType di Map.

Non leggi direttamente dal registro dei tipi di mappe. Puoi invece modificare il registry aggiungendo tipi di mappe personalizzate e associandoli a un identificatore di stringa di tua scelta. Non puoi modificare o alterare i tipi di mappe di base (ma puoi rimuoverli dalla mappa cambiando l'aspetto dell'elemento mapTypeControlOptions associato della mappa).

Il seguente codice imposta la mappa in modo che mostri solo due tipi di mappa nel campo mapTypeControlOptions della mappa e modifica il registry per aggiungere l'associazione con questo identificatore all'implementazione effettiva dell'interfaccia 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);

Mappe con stile

L'StyledMapType consente di personalizzare la presentazione delle mappe base standard di Google, modificando la visualizzazione visiva di elementi come strade, parchi e aree densamente edificate in modo che riflettano uno stile diverso da quello utilizzato nel tipo di mappa predefinito.

Per ulteriori informazioni su StyledMapType, consulta la guida alle mappe con stili applicati.

Tipi di mappe personalizzate

L'API Maps JavaScript supporta la visualizzazione e la gestione di tipi di mappe personalizzate, consentendoti di implementare le tue immagini di mappe o i tuoi overlay di riquadri.

L'API Maps JavaScript esistono diverse possibili implementazioni di tipi di mappa:

  • Set di riquadri standard costituiti da immagini che costituiscono collettivamente mappe cartografiche complete. Questi insiemi di riquadri sono noti anche come tipi di mappe base. Questi tipi di mappe funzionano e si comportano come i tipi di mappe predefinite esistenti: roadmap, satellite, hybrid e terrain. Puoi aggiungere il tuo tipo di mappa personalizzata all'array mapTypes di una mappa per consentire all'UI all'interno dell'API Maps JavaScript di trattare il tipo di mappa personalizzata come un tipo di mappa standard (includendolo, ad esempio, nel controllo MapType).
  • Overlay del riquadro immagine visualizzati sopra i tipi di mappe base esistenti. In genere, questi tipi di mappe vengono utilizzati per integrare un tipo di mappa esistente al fine di visualizzare ulteriori informazioni e sono spesso vincolati a posizioni e/o livelli di zoom specifici. Tieni presente che questi riquadri possono essere trasparenti e ti consentono di aggiungere elementi a mappe esistenti.
  • Tipi di mappe non immagine, che consentono di manipolare la visualizzazione delle informazioni della mappa al suo livello più fondamentale.

Ognuna di queste opzioni si basa sulla creazione di una classe che implementa l'interfaccia MapType. Inoltre, la classe ImageMapType fornisce alcuni comportamenti integrati per semplificare la creazione dei tipi di mappe di immagini.

Interfaccia di MapType

Prima di creare classi che implementano MapType, è importante capire in che modo Google Maps determina le coordinate e decide quali parti della mappa mostrare. Devi implementare una logica simile per qualsiasi tipo di mappa di base o overlay. Leggi la guida alle coordinate di mappe e riquadri.

I tipi di mappe personalizzate devono implementare l'interfaccia MapType. Questa interfaccia specifica determinati metodi e proprietà che consentono all'API di avviare richieste ai tipi di mappa quando l'API determina che ha bisogno di visualizzare i riquadri della mappa all'interno dell'area visibile e del livello di zoom correnti. Sei tu a gestire queste richieste per decidere quale riquadro caricare.

Nota: puoi creare una tua classe per implementare questa interfaccia. In alternativa, se disponi di immagini compatibili puoi utilizzare la classe ImageMapType che implementa già questa interfaccia.

Le classi che implementano l'interfaccia MapType richiedono la definizione e la compilazione delle seguenti proprietà:

  • tileSize (obbligatorio) specifica le dimensioni del riquadro (di tipo google.maps.Size). Le dimensioni devono essere rettangolari anche se non devono essere quadrate.
  • maxZoom (obbligatorio) specifica il livello di zoom massimo al quale visualizzare i riquadri di questo tipo di mappa.
  • minZoom (facoltativo) specifica il livello di zoom minimo al quale visualizzare il riquadro di questo tipo di mappa. Per impostazione predefinita, questo valore è 0 e indica che non esiste un livello di zoom minimo.
  • name (facoltativo) specifica il nome di questo tipo di mappa. Questa proprietà è necessaria solo se vuoi che questo tipo di mappa sia selezionabile all'interno di un controllo MapType. (Vedi la sezione Aggiungere controlli MapType di seguito).
  • (Facoltativo) alt specifica il testo alternativo per questo tipo di mappa, mostrato come testo al passaggio del mouse. Questa proprietà è necessaria solo se vuoi che questo tipo di mappa sia selezionabile in un controllo MapType. (consulta la sezione Aggiungere controlli MapType di seguito).

Inoltre, le classi che implementano l'interfaccia MapType devono implementare i seguenti metodi:

  • getTile() (obbligatorio) viene chiamato ogni volta che l'API determina che la mappa deve visualizzare nuovi riquadri per l'area visibile in questione. Il metodo getTile() deve avere la seguente firma:

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

    L'API determina se deve chiamare getTile() in base alle proprietà tileSize, minZoom e maxZoom di MapType, nonché all'area visibile e al livello di zoom correnti della mappa. Il gestore per questo metodo deve restituire un elemento HTML una data coordinata passata, livello di zoom ed elemento DOM a cui aggiungere l'immagine riquadro.

  • releaseTile() (facoltativo) viene chiamato ogni volta che l'API determina che la mappa deve rimuovere un riquadro quando non è più visibile. Questo metodo deve avere la seguente firma:

    releaseTile(tile:Node)

    In genere, dovresti gestire la rimozione di tutti gli elementi allegati ai riquadri della mappa al momento dell'aggiunta alla mappa. Ad esempio, se hai allegato listener di eventi agli overlay riquadro della mappa, devi rimuoverli qui.

Il metodo getTile() funge da controller principale per determinare quali riquadri caricare all'interno di una determinata area visibile.

Tipi di mappe base

I tipi di mappe che crei in questo modo possono essere utilizzati singolarmente o combinati con altri tipi di mappe come overlay. I tipi di mappe autonomi sono noti come tipi di mappe base. Puoi fare in modo che l'API tratti questi MapType personalizzati come qualsiasi altro tipo di mappa base esistente (ROADMAP, TERRAIN e così via). Per farlo, aggiungi il tuo MapType personalizzato alla proprietà mapTypes di Map. Questa proprietà è di tipo MapTypeRegistry.

Il seguente codice crea un MapType di base per visualizzare le coordinate dei riquadri di una mappa e disegna il contorno dei riquadri:

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;
Visualizza esempio

Prova Sample

Tipi di mappe overlay

Alcuni tipi di mappe sono progettati per funzionare sopra i tipi di mappe esistenti. Questi tipi di mappe possono avere livelli trasparenti che indicano punti d'interesse o mostrano dati aggiuntivi all'utente.

In questi casi, non vuoi che il tipo di mappa venga considerato come un'entità separata, ma come un overlay. Puoi farlo aggiungendo direttamente il tipo di mappa a un MapType esistente utilizzando la proprietà overlayMapTypes di Map. Questa proprietà contiene un valore MVCArray di MapType. Tutti i tipi di mappa (di base e overlay) vengono visualizzati nel livello mapPane. I tipi di mappe overlay vengono visualizzati sopra la mappa base a cui sono associati, nell'ordine in cui appaiono nell'array Map.overlayMapTypes (gli overlay con valori di indice più elevati vengono visualizzati davanti agli overlay con valori di indice più bassi).

Il seguente esempio è identico al precedente, ma abbiamo creato un overlay riquadro MapType sopra il tipo di mappa ROADMAP:

TypeScript

/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */

class CoordMapType implements google.maps.MapType {
  tileSize: google.maps.Size;
  alt: string|null = null;
  maxZoom: number = 17;
  minZoom: number = 0;
  name: string|null = null;
  projection: google.maps.Projection|null = null;
  radius: number = 6378137;

  constructor(tileSize: google.maps.Size) {
    this.tileSize = tileSize;
  }
  getTile(
    coord: google.maps.Point,
    zoom: number,
    ownerDocument: Document
  ): HTMLElement {
    const div = ownerDocument.createElement("div");

    div.innerHTML = String(coord);
    div.style.width = this.tileSize.width + "px";
    div.style.height = this.tileSize.height + "px";
    div.style.fontSize = "10";
    div.style.borderStyle = "solid";
    div.style.borderWidth = "1px";
    div.style.borderColor = "#AAAAAA";
    return div;
  }
  releaseTile(tile: Element): void {}
}

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 10,
      center: { lat: 41.85, lng: -87.65 },
    }
  );

  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  const coordMapType = new CoordMapType(new google.maps.Size(256, 256))
  map.overlayMapTypes.insertAt(
    0,
    coordMapType
  );
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

/*
 * This demo illustrates the coordinate system used to display map tiles in the
 * API.
 *
 * Tiles in Google Maps are numbered from the same origin as that for
 * pixels. For Google's implementation of the Mercator projection, the origin
 * tile is always at the northwest corner of the map, with x values increasing
 * from west to east and y values increasing from north to south.
 *
 * Try panning and zooming the map to see how the coordinates change.
 */
class CoordMapType {
  tileSize;
  alt = null;
  maxZoom = 17;
  minZoom = 0;
  name = null;
  projection = null;
  radius = 6378137;
  constructor(tileSize) {
    this.tileSize = tileSize;
  }
  getTile(coord, zoom, ownerDocument) {
    const div = ownerDocument.createElement("div");

    div.innerHTML = String(coord);
    div.style.width = this.tileSize.width + "px";
    div.style.height = this.tileSize.height + "px";
    div.style.fontSize = "10";
    div.style.borderStyle = "solid";
    div.style.borderWidth = "1px";
    div.style.borderColor = "#AAAAAA";
    return div;
  }
  releaseTile(tile) {}
}

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 10,
    center: { lat: 41.85, lng: -87.65 },
  });
  // Insert this overlay map type as the first overlay map type at
  // position 0. Note that all overlay map types appear on top of
  // their parent base map.
  const coordMapType = new CoordMapType(new google.maps.Size(256, 256));

  map.overlayMapTypes.insertAt(0, coordMapType);
}

window.initMap = initMap;
Visualizza esempio

Prova Sample

Tipi di mappe immagine

L'implementazione di un MapType in modo che agisca come tipo di mappa base può essere un'attività laboriosa e dispendiosa in termini di tempo. L'API fornisce una classe speciale che implementa l'interfaccia MapType per i tipi di mappe più comuni: tipi di mappe costituiti da riquadri costituiti da file di immagine singola.

Questa classe, ImageMapType, è creata utilizzando una specifica dell'oggetto ImageMapTypeOptions che definisce le seguenti proprietà obbligatorie:

  • tileSize (obbligatorio) specifica le dimensioni del riquadro (di tipo google.maps.Size). Le dimensioni devono essere rettangolari anche se non devono essere quadrate.
  • getTileUrl (obbligatorio) specifica la funzione, solitamente fornita come valore letterale di funzione inline, per gestire la selezione del riquadro immagine appropriato in base alle coordinate del mondo e al livello di zoom forniti.

Il seguente codice implementa un ImageMapType di base utilizzando i riquadri lunari di Google. L'esempio utilizza una funzione di normalizzazione per garantire che i riquadri si ripetano lungo l'asse x, ma non lungo l'asse y della mappa.

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;
Visualizza esempio

Prova Sample

Proiezioni

La Terra è una sfera tridimensionale (approssimativamente), mentre una mappa è una superficie piana bidimensionale. La mappa visualizzata nell'API Maps JavaScript, come qualsiasi mappa piana della Terra, è una proiezione della sfera su una superficie piana. In parole povere, una proiezione può essere definita come una mappatura dei valori di latitudine/longitudine in coordinate sulla mappa della proiezione.

Le proiezioni nell'API Maps JavaScript devono implementare l'interfaccia Projection. Un'implementazione Projection non deve fornire solo una mappatura da un sistema di coordinate a un altro, ma una mappatura bidirezionale. In altre parole, devi definire come eseguire la traduzione dalle coordinate di Earth (LatLng oggetti) al sistema di coordinate mondiali della classe Projection e viceversa. Google Maps utilizza la proiezione di Mercatore per creare le proprie mappe a partire da dati geografici e convertire gli eventi sulla mappa in coordinate geografiche. Puoi ottenere questa proiezione richiamando getProjection() su Map (o uno qualsiasi dei tipi di MapType di base standard.) Per la maggior parte degli utilizzi, questo Projection standard è sufficiente, ma puoi anche definire e utilizzare proiezioni personalizzate.

Implementazione di una proiezione

Quando implementi una proiezione personalizzata, devi definire alcune cose:

  • Le formule per mappare le coordinate di latitudine e longitudine in un piano cartesiano e viceversa. L'interfaccia Projection supporta solo trasformazioni in coordinate rettilinei.
  • Le dimensioni del riquadro di base. Tutti i riquadri devono essere rettangolari.
  • Le "dimensioni del mondo" di una mappa utilizzando il riquadro base impostato a livello di zoom 0. Tieni presente che per le mappe costituite da un riquadro con zoom pari a 0, le dimensioni del mondo e le dimensioni dei riquadri di base sono identiche.

Coordina le trasformazioni nelle proiezioni

Ogni proiezione offre due metodi che traducono tra questi due sistemi di coordinate, consentendo la conversione da coordinate geografiche a coordinate mondiali:

  • Il metodo Projection.fromLatLngToPoint() converte un valore LatLng in una coordinata mondiale. Questo metodo viene utilizzato per posizionare gli overlay sulla mappa (e la mappa stessa).
  • Il metodo Projection.fromPointToLatLng() converte una coordinata globale in un valore LatLng. Questo metodo viene utilizzato per convertire in coordinate geografiche eventi come i clic che si verificano sulla mappa.

Google Maps presuppone che le proiezioni siano rettilinee.

In genere, puoi utilizzare una proiezione per due casi: per creare una mappa del mondo o per creare una mappa di un'area locale. Nel primo caso, devi assicurarti che la proiezione sia anche rettilinea e normale a tutte le longitudini. Alcune proiezioni (in particolare quelle coniche) possono essere "localmente normali" (ovvero il punto nord), ma deviare dal vero nord; ad esempio, più la mappa è posizionata rispetto a una certa longitudine di riferimento. Puoi utilizzare una proiezione di questo tipo in locale, ma tieni presente che la proiezione è necessariamente imprecisa e che gli errori di trasformazione compiranno sempre più spesso man mano che ti allontani dalla longitudine di riferimento che devi.

Selezione dei riquadri della mappa nelle proiezioni

Le proiezioni sono utili non solo per determinare le posizioni di località o overlay, ma anche per posizionare i riquadri della mappa stessi. L'API Maps JavaScript esegue il rendering delle mappe di base utilizzando un'interfaccia MapType, che deve dichiarare sia una proprietà projection per identificare la proiezione della mappa sia un metodo getTile() per recuperare i riquadri della mappa in base ai valori della coordinata dei riquadri. Le coordinate dei riquadri si basano sia sulle dimensioni dei riquadri di base (che devono essere rettangolari) sia sulle "dimensioni del mondo" della tua mappa, ovvero le dimensioni in pixel del mondo della mappa a livello di zoom 0. (Per mappe costituite da un riquadro con zoom pari a 0, le dimensioni del riquadro e le dimensioni del mondo sono identiche.)

Puoi definire le dimensioni del riquadro di base all'interno della proprietà tileSize di MapType. La dimensione del mondo viene definita in modo implicito nei metodi fromLatLngToPoint() e fromPointToLatLng() della proiezione.

Poiché la selezione delle immagini dipende da questi valori passati, è utile assegnare un nome alle immagini che possono essere selezionate in modo programmatico alla luce dei valori passati, come map_zoom_tileX_tileY.png.

L'esempio seguente definisce un ImageMapType utilizzando la proiezione di 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;
Visualizza esempio

Prova Sample