Skip to content

Allt om WordPress, webbutveckling — och mer därtill

📍 Hur du lägger till flera anpassade markörer med en teckenförklaring i Google Maps

📍 Hur du lägger till flera anpassade markörer med en teckenförklaring i Google Maps

Markörer är det vanligaste sättet att markera en punkt på en karta. Den klassiska röda Google Maps-nålen är lätt att känna igen, men när du har fem punkter av olika typer tappar användarna bort sig: vilken är en exakt adress och vilken är ett ungefärligt landmärke?

Det här händer hela tiden: en butikskatalog uppdelad i "egna" och "partner"-butiker, en leveranskarta med zoner, en logistikpanel med lasttyper. Överallt där du har fler än tre punkter med olika betydelser uppstår kaos utan anpassade ikoner och en teckenförklaring.

Lösningen är anpassade markör-ikoner och en teckenförklaring som förklarar varje symbol. På 20 minuter bygger du en karta med flera markörtyper, och användarna förstår vad som är vad direkt. I praktiken har vi sett gång på gång att ett par olika nålar och en teckenförklaringsruta i hörnet sparar användarna minuter av tolkande och besparar supportteamet dussintals frågor om "vad betyder den blå cirkeln?".

Här nedan följer en steg-för-steg-genomgång med vanlig JavaScript, utan ramverk. Vi använder koordinater runt Eiffeltornet, ett praktiskt landmärke med igenkännbar geometri. Koden är avsiktligt minimal, och varje metod förklaras rad för rad så att du kan anpassa den till din uppgift utan att läsa hela dokumentationen.

Materialet går från enkelt till komplext: först skaffar du en API-nyckel och renderar en grundkarta, sedan lägger du till markörer med olika ikoner, bygger en teckenförklaring och slutligen har du en fungerande HTML-fil som går att köra direkt. Alla exempel har testats i Google Chrome 120+, Firefox 121+ och Safari 17+.

💡 Snabb översikt:

  • Skaffa en Google Maps API-nyckel och inkludera biblioteket
  • Förbered en array med punkter i JSON: namn, koordinater, typ (exakt/ungefärlig)
  • Tilldela varje typ en egen ikon via egenskapen icon
  • Bygg teckenförklaringen som ett HTML-element och fäst det på kartan via map.controls
  • Resultat: en karta, två visuella markörtyper, teckenförklaring i övre högra hörnet

Skaffa en Google Maps API-nyckel

Att arbeta med JavaScript Maps API kräver en nyckel. Om du inte har någon, skapa den i Google Cloud Console.

Snabba steg: gå till Console, skapa ett projekt (eller välj ett befintligt), aktivera Maps JavaScript API, generera en nyckel. För lokal utveckling räcker det att begränsa nyckeln med HTTP-referrer; för produktion lägger du till din domän i tillåtelselistan. I riktiga projekt skapar vi alltid en separat nyckel för varje applikation: det är enklare att följa upp kvoter i Cloud Console och återkalla åtkomst exakt om en nyckel läcker.

Att inkludera biblioteket tar en rad i <script>:

1<script async defer src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=drawMap"></script>

Attributet callback anger vilken funktion som körs efter att API:et har laddats. Den skriver vi härnäst.

Markörer på en karta: anpassade ikoner för Google Maps

Viktigt: sedan februari 2024 är klassen google.maps.Marker officiellt markerad som föråldrad. Den har ersatts av google.maps.marker.AdvancedMarkerElement, som erbjuder bättre prestanda och stöd för anpassad HTML. Koden nedan använder den klassiska Marker (den fungerar fortfarande och är enklare att börja med), och FAQ-avsnittet innehåller en länk till migreringsguiden för att byta till AdvancedMarkerElement.

Initiera kartan och förbereda data

Först en behållare för kartan och en array med koordinater. Använd vilka koordinater du vill; här har vi fem punkter runt Eiffeltornet i Paris, tre exakta och två ungefärliga.

1<div id="mapCanvas"></div>

Vi paketerar datan i en array av objekt. Fältet is_exact kommer att separera markörerna i två typer: de som pekar ut en exakt adress och de som indikerar ett allmänt område.

1const 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 här är helt enkelt ett praktiskt format: läsbart, utbyggbart, och vilken backend som helst kan returnera en sådan array på en rad.

Själva kartan initieras med ett google.maps.Map-objekt. Centrera den på den första array-punkten, sätt zoom så att alla fem får plats:

1const centerMap = new google.maps.LatLng(48.856, 2.294);
2
3const 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});

Lägga till anpassade markörer med olika ikoner

Utan en anpassad ikon ritar varje anrop till google.maps.Marker den vanliga röda nålen. För att skilja punkttyper åt anger du en egen bild i egenskapen icon.

Förbered två ikoner, till exempel marker_exact.png (en grön nål för exakta adresser) och marker_approx.png (en blå cirkel för ungefärliga platser). Lägg filerna i en images/-mapp bredvid HTML-filen.

Logiken för ikonval använder en ternär operator baserad på flaggan is_exact:

1function 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}

För att placera alla markörer på en gång, iterera genom arrayen:

1function setMarkers(locations) {
2 for (let i = 0; i < locations.length; i++) {
3 plotMarker(locations[i]);
4 }
5}

Klart. Fem punkter, två ikoner, kartan känner till varje markör. Enligt vår erfarenhet bör du i det här läget öppna konsolen och kontrollera att alla fem markörer har renderats: om en ikon inte hittades på den angivna sökvägen faller markören tyst tillbaka på standardnålen, och du kanske inte ens märker det visuellt. Men betraktaren förstår ännu ingenting. De behöver en teckenförklaring.

Några ord om ikoner. Optimal storlek är 40×40 px för standardskärmar och 80×80 px för Retina (ange den större filen i attributet icon och sätt scaledSize till new google.maps.Size(40,40); bilden blir skarp på retinaskärmar). Formatet kan vara PNG/SVG/WebP, men för anpassade nålar föredrar vi SVG: det väger mindre, skalas utan pixelering och är lätt att redigera. Om du ändå använder PNG, välj 24-bitars med alfakanal; annars dyker en vit bakgrund upp runt nålen, vilket ser malplacerat ut på mörka kartor.

Ett vanligt misstag: att ange ikonfilens sökväg relativt HTML-filen i stället för relativt serverroten. Placera marker_exact.png i samma mapp som index.html och ange "marker_exact.png" utan inledande snedstreck. Om ikonerna ligger i en undermapp som images/ blir sökvägen "images/marker_exact.png", precis som i koden ovan.

Skapa en teckenförklaring för markörer

En teckenförklaring är bara ett vanligt DOM-element som vi placerar i kartans kontrollzon. Google Maps låter dig placera en kontroll på en av standardpositionerna: till exempel TOP_LEFT, TOP_CENTER eller RIGHT_TOP. För en teckenförklaring är det övre högra hörnet logiskt.

Beskriv först behållaren i HTML och stila den:

1<div id="mapLegend">
2 <h2>Обозначения</h2>
3</div>
4
5css
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}

Fyll nu teckenförklaringen med rader av typen "ikon + etikett" och lämna den till kartan:

1const legend = document.getElementById("mapLegend");
2
3const exactDiv = document.createElement("div");
4exactDiv.innerHTML = '<img src="images/marker_exact.png"> Точное местоположение';
5legend.appendChild(exactDiv);
6
7const approxDiv = document.createElement("div");
8approxDiv.innerHTML = '<img src="images/marker_approx.png"> Примерное местоположение';
9legend.appendChild(approxDiv);
10
11map.controls[google.maps.ControlPosition.RIGHT_TOP].push(legend);

Ordningen spelar roll: bygg först legend som en DOM-nod, lägg sedan till den. Om du vänder på detta förblir kontrollen tom.

Fullständig kod: allt samlat

Kombinera HTML, CSS och JavaScript i en enda fil. Spara den som index.html, ersätt YOUR_API_KEY med en fungerande nyckel och öppna den i en webbläsare.

Karta med anpassade markörer och teckenförklaring i Google Maps

Här är den slutliga koden:

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>
44const 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
52let map;
53
54function 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
69function setMarkers(locations) {
70 for (let i = 0; i < locations.length; i++) {
71 plotMarker(locations[i]);
72 }
73}
74
75function 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
86function 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>

Ersätt YOUR_API_KEY så vaknar kartan till liv. Att lägga till en tredje markörtyp innebär ytterligare en ikon, ytterligare en div i teckenförklaringen och ytterligare ett villkor i plotMarker. Det skalas linjärt.

När du överför den här koden till ditt projekt, var uppmärksam på två saker. För det första: i en riktig applikation kommer locations-datan sannolikt från en backend via fetch eller XMLHttpRequest snarare än att vara hårdkodad i <script>. För det andra: om du har fler än tio punkter, flytta arrayen till en separat .json-fil och ladda den asynkront; detta håller HTML:en läsbar och förhindrar att kartan blockerar sidrenderingen.

För produktion med dussintals markörer, lägg till klustring via biblioteket @googlemaps/markerclusterer: det grupperar närliggande punkter i cirklar med siffror och expanderar dem sedan till enskilda nålar vid inzoomning. Installera via npm (npm i @googlemaps/markerclusterer) och anslut med tre rader: new MarkerClusterer({ map, markers }). Utan klustring förvandlar femtio markörer på stadszoom kartan till en oläslig röra av överlappande ikoner.

⁉️🤔 Vanliga frågor

Kan jag använda SVG istället för PNG för markörikoner?

Ja, Google Maps accepterar alla format som webbläsaren kan rendera: PNG, SVG, WebP. SVG är särskilt praktiskt eftersom det inte blir pixligt vid inzoomning och väger mindre. Skicka sökvägen till .svg-filen i egenskapen icon precis som du skulle göra för PNG. Ange ikonstorlek via width-/height-attributen i själva SVG-filen: Google Maps använder dem som bas och skalar för olika skärmtätheter.

Hur migrerar jag från google.maps.Marker till AdvancedMarkerElement?

Sedan februari 2024 är google.maps.Marker markerad som föråldrad. Den nya klassen google.maps.marker.AdvancedMarkerElement använder HTML-innehåll istället för egenskapen icon, så du kan stoppa in en knapp, badge eller animerad SVG direkt i markören. Inkludera marker-biblioteket (&libraries=marker i API-URL:en) och ersätt icon med content som innehåller ett DOM-element i konstruktorn:

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>

Innehållet kan vara vilket DOM-element som helst: <img>, en <div> med bakgrund eller SVG. Den officiella migreringsguiden går igenom varje ersättningsscenario steg för steg med exempel.

Hur lägger jag till en teckenförklaring i mobilversionen av kartan?

Kontrollen RIGHT_TOP överlappar kartan på smala skärmar (under 480 px). Lösningen är en CSS-media query: för max-width: 480px, flytta teckenförklaringen till BOTTOM_CENTER eller halvera teckenstorlek och padding. Ett alternativ är att placera teckenförklaringen utanför kartan som ett statiskt block och synkronisera tillståndet via JavaScript. För BOTTOM_CENTER ändrar du helt enkelt positionen inuti buildLegend().

Hur många markörer klarar kartan utan prestandaproblem?

Upp till 100 markörer på skärmen orsakar ingen märkbar fördröjning, även på mellanklasstelefoner. Från 100 till 500 börjar du se förseningar vid zoomning och panorering. För 500+ aktivera klustring; Google tillhandahåller det färdiga biblioteket @googlemaps/markerclusterer som grupperar närliggande markörer i numrerade cirklar. I praktiken: 50 markörer med PNG-ikoner på 2 KB innebär 100 KB nedladdning och omedelbar rendering. 500 markörer utan klustring innebär att kartan gör cirka 500 drawImage()-anrop per zoom-bildruta, vilket blir märkbart.

Vad du ska göra om markörer inte visas

Kontrollera först webbläsarens konsol. Typiska fel: MissingKeyMapError (API-nyckel saknas), RefererNotAllowedMapError (domän finns inte i nyckelns tillåtelselista), Cannot read property 'maps' of undefined (API-skriptet laddades inte; kontrollera URL:en och callback). Öppna DevTools på fliken Console och uppdatera sidan; den röda felraden visar omedelbart grundorsaken.

För det andra, se till att containern #mapCanvas finns i DOM:en när drawMap() anropas. Om ditt skript ligger i <head> utan defer har elementet inte renderats än och kartan misslyckas tyst. Attributen [async defer](/orig_post/luchshij-sposob-zagruzit-vneshnij-javascript)<script>-taggen löser detta, men bästa praxis är att placera <script>-taggen i slutet av <body>, efter alla DOM-element.

För det tredje, kontrollera ikonsökvägar. Om marker_exact.png inte finns i images/ relativt HTML-filen returnerar webbläsaren en 404 för bilden och markören renderas som den vanliga röda nålen (eller renderas inte alls, beroende på API-version). Tips: verifiera alltid sökvägar via fliken Network i DevTools genom att filtrera på typen Img; trasiga ikoner markeras omedelbart i rött.

Viktigast av allt: testa alltid med en riktig nyckel. Utan nyckel eller med en ogiltig nyckel mörknar kartan med en "Endast för utvecklingssyfte"-vattenstämpel, och vissa API-metoder returnerar tomma svar. Vi hade ett fall där kartan fungerade perfekt i staging men teckenförklaringen inte visades i produktion: det visade sig att produktionsnyckeln var IP-begränsad, och API:et vägrade tyst kontrollerna. Kontrollera nyckelbegränsningar i Cloud Console före driftsättning.


Vi har täckt hela cykeln: från att skaffa en nyckel till en live-karta med teckenförklaring. Vi testade koden ovan på Google Maps API v3.56 (aktuell i juni 2026); alla fem markörer med anpassade ikoner renderades korrekt, och teckenförklaringen i RIGHT_TOP överlappade inte zoomkontrollerna.

Om du går vidare, ha tre saker i åtanke. För det första: ladda alltid ikoner i den storlek de kommer att visas på kartan, eftersom webbläsarens storleksändring i farten kostar bildrutor vid zoomning. För det andra: för kartor med dussintals markörer är klustring obligatoriskt, annars kommer mobilanvändarna att tacka dig med lagg. För det tredje: håll API-nyckeln under begränsad HTTP-referrer från dag ett, även i utvecklingsmiljöer; en läckt nyckel utan begränsningar är en direkt väg till någon annans trafik på ditt faktureringskonto.

Om uppgiften blir mer komplex (klustring, informationsfönster vid klick, markörfiltrering efter kategorier), låt oss veta i kommentarerna vilket scenario vi ska ta upp härnäst.