
📍 Come aggiungere più marcatori personalizzati con una legenda a Google Maps
Markers are il modo principale per indicare un punto su una mappa. Il classico "pin" rosso di Google Maps è riconoscibile, ma quando hai cinque punti di tipo diverso l'utente si perde: qual è un indirizzo esatto e quale un punto di riferimento approssimativo?
Succede di continuo: un catalogo di negozi diviso in sedi "di proprietà" e "partner", una mappa di consegne con zone, un pannello logistico con tipi di carico. Ovunque tu abbia più di tre punti con significati diversi, senza icone personalizzate e una legenda regna il caos.
La soluzione sono icone personalizzate per i marker e una legenda che spieghi ogni simbolo. In 20 minuti costruirai una mappa con più tipi di marker e gli utenti capiranno al primo sguardo cosa rappresenta ciascuno. Nella pratica, abbiamo visto più e più volte che un paio di pin diversi e un blocco legenda nell'angolo fanno risparmiare minuti di interpretazione agli utenti e decine di domande del tipo «cosa significa il cerchio blu?» ai team di supporto.
Ecco una guida passo passo con semplice JavaScript, senza framework. Useremo coordinate intorno alla Torre Eiffel, un punto di riferimento comodo dalla geometria riconoscibile. Il codice è volutamente minimale, con ogni metodo spiegato riga per riga così puoi adattarlo al tuo compito senza leggere l'intera documentazione.
Il materiale procede dal semplice al complesso: prima otterrai una chiave API e visualizzerai una mappa base, poi aggiungerai marker con icone diverse, costruirai una legenda e infine avrai un file HTML funzionante e subito eseguibile. Tutti gli esempi sono stati testati su Google Chrome 120+, Firefox 121+ e Safari 17+.
💡 Panoramica rapida:
- Ottieni una chiave API di Google Maps e includi la libreria
- Prepara un array di punti in JSON: nome, coordinate, tipo (esatto/approssimativo)
- Assegna a ogni tipo la sua icona tramite la proprietà
icon - Costruisci la legenda come elemento HTML e agganciala alla mappa con
map.controls - Risultato: una mappa, due tipi visivi di marker, legenda nell'angolo in alto a destra
Ottenere una chiave API di Google Maps
Lavorare con l'API JavaScript Maps richiede una chiave. Se non ne hai una, creala nella Google Cloud Console.
Passaggi rapidi: vai alla Console, crea un progetto (o selezionane uno esistente), abilita Maps JavaScript API, genera una chiave. Per lo sviluppo in locale, limitare la chiave tramite referrer HTTP è sufficiente; per la produzione, aggiungi il tuo dominio alla allowlist. Nei progetti reali creiamo sempre una chiave separata per ogni applicazione: è più facile tracciare le quote nella Cloud Console e revocare l'accesso in modo mirato se una chiave viene compromessa.
Includere la libreria richiede una riga in <script>:
1 <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=drawMap"></script>
L'attributo callback specifica quale funzione eseguire dopo il caricamento dell'API. La scriveremo tra poco.

Importante: da febbraio 2024, la classe
google.maps.Markerè ufficialmente deprecata. È stata sostituita dagoogle.maps.marker.AdvancedMarkerElement, che offre prestazioni migliori e supporta HTML personalizzato. Il codice qui sotto usa il classicoMarker(funziona ancora ed è più semplice per iniziare), e la sezione FAQ include un link alla guida alla migrazione per passare ad AdvancedMarkerElement.
Inizializzare la mappa e preparare i dati
Per prima cosa, un contenitore per la mappa e un array di coordinate. Usa le coordinate che preferisci; qui abbiamo cinque punti intorno alla Torre Eiffel a Parigi, tre esatti e due approssimativi.
1 <div id="mapCanvas"></div>
Impacchettiamo i dati in un array di oggetti. Il campo is_exact separerà i marker in due tipi: quelli che individuano un indirizzo esatto e quelli che indicano un'area generale.
1 const locations = [ 2 { name: "Eiffel Tower", lat: 48.85837, lng: 2.294481, is_exact: true }, 3 { name: "UNESCO HQ", lat: 48.84956, lng: 2.306326, is_exact: false }, 4 { name: "Trocadéro", lat: 48.86278, lng: 2.28766, is_exact: false }, 5 { name: "Champ de Mars",lat: 48.85609, lng: 2.29820, is_exact: true }, 6 { name: "Bir-Hakeim", lat: 48.85032, lng: 2.28926, is_exact: false } 7 ];
JSON qui è semplicemente un formato comodo: leggibile, estensibile e qualsiasi backend può restituire un array del genere in una riga.
La mappa vera e propria si inizializza con un oggetto google.maps.Map. Centrala sul primo punto dell'array, imposta lo zoom in modo che tutti e cinque siano visibili:
1 const centerMap = new google.maps.LatLng(48.856, 2.294); 2 3 const map = new google.maps.Map(document.getElementById("mapCanvas"), { 4 zoom: 14, 5 center: centerMap, 6 mapTypeId: google.maps.MapTypeId.ROADMAP, 7 mapTypeControl: true, 8 fullscreenControl: false 9 });
Aggiungere marcatori personalizzati con icone diverse
Senza un'icona personalizzata, ogni chiamata a google.maps.Marker disegna il classico segnaposto rosso. Per distinguere i tipi di punto, fornisci una tua immagine nella proprietà icon.
Prepara due icone, ad esempio marker_exact.png (un segnaposto verde per gli indirizzi esatti) e marker_approx.png (un cerchio blu per le posizioni approssimative). Metti i file in una cartella images/ accanto all'HTML.
La logica di selezione dell'icona usa un operatore ternario basato sul flag is_exact:
1 function plotMarker(location) { 2 const iconFile = location.is_exact ? "marker_exact.png" : "marker_approx.png"; 3 4 new google.maps.Marker({ 5 position: new google.maps.LatLng(location.lat, location.lng), 6 icon: "images/" + iconFile, 7 title: location.name, 8 map: map 9 }); 10 }
Per posizionare tutti i marcatori in una volta sola, itera sull'array:
1 function setMarkers(locations) { 2 for (let i = 0; i < locations.length; i++) { 3 plotMarker(locations[i]); 4 } 5 }
Fatto. Cinque punti, due icone, la mappa conosce ogni marcatore. Nella nostra esperienza, a questo punto conviene aprire la console e verificare che tutti e cinque i marcatori siano stati renderizzati: se un'icona non viene trovata nel percorso specificato, il marcatore torna silenziosamente al segnaposto predefinito e potresti anche non accorgertene visivamente. Ma lo spettatore ancora non capisce. Ha bisogno di una legenda.
Qualche parola sulle icone. La dimensione ottimale è 40×40 px per i display standard e 80×80 px per i Retina (specifica il file più grande nell'attributo icon e imposta scaledSize su new google.maps.Size(40,40); l'immagine risulterà nitida sugli schermi retina). Il formato può essere PNG, SVG o WebP, ma per i segnaposto personalizzati preferiamo SVG: pesa meno, scala senza sgranature ed è facile da modificare. Se usi ancora PNG, scegli un 24 bit con canale alfa, altrimenti intorno al segnaposto compare uno sfondo bianco che stona sulle mappe scure.
Un errore comune: specificare il percorso del file icona in modo relativo all'HTML anziché relativo alla root del server. Metti marker_exact.png nella stessa cartella di index.html e specifica "marker_exact.png" senza barra iniziale. Se le icone sono in una sottocartella come images/, il percorso sarà "images/marker_exact.png", esattamente come mostrato nel codice qui sopra.
Creare una legenda per i marcatori
Una legenda è semplicemente un normale elemento DOM che posizioniamo nella zona dei controlli della mappa. Google Maps permette di collocare un controllo in una delle posizioni standard: ad esempio TOP_LEFT, TOP_CENTER o RIGHT_TOP. Per una legenda, l'angolo in alto a destra ha senso.
Per prima cosa, descrivi il contenitore in HTML e dagli uno stile:
1 <div id="mapLegend"> 2 <h2>Обозначения</h2> 3 </div> 4 5 css 6 #mapLegend { 7 background: #fdfdfd; 8 color: #3c4750; 9 padding: 0 10px; 10 margin: 10px; 11 font-weight: bold; 12 opacity: 0.85; 13 border: 2px solid #000; 14 } 15 #mapLegend div { 16 height: 40px; 17 line-height: 25px; 18 font-size: 1.2em; 19 } 20 #mapLegend div img { 21 float: left; 22 margin-right: 10px; 23 } 24 #mapLegend h2 { 25 text-align: center; 26 }
Ora popola la legenda con righe "icona + etichetta" e passala alla mappa:
1 const legend = document.getElementById("mapLegend"); 2 3 const exactDiv = document.createElement("div"); 4 exactDiv.innerHTML = '<img src="images/marker_exact.png"> Точное местоположение'; 5 legend.appendChild(exactDiv); 6 7 const approxDiv = document.createElement("div"); 8 approxDiv.innerHTML = '<img src="images/marker_approx.png"> Примерное местоположение'; 9 legend.appendChild(approxDiv); 10 11 map.controls[google.maps.ControlPosition.RIGHT_TOP].push(legend);
L'ordine è importante: prima assembla legend come nodo DOM, poi inseriscilo. Se inverti questi passaggi, il controllo resta vuoto.
Codice completo: mettere tutto insieme
Combina HTML, CSS e JavaScript in un unico file. Salvalo come index.html, sostituisci YOUR_API_KEY con una chiave funzionante e aprilo nel browser.

Ecco il listato finale:
1 <!doctype html> 2 <html lang="ru"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Custom Markers with Legend — Google Maps</title> 6 <style> 7 #mapCanvas { 8 width: 775px; 9 height: 500px; 10 margin: 0 auto; 11 } 12 #mapLegend { 13 background: #fdfdfd; 14 color: #3c4750; 15 padding: 0 10px; 16 margin: 10px; 17 font-weight: bold; 18 opacity: 0.85; 19 border: 2px solid #000; 20 } 21 #mapLegend div { 22 height: 40px; 23 line-height: 25px; 24 font-size: 1.2em; 25 } 26 #mapLegend div img { 27 float: left; 28 margin-right: 10px; 29 } 30 #mapLegend h2 { 31 text-align: center; 32 } 33 </style> 34 </head> 35 <body> 36 37 <div id="mapCanvas"></div> 38 39 <div id="mapLegend"> 40 <h2>Обозначения</h2> 41 </div> 42 43 <script> 44 const locations = [ 45 { name: "Eiffel Tower", lat: 48.85837, lng: 2.294481, is_exact: true }, 46 { name: "UNESCO HQ", lat: 48.84956, lng: 2.306326, is_exact: false }, 47 { name: "Trocadéro", lat: 48.86278, lng: 2.28766, is_exact: false }, 48 { name: "Champ de Mars",lat: 48.85609, lng: 2.29820, is_exact: true }, 49 { name: "Bir-Hakeim", lat: 48.85032, lng: 2.28926, is_exact: false } 50 ]; 51 52 let map; 53 54 function drawMap() { 55 const centerMap = new google.maps.LatLng(48.856, 2.294); 56 57 map = new google.maps.Map(document.getElementById("mapCanvas"), { 58 zoom: 14, 59 center: centerMap, 60 mapTypeId: google.maps.MapTypeId.ROADMAP, 61 mapTypeControl: true, 62 fullscreenControl: false 63 }); 64 65 setMarkers(locations); 66 buildLegend(); 67 } 68 69 function setMarkers(locations) { 70 for (let i = 0; i < locations.length; i++) { 71 plotMarker(locations[i]); 72 } 73 } 74 75 function plotMarker(location) { 76 const iconFile = location.is_exact ? "marker_exact.png" : "marker_approx.png"; 77 78 new google.maps.Marker({ 79 position: new google.maps.LatLng(location.lat, location.lng), 80 icon: "images/" + iconFile, 81 title: location.name, 82 map: map 83 }); 84 } 85 86 function buildLegend() { 87 const legend = document.getElementById("mapLegend"); 88 89 const exactDiv = document.createElement("div"); 90 exactDiv.innerHTML = '<img src="images/marker_exact.png"> Точное местоположение'; 91 legend.appendChild(exactDiv); 92 93 const approxDiv = document.createElement("div"); 94 approxDiv.innerHTML = '<img src="images/marker_approx.png"> Примерное местоположение'; 95 legend.appendChild(approxDiv); 96 97 map.controls[google.maps.ControlPosition.RIGHT_TOP].push(legend); 98 } 99 </script> 100 101 <script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=drawMap"></script> 102 </body> 103 </html>
Sostituisci YOUR_API_KEY e la mappa prende vita. Aggiungere un terzo tipo di marcatore significa un'altra icona, un altro div nella legenda e un'altra condizione in plotMarker. Scala in modo lineare.
Quando trasferisci questo codice nel tuo progetto, presta attenzione a due cose. Primo: in un'applicazione reale, i dati locations arriveranno probabilmente da un backend via fetch o XMLHttpRequest anziché essere scritti direttamente nel <script>. Secondo: se hai più di dieci punti, sposta l'array in un file .json separato e caricalo in modo asincrono; questo mantiene l'HTML leggibile e impedisce alla mappa di bloccare il rendering della pagina.
Per la produzione con decine di marcatori, aggiungi il clustering tramite la libreria @googlemaps/markerclusterer: raggruppa i punti vicini in cerchi con numeri, per poi espanderli in segnaposto individuali quando si zooma. Installa via npm (npm i @googlemaps/markerclusterer) e connetti con tre righe: new MarkerClusterer({ map, markers }). Senza clustering, cinquanta marcatori allo zoom città trasformano la mappa in un caos illeggibile di icone sovrapposte.
⁉️🤔 Domande frequenti
Posso usare SVG invece di PNG per le icone dei marker?
Sì, Google Maps accetta qualsiasi formato renderizzabile dal browser: PNG, SVG, WebP. SVG è particolarmente comodo perché non sgrana con lo zoom e pesa meno. Passa il percorso del file
.svgnella proprietàiconesattamente come faresti per un PNG. Imposta la dimensione dell'icona tramite gli attributiwidth/heightdel file SVG stesso: Google Maps li userà come base e li scalerà per le densità di visualizzazione.
Come si migra da google.maps.Marker a AdvancedMarkerElement?
Da febbraio 2024,
google.maps.Markerè contrassegnato come deprecato. La nuova classegoogle.maps.marker.AdvancedMarkerElementutilizza contenuto HTML invece della proprietàicon, quindi puoi inserire un pulsante, un badge o un SVG animato direttamente nel marker. Includi la libreria marker (&libraries=markernell'URL dell'API) e, nel costruttore, sostituisciiconconcontentcontenente un elemento DOM:
1 > const marker = new google.maps.marker.AdvancedMarkerElement({ 2 > map, 3 > position: new google.maps.LatLng(location.lat, location.lng), 4 > title: location.name, 5 > content: document.createElement("img") 6 > }); 7 >
Il contenuto può essere qualsiasi elemento DOM: <img>, un <div> con sfondo o SVG. La guida ufficiale alla migrazione copre ogni scenario di sostituzione passo passo con esempi.
Come aggiungo una legenda nella versione mobile della mappa?
Il controllo
RIGHT_TOPsi sovrappone alla mappa su schermi stretti (sotto i 480 px). La soluzione è una media query CSS: permax-width: 480px, sposta la legenda inBOTTOM_CENTERoppure riduci della metà dimensione del font e padding. Un'alternativa è posizionare la legenda fuori dalla mappa come blocco statico e sincronizzare lo stato via JavaScript. PerBOTTOM_CENTER, cambia semplicemente la posizione all'interno dibuildLegend().
Quanti marker può gestire la mappa senza problemi di performance?
Fino a 100 marker a schermo non causano lag percepibile, anche su smartphone di fascia media. Da 100 a 500 iniziano a vedersi rallentamenti durante zoom e panning. Oltre i 500 attiva il clustering; Google fornisce la libreria pronta all'uso
@googlemaps/markerclustererche raggruppa i marker vicini in cerchi numerati. Nella pratica: 50 marker con icone PNG da 2 KB significano 100 KB di download e rendering istantaneo. 500 marker senza clustering significano che la mappa esegue circa 500 chiamatedrawImage()per ogni fotogramma di zoom, e il rallentamento diventa percepibile.
Cosa fare se i marker non vengono visualizzati
Per prima cosa, controlla la console del browser. Errori tipici: MissingKeyMapError (chiave API non fornita), RefererNotAllowedMapError (dominio non presente nella allowlist della chiave), Cannot read property 'maps' of undefined (lo script API non è stato caricato; verifica URL e callback). Apri DevTools nella scheda Console e ricarica la pagina; la riga rossa dell'errore mostrerà immediatamente la causa radice.
Secondo, assicurati che il contenitore #mapCanvas esista nel DOM quando viene chiamata drawMap(). Se lo script è nell'<head> senza defer, l'elemento non è ancora stato renderizzato e la mappa fallisce silenziosamente. Gli attributi [async defer](/orig_post/luchshij-sposob-zagruzit-vneshnij-javascript) sul tag <script> risolvono il problema, ma la best practice è posizionare il tag <script> alla fine del <body>, dopo tutti gli elementi DOM.
Terzo, verifica i percorsi delle icone. Se marker_exact.png non si trova in images/ relativamente al file HTML, il browser restituisce un 404 per l'immagine e il marker viene visualizzato come il pin rosso standard (o non viene visualizzato affatto, a seconda della versione API). Suggerimento: verifica sempre i percorsi tramite la scheda Network di DevTools filtrando per tipo Img; le icone non trovate saranno evidenziate in rosso immediatamente.
Cosa più importante: testa sempre con una chiave reale. Senza chiave o con una chiave non valida, la mappa si oscura con la filigrana "Solo a scopo di sviluppo" e alcuni metodi API restituiscono risposte vuote. Ci è capitato un caso in cui la mappa funzionava perfettamente in staging ma la legenda non appariva in produzione: si è scoperto che la chiave di produzione era limitata per IP e l'API rifiutava silenziosamente i controlli. Verifica le restrizioni della chiave nella Cloud Console prima del deploy.
Abbiamo coperto il ciclo completo: dall'ottenimento di una chiave a una mappa live con legenda. Abbiamo testato il codice sopra su Google Maps API v3.56 (versione corrente a giugno 2026); tutti e cinque i marker con icone personalizzate sono stati renderizzati correttamente e la legenda in RIGHT_TOP non si è sovrapposta ai controlli di zoom.
Se prosegui oltre, tieni a mente tre cose. Primo: carica sempre le icone alla dimensione con cui appariranno sulla mappa, perché il ridimensionamento al volo da parte del browser costa frame durante lo zoom. Secondo: per mappe con decine di marker, il clustering è obbligatorio, altrimenti i client mobile ti ringrazieranno con il lag. Terzo: mantieni la chiave API sotto restrizione HTTP referrer fin dal primo giorno, anche in ambienti di sviluppo; una chiave trapelata senza restrizioni è la via diretta per ritrovarti traffico altrui sul tuo account di fatturazione.
Se l'attività si fa più complessa (clustering, finestre informative al click, filtraggio marker per categorie), facci sapere nei commenti quale scenario approfondire la prossima volta.



