Questo documento illustra i tipi di mappe che puoi visualizzare utilizzando l'API Maps JavaScript. L'API usa un oggetto MapType che contiene le informazioni su queste mappe. Un MapType è un'interfaccia che definisce la visualizzazione e l'utilizzo dei riquadri della mappa e la conversione 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, nonché 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 dei tipi di mappa esistenti utilizzando le mappe con stili o definire i tuoi riquadri di mappa utilizzando tipi di mappa personalizzati. Quando fornisci tipi di mappa 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 familiari riquadri della mappa stradale "disegnata", l'API Maps JavaScript supporta anche altri tipi di mappe.
Nell'API Maps JavaScript sono disponibili i seguenti tipi di mappa:
roadmapmostra la visualizzazione predefinita della mappa stradale con le etichette della mappa base.satellitemostra una mappa fotorealistica basata su immagini aeree.hybridmostra la visualizzazione della mappa satellitare con le etichette della mappa base.terrainmostra una mappa fisica basata sulle informazioni dei rilievi.
Puoi modificare il tipo di mappa utilizzato da Map impostando la relativa proprietà mapTypeId, all'interno del costruttore impostando l'oggetto Map options o chiamando il metodo setMapTypeId() della mappa. Il valore predefinito della proprietà mapTypeID è roadmap.
Impostazione di mapTypeId al momento della creazione:
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 dinamica di mapTypeId:
map.setMapTypeId('terrain');
Tieni presente che non imposti direttamente il tipo di mappa, ma imposti il relativo mapTypeId in modo che faccia riferimento a un MapType utilizzando un identificatore.
L'API Maps JavaScript utilizza un registro dei tipi di mappa, spiegato di seguito, per gestire questi riferimenti.
3D Maps
L'API Maps JavaScript supporta le immagini 3D. Molte delle azioni e delle funzionalità di personalizzazione disponibili per le mappe 2D sono disponibili anche per le mappe 3D.
Scopri di più sulle mappe 3D nella panoramica delle mappe 3D.
L'esempio seguente mostra una vista prospettica 3D di San Francisco:
Scopri di più su 3D Maps nella panoramica di 3D Maps.
Immagini a 45° (deprecate)
L'esempio seguente mostra come ottenere una vista prospettica a 45° di San Francisco utilizzando le mappe 3D:
TypeScript
async function init() { const { Map3DElement } = await google.maps.importLibrary('maps3d'); const map = new Map3DElement({ center: { lat: 37.789, lng: -122.401, altitude: 0, }, range: 2200, tilt: 45, heading: 188, }); map.mode = 'SATELLITE'; document.body.append(map); } void init();
JavaScript
async function init() { const { Map3DElement } = await google.maps.importLibrary('maps3d'); const map = new Map3DElement({ center: { lat: 37.789, lng: -122.401, altitude: 0, }, range: 2200, tilt: 45, heading: 188, }); map.mode = 'SATELLITE'; document.body.append(map); } void init();
CSS
/* * Always set the map height explicitly to define the size of the div element * that contains the map. */ #gmp-map-3d { height: 100%; } html, body { height: 100%; margin: 0; padding: 0; }
HTML
<html>
<head>
<title>3d map 45-degree perspective</title>
<link rel="stylesheet" type="text/css" href="./style.css" />
<script type="module" src="./index.js"></script>
<script>
// prettier-ignore
(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
key: "GOOGLE_MAPS_API_KEY"
});
</script>
</head>
<body>
<div id="map"></div>
</body>
</html>Modifica il registro dei tipi di mappa
L'mapTypeId di una mappa è un identificatore di stringa utilizzato per associare un MapType a un valore univoco. Ogni oggetto Map gestisce un
MapTypeRegistry che contiene la raccolta di
MapType disponibili per la mappa. Questo registro viene utilizzato, ad esempio, per selezionare i tipi di mappe disponibili nel controllo MapType della mappa.
Non leggi direttamente dal registro dei tipi di mappa. Invece,
modifichi il registro aggiungendo tipi di mappa personalizzati e associandoli
a un identificatore di stringa di tua scelta. Non puoi modificare o alterare i tipi di mappa di base, anche se puoi rimuoverli dalla mappa modificando l'aspetto del mapTypeControlOptions associato alla 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 standard di Google, modificando la visualizzazione di elementi come strade, parchi e aree edificate per riflettere uno stile diverso da quello utilizzato nel tipo di mappa predefinito. StyledMapType influisce solo sul tipo di mappa roadmap predefinito.
Per ulteriori informazioni su StyledMapType, consulta
Utilizzo delle dichiarazioni di stile JSON incorporate.
Tipi di mappe personalizzate
L'API Maps JavaScript supporta la visualizzazione e la gestione di tipi di mappa personalizzati, consentendoti di implementare le tue immagini della mappa o i tuoi overlay di riquadri.
Nell'API Maps JavaScript esistono diverse possibili implementazioni dei tipi di mappa:
- Set di riquadri standard costituiti da immagini che collettivamente costituiscono mappe cartografiche complete. Questi set di riquadri sono noti anche come tipi di mappa base. Questi tipi di mappa agiscono e si comportano come i tipi di mappa predefiniti esistenti:
roadmap,satellite,hybrideterrain. Puoi aggiungere il tuo tipo di mappa personalizzato all'arraymapTypesdi una mappa per consentire alla UI dell'API Maps JavaScript di trattare il tipo di mappa personalizzato come un tipo di mappa standard (ad esempio includendolo nel controllo MapType). - Overlay di riquadri di immagini visualizzati sopra i tipi di mappa base esistenti. In genere, questi tipi di mappa vengono utilizzati per potenziare un tipo di mappa esistente per visualizzare informazioni aggiuntive e sono spesso limitati a località e/o livelli di zoom specifici. Tieni presente che questi riquadri possono essere trasparenti, consentendoti di aggiungere elementi alle mappe esistenti.
- Tipi di mappa non basati su mappe immagine, che ti consentono di manipolare la visualizzazione delle informazioni sulla mappa al livello più elementare.
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 di tipi di mappa immagine.
L'interfaccia 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 tutti i tipi di mappa di base o overlay.
Leggi la guida alle coordinate della mappa e dei riquadri.
I tipi di mappa personalizzati devono implementare l'interfaccia MapType. Questa interfaccia specifica determinate proprietà e metodi che consentono all'API di avviare richieste ai tuoi tipi di mappa quando l'API determina che deve 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 la tua classe per implementare questa interfaccia. In alternativa, se hai immagini compatibili, puoi utilizzare la classe
ImageMapType che implementa già questa interfaccia.
Le classi che implementano l'interfaccia MapType richiedono di definire e compilare le seguenti proprietà:
tileSize(obbligatorio) specifica le dimensioni del riquadro (di tipogoogle.maps.Size). Le dimensioni devono essere rettangolari, anche se non necessariamente quadrate.maxZoom(obbligatorio) specifica il livello di zoom massimo a cui 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, il che 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. (Consulta la sezione Opzioni di controllo.)alt(facoltativo) specifica il testo alternativo per questo tipo di mappa, visualizzato come testo di 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 Opzioni di controllo.
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 specificata. Il metodogetTile()deve avere la seguente firma:getTile(tileCoord:Point,zoom:number,ownerDocument:Document):NodeL'API determina se deve chiamare
getTile()in base alle proprietàtileSize,minZoomemaxZoomdiMapTypee all'area visibile e al livello di zoom correnti della mappa. Il gestore di questo metodo deve restituire un elemento HTML in base a una coordinata, un livello di zoom e un elemento DOM passati su cui aggiungere l'immagine del riquadro. -
releaseTile()(facoltativo) viene chiamato ogni volta che l'API determina che la mappa deve rimuovere un riquadro perché non è più visibile. Questo metodo deve avere la seguente firma:releaseTile(tile:Node)In genere, devi gestire la rimozione di tutti gli elementi che sono stati collegati ai riquadri della mappa al momento dell'aggiunta alla mappa. Ad esempio, se hai collegato listener di eventi agli overlay di tile della mappa, devi rimuoverli qui.
Il metodo getTile() funge da controller principale per determinare quali riquadri caricare all'interno di un'area visibile specifica.
Tipi di mappe base
I tipi di mappa che crei in questo modo possono essere autonomi o essere combinati con altri tipi di mappa come overlay. I tipi di mappa autonomi sono noti come tipi di mappa base. Potresti voler 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 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;
Tipi di mappe in overlay
Alcuni tipi di mappa sono progettati per funzionare sopra i tipi di mappa esistenti. Questi tipi di mappa possono avere livelli trasparenti che indicano punti di interesse o mostrano dati aggiuntivi all'utente.
In questi casi, non vuoi che il tipo di mappa venga trattato come un'entità separata, ma come un overlay.
Puoi farlo aggiungendo il tipo di mappa a un MapType esistente direttamente utilizzando la proprietà overlayMapTypes di Map. Questa proprietà contiene un MVCArray di MapType. Tutti i tipi di mappa (base e overlay) vengono visualizzati all'interno del livello mapPane. I tipi di mappa 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).
L'esempio seguente è identico al precedente,
ma 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;
Tipi di mappe immagine
L'implementazione di un MapType che funga da 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 mappa più comuni: tipi di mappa costituiti da riquadri composti da singoli file immagine.
Questa classe, la classe ImageMapType, viene creata utilizzando una specifica dell'oggetto ImageMapTypeOptions che definisce le seguenti proprietà obbligatorie:
tileSize(obbligatorio) specifica le dimensioni del riquadro (di tipogoogle.maps.Size). Le dimensioni devono essere rettangolari, anche se non necessariamente quadrate.getTileUrl(obbligatorio) specifica la funzione, di solito fornita come valore letterale della funzione incorporata, per gestire la selezione della corretta sezione dell'immagine in base alle coordinate mondiali e al livello di zoom forniti.
Il seguente codice implementa un ImageMapType di base utilizzando i riquadri della Luna 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;
Proiezioni
La Terra è una sfera tridimensionale (approssimativamente), mentre una mappa è una superficie piana bidimensionale. La mappa che vedi nell'API Maps JavaScript, come qualsiasi mappa piatta della Terra, è una proiezione di quella sfera su una superficie piana. In termini più 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 eseguire la conversione dalle coordinate della Terra (oggetti LatLng) al sistema di coordinate del mondo della classe Projection e viceversa.
Google Maps utilizza la proiezione di Mercatore per creare le mappe
dai dati geografici e convertire gli eventi sulla mappa in
coordinate geografiche. Puoi ottenere questa proiezione chiamando getProjection() su Map (o su uno qualsiasi dei tipi di base MapType standard). Per la maggior parte degli utilizzi, questa Projection standard è sufficiente, ma puoi anche definire e utilizzare le tue proiezioni personalizzate.
Implementa una proiezione
Quando implementi una proiezione personalizzata, devi definire alcuni elementi:
- Le formule per mappare le coordinate di latitudine e longitudine in un piano cartesiano e le formule corrispondenti per mappare da un piano cartesiano alle coordinate di latitudine e longitudine. (L'interfaccia
Projectionsupporta solo le trasformazioni in coordinate rettilinee). - La dimensione di base del riquadro. Tutti i riquadri devono essere rettangolari.
- La "dimensione globale" di una mappa che utilizza il set di riquadri di base con livello di zoom 0. Tieni presente che per le mappe costituite da un'icona con livello di zoom 0, le dimensioni del mondo e quelle dell'icona di base sono identiche.
Trasformazioni delle coordinate nelle proiezioni
Ogni proiezione fornisce due metodi che traducono tra questi due sistemi di coordinate, consentendoti di convertire tra coordinate geografiche e coordinate del mondo:
- Il metodo
Projection.fromLatLngToPoint()converte un valoreLatLngin una coordinata del mondo. Questo metodo viene utilizzato per posizionare gli overlay sulla mappa (e per posizionare la mappa stessa). - Il metodo
Projection.fromPointToLatLng()converte una coordinata del mondo in un valoreLatLng. Questo metodo viene utilizzato per convertire eventi come i clic sulla mappa in coordinate geografiche.
Google Maps presuppone che le proiezioni siano rettilinee.
In genere, puoi utilizzare una proiezione in due casi: per creare una mappa del mondo o per creare una mappa di un'area locale. In quest'ultimo caso, devi assicurarti che la proiezione sia anche rettilinea e normale a tutte le longitudini. Alcune proiezioni (soprattutto quelle coniche) potrebbero essere "localmente normali" (ovvero puntare a nord), ma deviare dal nord reale, ad esempio, più la mappa è posizionata rispetto a una longitudine di riferimento. Puoi utilizzare questa proiezione localmente, ma tieni presente che è necessariamente imprecisa e che gli errori di trasformazione diventeranno sempre più evidenti man mano che ti allontani dalla longitudine di riferimento.
Selezione dei riquadri della mappa nelle proiezioni
Le proiezioni non sono utili 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 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 dei riquadri. Le coordinate dei riquadri si basano sia sulle dimensioni di base dei riquadri (che devono essere rettangolari) sia sulle "dimensioni del mondo" della mappa, ovvero le dimensioni in pixel del mondo della mappa al livello di zoom 0. Per le mappe costituite da un tile con livello di zoom 0, le dimensioni del tile e del mondo sono identiche.
Puoi definire le dimensioni di base del riquadro all'interno della proprietà tileSize di MapType. Le dimensioni del mondo vengono definite implicitamente
all'interno dei metodi fromLatLngToPoint()
e fromPointToLatLng() della proiezione.
Poiché la selezione delle immagini dipende da questi valori passati, è utile assegnare alle immagini nomi che possono essere selezionati in modo programmatico in base ai valori passati, ad esempio 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 const mapElement = document.querySelector('gmp-map')!; let innerMap: google.maps.Map; async function init() { // Request the needed libraries. await google.maps.importLibrary('maps'); // Create a map. innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Set the Gall-Peters map type. const gallPetersMapType = await initGallPeters(); innerMap.mapTypes.set('gallPeters', gallPetersMapType); innerMap.setMapTypeId('gallPeters'); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById('coords')!; innerMap.addListener('mousemove', (event: google.maps.MapMouseEvent) => { coordsDiv.textContent = `lat: ${String(Math.round(event.latLng!.lat()))}, lng: ${String(Math.round(event.latLng!.lng()))}`; }); // Add some markers to the map. innerMap.data.setStyle((feature) => { return { title: feature.getProperty('name') as string, optimized: false, }; }); innerMap.data.addGeoJson(cities); } async function initGallPeters(): Promise<google.maps.ImageMapType> { const [{ ImageMapType }, { Size, Point, LatLng }] = await Promise.all([ google.maps.importLibrary('maps'), google.maps.importLibrary('core'), ]); const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. const gallPetersMapType = new ImageMapType({ getTileUrl(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 `gall-peters_${String(zoom)}_${String(x)}_${String(y)}.png`; }, tileSize: new 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(latLng: google.maps.LatLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)) ); }, fromPointToLatLng(point: google.maps.Point, noWrap?: boolean) { const x = point.x / GALL_PETERS_RANGE_X; const y = Math.max(0, Math.min(1, point.y / GALL_PETERS_RANGE_Y)); return new LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap ); }, }; return gallPetersMapType; } // 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' }, }, ], }; void init();
JavaScript
// This example defines an image map type using the Gall-Peters // projection. // https://en.wikipedia.org/wiki/Gall%E2%80%93Peters_projection const mapElement = document.querySelector('gmp-map'); let innerMap; async function init() { // Request the needed libraries. await google.maps.importLibrary('maps'); // Create a map. innerMap = mapElement.innerMap; innerMap.setOptions({ mapTypeControl: false, }); // Set the Gall-Peters map type. const gallPetersMapType = await initGallPeters(); innerMap.mapTypes.set('gallPeters', gallPetersMapType); innerMap.setMapTypeId('gallPeters'); // Show the lat and lng under the mouse cursor. const coordsDiv = document.getElementById('coords'); innerMap.addListener('mousemove', (event) => { coordsDiv.textContent = `lat: ${String(Math.round(event.latLng.lat()))}, lng: ${String(Math.round(event.latLng.lng()))}`; }); // Add some markers to the map. innerMap.data.setStyle((feature) => { return { title: feature.getProperty('name'), optimized: false, }; }); innerMap.data.addGeoJson(cities); } async function initGallPeters() { const [{ ImageMapType }, { Size, Point, LatLng }] = await Promise.all([ google.maps.importLibrary('maps'), google.maps.importLibrary('core'), ]); const GALL_PETERS_RANGE_X = 800; const GALL_PETERS_RANGE_Y = 512; // Fetch Gall-Peters tiles stored locally on our server. const gallPetersMapType = new ImageMapType({ getTileUrl(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 `gall-peters_${String(zoom)}_${String(x)}_${String(y)}.png`; }, tileSize: new 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(latLng) { const latRadians = (latLng.lat() * Math.PI) / 180; return new Point( GALL_PETERS_RANGE_X * (0.5 + latLng.lng() / 360), GALL_PETERS_RANGE_Y * (0.5 - 0.5 * Math.sin(latRadians)) ); }, fromPointToLatLng(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 LatLng( (Math.asin(1 - 2 * y) * 180) / Math.PI, -180 + 360 * x, noWrap ); }, }; return gallPetersMapType; } // 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' }, }, ], }; void init();