Tipi di mappa

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.
Seleziona piattaforma: Android iOS JavaScript

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

Il funzionamento interno dei tipi di mappa nell'API Maps JavaScript è un argomento avanzato. La maggior parte degli sviluppatori può utilizzare i tipi di mappa di base indicati di seguito. Tuttavia, puoi anche modificare la presentazione di tipi di mappa esistenti utilizzando Mappe con stile o definire riquadri di mappa personalizzati utilizzando i tipi di mappa personalizzati. Quando fornisci tipi di mappe personalizzati, devi capire come modificare il registro di tipi di mappe.

Tipi di mappe di base

Nell'API Maps JavaScript sono disponibili quattro tipi di mappe. Oltre ai consueti riquadri della mappa stradale "dipinti", l'API Maps JavaScript supporta anche altri tipi di mappe.

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

  • roadmap mostra la visualizzazione predefinita della mappa stradale. Questo è il tipo di mappa predefinito.
  • satellite mostra le immagini satellitari di Google Earth.
  • hybrid mostra un mix di visualizzazioni normali e satellitari.
  • terrain mostra una mappa fisica basata sulle informazioni del rilievo.

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

Impostazione del mapTypeId in fase di 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 non imposti direttamente il tipo di mappa della mappa, ma imposti mapTypeId per fare riferimento a un MapType utilizzando un identificatore. L'API Maps JavaScript utilizza un registro dei tipi di mappa, illustrato di seguito, per gestire questi riferimenti.

Immagini a 45°

L'API Maps JavaScript supporta immagini speciali a 45° per alcune località. Queste immagini ad alta risoluzione offrono visualizzazioni prospettiche verso ciascuna delle direzioni cardiache (Nord, Sud, Est, Ovest). Queste immagini sono disponibili con livelli di zoom più elevati per i tipi di mappe supportati.

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

I tipi di mappa satellite e hybrid supportano le immagini a 45° con livelli di zoom elevati (12 o superiori), se disponibili. Se l'utente esegue lo zoom su una località per la quale esistono tali immagini, questi tipi di mappa alterano automaticamente le proprie visualizzazioni nel seguente modo:

  • Le immagini satellitari o ibride vengono sostituite da immagini che offrono una prospettiva di 45° centrata sulla posizione corrente. Per impostazione predefinita, queste viste sono orientate verso nord. Se l'utente riduce lo zoom, vengono mostrate 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 viene visualizzata per impostazione predefinita la mappa base dall'alto verso il basso (0°), a meno che tilt non sia impostato su 45.
    • A livelli di zoom di 18 o superiori, la mappa di base di 45° viene visualizzata, a meno che tilt non sia impostato su 0.
  • Il controllo di rotazione diventa visibile. Il controllo di rotazione offre 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.

Per diminuire lo zoom di un tipo di mappa che mostra immagini a 45°, puoi annullare ciascuna di queste modifiche ripristinando i tipi di mappa originali.

Attivazione e disattivazione delle immagini a 45°

Puoi disattivare le immagini a 45° chiamando setTilt(0) per l'oggetto Map. Per attivare le immagini a 45° per i tipi di mappa supportati, chiama setTilt(45). Il metodo getTilt() di Map rifletterà sempre l'attuale tilt visualizzato sulla mappa; se imposti una tilt su una mappa e poi rimuovi la località 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 radar; 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 anteprima

Visualizza esempio.

Rotazione delle immagini a 45°

Le immagini a 45° sono in realtà una raccolta di immagini per ciascuna direzione cardinale (Nord, Sud, Est, Ovest). Quando la mappa mostra immagini a 45°, puoi orientarla verso una delle sue direzioni cardiache chiamando setHeading() sull'oggetto Map, trasmettendo un valore numerico espresso in gradi da 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 anteprima

Visualizza esempio.

Modifica del registro dei tipi di mappa

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

Non leggi direttamente dal registro dei tipi di mappa. Puoi modificare il registro aggiungendo tipi di mappe personalizzati e associandoli a un identificatore di stringa di tua scelta. Non puoi modificare né modificare i tipi di mappa di base (anche se puoi rimuoverli dalla mappa modificando l'aspetto dei mapTypeControlOptions associati della mappa).

Il seguente codice imposta la mappa in modo che mostri solo due tipi di mappa nel mapTypeControlOptions della mappa e modifica il registro 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

StyledMapType ti consente di personalizzare la presentazione delle mappe base di Google standard, cambiando la visualizzazione visiva di elementi come strade, parchi e aree edificate per riflettere uno stile diverso da quello utilizzato nel tipo di mappa predefinito.

Per scoprire di più su StyledMapType, consulta la guida alle mappe con stile.

Tipi di mappe personalizzate

L'API Maps JavaScript supporta la visualizzazione e la gestione di tipi di mappe personalizzate, consentendo di implementare immagini di mappa o overlay di riquadri personalizzati.

All'interno dell'API Maps JavaScript sono disponibili diverse implementazioni possibili per i tipi di mappa:

  • Set di riquadri standard costituiti da immagini che costituiscono collettivamente mappe cartografiche complete. Questi set di riquadri sono noti anche come tipi di mappa base. Questi tipi di mappa si comportano e si comportano come i tipi di mappa predefiniti esistenti: roadmap, satellite, hybrid e terrain. Puoi aggiungere il tuo tipo di mappa personalizzata a un array mapTypes di una mappa per consentire alla UI all'interno dell'API Maps JavaScript di trattare il tuo tipo di mappa personalizzato come un tipo di mappa standard (includendolo nel controllo MapType, ad esempio).
  • Riquadri a mosaico di immagini visualizzati sopra i tipi di mappa base esistenti. In genere, questi tipi di mappa vengono utilizzati per integrare un tipo di mappa esistente per mostrare informazioni aggiuntive e sono spesso vincolati a posizioni specifiche e/o a livelli di zoom. Tieni presente che questi riquadri possono essere trasparenti, permettendoti di aggiungere funzionalità alle mappe esistenti.
  • Tipi di mappe non immagine che consentono di manipolare la visualizzazione delle informazioni sulla mappa al livello più importante.

Ognuna di queste opzioni si basa sulla creazione di una classe che implementa l'interfaccia MapType. Inoltre, la classe ImageMapType fornisce un comportamento integrato per semplificare la creazione dei tipi di mappe immagine.

L'interfaccia di MapType

Prima di creare classi che implementano MapType, è importante comprendere in che modo Google Maps determina le coordinate e decidere quali parti della mappa mostrare. Devi implementare una logica simile per qualsiasi tipo di mappa 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 alcune proprietà e alcuni metodi che consentono all'API di avviare richieste ai tipi di mappe quando determinano che devono visualizzare i riquadri della mappa all'interno dell'area visibile e del livello di zoom correnti. sei tu a gestire le richieste per decidere quale riquadro caricare.

Nota: per creare questa interfaccia, puoi creare la tua classe. 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 di definire e completare le 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 massimo di zoom su cui visualizzare i riquadri di questo tipo di mappa.
  • minZoom (facoltativo) specifica il livello minimo di zoom con cui visualizzare il riquadro di questo tipo di mappa. Per impostazione predefinita, questo valore è 0, che indica che non esiste alcun livello di zoom minimo.
  • name (facoltativo) specifica il nome per questo tipo di mappa. Questa proprietà è necessaria solo se vuoi che questo tipo di mappa sia selezionabile all'interno di un controllo MapType. (consulta la sezione Aggiungere i controlli MapType di seguito).
  • alt (facoltativo) specifica il testo alternativo per questo tipo di mappa, mostrato come testo mostrato al passaggio del mouse. Questa proprietà è necessaria solo se vuoi che questo tipo di mappa sia selezionabile all'interno di un controllo MapType. (consulta la sezione Aggiungere MapType controlli di seguito).

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

  • getTile() (obbligatorio) viene richiamato ogni volta che l'API determina che la mappa deve visualizzare nuovi riquadri per l'area visibile specificata. 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 dell'MapType e all'area visibile corrente e al livello di zoom della mappa. Il gestore per questo metodo dovrebbe restituire un elemento HTML con una coordinata passata, un livello di zoom e un elemento DOM su cui aggiungere l'immagine riquadro.

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

    releaseTile(tile:Node)

    In genere devi gestire la rimozione di tutti gli elementi allegati ai riquadri della mappa dopo l'aggiunta alla mappa. Ad esempio, se hai collegato i listener di eventi per mappare gli overlay di riquadro, 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 di base

I tipi di mappa che crei in questo modo possono essere indipendenti o essere combinati con altri tipi di mappe come overlay. I tipi di mappa autonomi sono noti come tipi di mappa base. Potrebbe essere opportuno che l'API tratti tali MapType personalizzati come qualsiasi altro tipo di mappa base esistente (ROADMAP, TERRAIN e così via). A tale scopo, aggiungi il tuo MapType personalizzato alla proprietà mapTypes di Map. Questa proprietà è di tipo MapTypeRegistry.

Il codice seguente crea una base MapType per visualizzare le coordinate dei riquadri di una mappa e disegna un 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 anteprima

Tipi di mappa in overlay

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

In questi casi, non vuoi che il tipo di mappa venga considerato come un'entità a parte, ma come overlay. Puoi farlo aggiungendo il tipo di mappa a una proprietà MapType esistente utilizzando la proprietà overlayMapTypes di Map. Questa proprietà contiene MVCArray di MapType. Tutti i tipi di mappa (base e overlay) vengono visualizzati all'interno del livello mapPane. I tipi di mappa di overlay verranno visualizzati sopra la mappa di base alla quale sono collegati, nell'ordine in cui sono visualizzati nell'array di Map.overlayMapTypes (gli overlay con valori di indicizzazione più elevati vengono visualizzati davanti agli overlay con valori di indicizzazione più bassi).

L'esempio seguente è identico a quello precedente tranne per il fatto che abbiamo creato un overlay di riquadri 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 anteprima

Tipi di mappe immagine

L'implementazione di un MapType come tipo di mappa base può essere un'attività lunga e laboriosa. L'API fornisce una classe speciale che implementa l'interfaccia MapType per i tipi di mappa più comuni: tipi di mappa costituiti da riquadri costituiti da singoli file immagine.

Questa classe, la classe ImageMapType, è creata utilizzando una specifica di 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, generalmente fornita come valore letterale di una funzione in linea, per gestire la selezione del riquadro dell'immagine corretto in base alle coordinate del mondo e al livello di zoom forniti.

Il codice seguente 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 anteprima

Proiezioni

La Terra è una sfera tridimensionale (circa), mentre una mappa è una superficie piana bidimensionale. La mappa che vedi all'interno dell'API Maps JavaScript, come qualsiasi mappa piatta della Terra, è una proiezione di quella sfera su una superficie piana. In termini semplici, 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 di Projection deve fornire non solo una mappatura da un sistema di coordinate a un altro, ma una mappatura bidirezionale. In altre parole, devi definire come tradurre dalle coordinate di Earth (LatLng oggetti) al sistema di coordinate globali della classe Projection e viceversa. Google Maps utilizza la proiezione di Mercator per creare mappe con i dati geografici e convertire gli eventi sulla mappa in coordinate geografiche. Puoi ottenere questa proiezione chiamando getProjection() su Map (o su qualsiasi tipo di base MapType standard). Per la maggior parte degli utilizzi, è sufficiente questo Projection standard, ma puoi anche definire e utilizzare le tue proiezioni personalizzate.

Implementazione di una proiezione

Quando implementi una proiezione personalizzata, devi definire alcune cose:

  • La formula per mappare le coordinate di latitudine e longitudine in un piano cartesiano e viceversa. (L'interfaccia Projection supporta solo le trasformazioni in coordinate rettangolari).
  • La dimensione del riquadro di base. Tutti i riquadri devono essere rettangolari.
  • Le "dimensioni del mondo" di una mappa utilizzando il riquadro di base impostato al livello di zoom 0. Tieni presente che per le mappe composte da un riquadro con zoom 0, le dimensioni globali e le dimensioni a mosaico di base sono identiche.

Trasformazione delle coordinate nelle proiezioni

Ogni proiezione offre due metodi che si traducono tra questi due sistemi di coordinate, permettendoti di convertire le coordinate geografiche e il mondo:

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

Google Maps presume che le proiezioni siano rettangolari.

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 anche la proiezione sia rettilinea e normale a tutte le lunghezze. Alcune proiezioni (soprattutto coniche) possono essere "localmente normale" (ossia punto nord) ma deviare da nord nord; ad esempio, più la mappa è posizionata rispetto a una certa longitudine di riferimento. Puoi utilizzare tale proiezione a livello locale, ma tieni presente che tale proiezione è necessariamente imprecisa e che gli errori di trasformazione diventeranno sempre più evidente man mano che si allontana la longitudine di riferimento.

Selezione riquadri mappa in proiezioni

Le proiezioni non sono utili solo per determinare la posizione delle posizioni o degli 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 delle coordinate a mosaico. Le coordinate dei riquadri si basano sia sulla dimensione del riquadro di base (che deve essere rettangolare) sia sul "mondo" della mappa, ovvero le dimensioni del pixel del mondo al livello di zoom 0. (per le mappe composte da un riquadro con zoom 0, le dimensioni del riquadro e quelle del mondo sono identiche).

Puoi definire le dimensioni del riquadro di base all'interno della proprietà tileSize di MapType. Puoi definire le dimensioni del mondo in modo implicito all'interno dei 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 date quei valori passati, come map_zoom_tileX_tileY.png.

L'esempio seguente definisce un ImageMapType che utilizza la proiezione Gall-Peter:

TypeScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection

function initMap(): void {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 0,
      center: { lat: 0, lng: 0 },
      mapTypeControl: false,
    }
  );

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

  // Show the lat and lng under the mouse cursor.
  const coordsDiv = document.getElementById("coords") as HTMLElement;

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event: google.maps.MapMouseEvent) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng!.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng!.lng());
  });

  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name"),
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;

      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;

      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";

      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });

  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));

      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap
      );
    },
  };
}

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

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

JavaScript

// This example defines an image map type using the Gall-Peters
// projection.
// https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection
function initMap() {
  // Create a map. Use the Gall-Peters map type.
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 0,
    center: { lat: 0, lng: 0 },
    mapTypeControl: false,
  });

  initGallPeters();
  map.mapTypes.set("gallPeters", gallPetersMapType);
  map.setMapTypeId("gallPeters");

  // Show the lat and lng under the mouse cursor.
  const coordsDiv = document.getElementById("coords");

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(coordsDiv);
  map.addListener("mousemove", (event) => {
    coordsDiv.textContent =
      "lat: " +
      Math.round(event.latLng.lat()) +
      ", " +
      "lng: " +
      Math.round(event.latLng.lng());
  });
  // Add some markers to the map.
  map.data.setStyle((feature) => {
    return {
      title: feature.getProperty("name"),
      optimized: false,
    };
  });
  map.data.addGeoJson(cities);
}

let gallPetersMapType;

function initGallPeters() {
  const GALL_PETERS_RANGE_X = 800;
  const GALL_PETERS_RANGE_Y = 512;

  // Fetch Gall-Peters tiles stored locally on our server.
  gallPetersMapType = new google.maps.ImageMapType({
    getTileUrl: function (coord, zoom) {
      const scale = 1 << zoom;
      // Wrap tiles horizontally.
      const x = ((coord.x % scale) + scale) % scale;
      // Don't wrap tiles vertically.
      const y = coord.y;

      if (y < 0 || y >= scale) return "";
      return (
        "https://developers.google.com/maps/documentation/" +
        "javascript/examples/full/images/gall-peters_" +
        zoom +
        "_" +
        x +
        "_" +
        y +
        ".png"
      );
    },
    tileSize: new google.maps.Size(GALL_PETERS_RANGE_X, GALL_PETERS_RANGE_Y),
    minZoom: 0,
    maxZoom: 1,
    name: "Gall-Peters",
  });
  // Describe the Gall-Peters projection used by these tiles.
  gallPetersMapType.projection = {
    fromLatLngToPoint: function (latLng) {
      const latRadians = (latLng.lat() * Math.PI) / 180;
      return new google.maps.Point(
        GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360),
        GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians))
      );
    },
    fromPointToLatLng: function (point, noWrap) {
      const x = point.x / GALL_PETERS_RANGE_X;
      const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y));
      return new google.maps.LatLng(
        (Math.asin(1 - 2 * y) * 180) / Math.PI,
        -180 + 360 * x,
        noWrap
      );
    },
  };
}

// GeoJSON, describing the locations and names of some cities.
const cities = {
  type: "FeatureCollection",
  features: [
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-87.65, 41.85] },
      properties: { name: "Chicago" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-149.9, 61.218] },
      properties: { name: "Anchorage" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-99.127, 19.427] },
      properties: { name: "Mexico City" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [-0.126, 51.5] },
      properties: { name: "London" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [28.045, -26.201] },
      properties: { name: "Johannesburg" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [15.322, -4.325] },
      properties: { name: "Kinshasa" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [151.207, -33.867] },
      properties: { name: "Sydney" },
    },
    {
      type: "Feature",
      geometry: { type: "Point", coordinates: [0, 0] },
      properties: { name: "0°N 0°E" },
    },
  ],
};

window.initMap = initMap;
Visualizza esempio

Prova anteprima