Skip to content

Kõik WordPressist, veebiarendusest — ja mitte ainult

📍 Kuidas lisada Google Mapsile mitu kohandatud markerit koos legendiga

📍 Kuidas lisada Google Mapsile mitu kohandatud markerit koos legendiga

Markers on peamine viis kaardil punkti tähistamiseks. Tavaline punane Google Mapsi „nõel" on äratuntav, kuid kui sul on viis eri tüüpi punkti, lähevad vaatajad segadusse: milline neist on täpne aadress ja milline umbkaudne maamärk?

Seda juhtub kogu aeg: poekataloog, mis on jaotatud „ettevõtte omanduses" ja „partner" asukohtadeks, tsoonidega kohaletoimetamise kaart, kaubatüüpidega logistikapaneel. Kõikjal, kus on rohkem kui kolm erineva tähendusega punkti, tekib ilma kohandatud ikoonide ja legendita kaos.

Lahenduseks on kohandatud markeriikoonid ja legend, mis selgitab iga sümbolit. 20 minutiga ehitad mitut tüüpi markeritega kaardi ja kasutajad saavad esmapilgul aru, mis on mis. Praktikas oleme korduvalt näinud, et paar erinevat nõela ja legendiplokk nurgas säästavad kasutajatelt minuteid tõlgendamist ja tugimeeskondadelt kümneid küsimusi stiilis „mida see sinine ring tähendab?".

Allpool on samm-sammuline jaotus, kasutades tavalist JavaScripti, ilma raamistikuteta. Kasutame Eiffeli torni ümbruse koordinaate, mis on mugav ja äratuntava geomeetriaga maamärk. Kood on tahtlikult minimaalne, iga meetod on rida-realt lahti seletatud, et saaksid selle oma ülesande jaoks kohandada ilma kogu dokumentatsiooni lugemata.

Materjal liigub lihtsast keerukamaks: kõigepealt hangid API võtme ja renderdad põhikaardi, seejärel lisad erinevate ikoonidega markerid, ehitad legendi ja lõpuks on sul töötav HTML-fail, mis käivitub kohe. Kõik näited on testitud Google Chrome'is 120+, Firefoxis 121+ ja Safaris 17+.

💡 Kiirülevaade:

  • Hangi Google Maps API võti ja lisa teek
  • Valmista ette punktide massiiv JSON-is: nimi, koordinaadid, tüüp (täpne/ligikaudne)
  • Määra igale tüübile icon atribuudi kaudu oma ikoon
  • Ehita legend HTML-elemendina ja kinnita see kaardile map.controls kaudu
  • Tulemus: üks kaart, kaks visuaalset markeritüüpi, legend paremas ülanurgas

Google Maps API võtme hankimine

JavaScripti Maps API-ga töötamiseks on vaja võtit. Kui sul seda pole, loo see Google Cloud Console'is.

Kiired sammud: mine Console'isse, loo projekt (või vali olemasolev), luba Maps JavaScript API, genereeri võti. Kohaliku arenduse jaoks piisab võtme piiramisest HTTP viitaja järgi; tootmiskeskkonnas lisa oma domeen lubatud nimekirja. Reaalsetes projektides loome alati igale rakendusele eraldi võtme: nii on Cloud Console'is lihtsam kvoote jälgida ja võtme lekke korral täpselt juurdepääs tühistada.

Teegi lisamine võtab ühe rea <script>-s:

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

Atribuut callback määrab, milline funktsioon käivitub pärast API laadimist. Selle kirjutame järgmisena.

Markerid kaardil: kohandatud ikoonid Google Mapsile

Oluline: alates 2024. aasta veebruarist on google.maps.Marker klass ametlikult aegunuks märgitud. See on asendatud klassiga google.maps.marker.AdvancedMarkerElement, mis pakub paremat jõudlust ja toetab kohandatud HTML-i. Allolev kood kasutab klassikalist Marker-it (see töötab endiselt ja sellega on lihtsam alustada) ning KKK jaotis sisaldab linki migratsioonijuhendile AdvancedMarkerElement-ile üleminekuks.

Kaardi lähtestamine ja andmete ettevalmistamine

Esiteks konteiner kaardi jaoks ja koordinaatide massiiv. Kasuta mis tahes endale meelepäraseid koordinaate; siin on meil viis punkti Eiffeli torni ümber Pariisis, kolm täpset ja kaks ligikaudset.

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

Pakendame andmed objektide massiivi. Väli is_exact eraldab markerid kahte tüüpi: need, mis tähistavad täpset aadressi, ja need, mis näitavad üldist piirkonda.

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 on siin lihtsalt mugav formaat: loetav, laiendatav ja iga backend suudab sellise massiivi ühe reaga tagastada.

Kaart ise lähtestatakse google.maps.Map objektiga. Tsentreeri see massiivi esimesele punktile, määra suum nii, et kõik viis mahuksid ära:

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

Kohandatud markerite lisamine erinevate ikoonidega

Ilma kohandatud ikoonita joonistab iga google.maps.Marker kutse standardse punase nõela. Punktitüüpide eristamiseks anna icon atribuudis kaasa oma pilt.

Valmista ette kaks ikooni, näiteks marker_exact.png (roheline nõel täpsetele aadressidele) ja marker_approx.png (sinine ring ligikaudsetele asukohtadele). Paiguta failid HTML-iga samasse kausta images/.

Ikooni valiku loogika kasutab is_exact lipul põhinevat kolmikoperaatorit:

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}

Kõigi markerite korraga paigutamiseks itereeri läbi massiivi:

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

Valmis. Viis punkti, kaks ikooni, kaart teab igast markerist. Meie kogemuse põhjal tuleks selles etapis avada konsool ja kontrollida, kas kõik viis markerit renderdusid: kui ikooni määratud teekonnal ei leitud, taandub marker vaikimisi nõelale ja sa ei pruugi seda visuaalselt isegi märgata. Kuid vaataja ei saa sellest veel aru. Ta vajab legendi.

Paar sõna ikoonidest. Optimaalne suurus on 40×40 px tavalistel ekraanidel ja 80×80 px Retina puhul (määra icon atribuudis suurem fail ja sea scaledSize väärtuseks new google.maps.Size(40,40); pilt on retina ekraanidel terav). Formaat võib olla PNG, SVG või WebP, kuid kohandatud nõelte puhul eelistame SVG-d: see kaalub vähem, skaleerub ilma pikslitumiseta ja seda on lihtne redigeerida. Kui kasutad siiski PNG-d, vali 24-bitine alfakanaliga variant; vastasel juhul tekib nõela ümber valge taust, mis tundel kaartidel paistab kohatu.

Levinud viga: ikoonifaili tee määramine HTML-i, mitte serveri juure suhtes. Paiguta marker_exact.png samasse kausta kui index.html ja määra "marker_exact.png" ilma eesliiteta kaldkriipsuta. Kui ikoonid on alamkaustas nagu images/, on tee "images/marker_exact.png", täpselt nagu ülaltoodud koodis näidatud.

Legendi loomine markeritele

Legend on lihtsalt tavaline DOM-element, mille paigutame kaardi juhtelementide tsooni. Google Maps võimaldab paigutada juhtelemendi ühte standardsetest positsioonidest: näiteks TOP_LEFT, TOP_CENTER või RIGHT_TOP. Legendi puhul on mõistlik parem ülemine nurk.

Esmalt kirjelda konteiner HTML-is ja kujunda see:

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}

Nüüd täida legend "ikoon + silt" ridadega ja anna see kaardile:

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

Järjekord on oluline: esmalt koosta legend kui DOM-sõlm, seejärel lükka see kaardile. Kui teed vastupidi, jääb juhtelement tühjaks.

Täielik kood: kõige kokkupanek

Kombineeri HTML, CSS ja JavaScript ühte faili. Salvesta see kui index.html, asenda YOUR_API_KEY töötava võtmega ja ava brauseris.

Kaart kohandatud markerite ja legendiga Google Mapsis

Siin on lõplik loetelu:

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>

Asenda YOUR_API_KEY ja kaart ärkab ellu. Kolmanda markeritüübi lisamine tähendab veel üht ikooni, veel üht div elementi legendis ja veel üht tingimust funktsioonis plotMarker. See skaleerub lineaarselt.

Selle koodi oma projekti ülekandmisel pööra tähelepanu kahele asjale. Esiteks: reaalses rakenduses tulevad locations andmed tõenäoliselt backendist fetch-i või XMLHttpRequest-i kaudu, mitte ei ole <script> sisse kodeeritud. Teiseks: kui punkte on üle kümne, vii massiiv eraldi .json faili ja laadi see asünkroonselt; see hoiab HTML-i loetavana ja väldib kaardi lehe renderdamise blokeerimist.

Tootmiskeskkonnas kümnete markerite puhul lisa klasterdamine @googlemaps/markerclusterer teegi abil: see grupeerib lähedased punktid numbritega ringideks ja laiendab need sissesuumimisel üksikuteks nõelteks. Paigalda npm-i kaudu (npm i @googlemaps/markerclusterer) ja ühenda kolme reaga: new MarkerClusterer({ map, markers }). Ilma klasterdamiseta muudavad viiskümmend markerit linna suumitasemel kaardi loetamatuks kattuvate ikoonide segaduseks.

⁉️🤔 Korduma kippuvad küsimused

Kas markeri ikoonide jaoks saab PNG asemel kasutada SVG-d?

Jah, Google Maps aktsepteerib kõiki formaate, mida brauser suudab renderdada: PNG, SVG, WebP. SVG on eriti mugav, kuna see ei muutu suumimisel piksliseks ja kaalub vähem. Anna .svg faili tee icon atribuudis täpselt samamoodi nagu PNG puhul. Määra ikooni suurus SVG faili enda width/height atribuutide kaudu: Google Maps kasutab neid alusena ja skaleerib vastavalt ekraani tihedusele.

Kuidas migreeruda google.maps.Markerilt AdvancedMarkerElementile?

Alates 2024. aasta veebruarist on google.maps.Marker märgitud aegunuks. Uus google.maps.marker.AdvancedMarkerElement klass kasutab icon atribuudi asemel HTML-sisu, nii et saad markerisse otse lisada nupu, märgise või animeeritud SVG. Lisa markerite teek (&libraries=marker API URL-i) ja asenda konstruktoris icon atribuut content-iga, mis sisaldab DOM elementi:

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>

Sisu võib olla ükskõik milline DOM element: <img>, taustaga <div> või SVG. Ametlik migreerimisjuhend käsitleb iga asendusstsenaariumi samm-sammult koos näidetega.

Kuidas lisada legendi kaardi mobiiliversioonis?

RIGHT_TOP juhtelement kattub kitsastel ekraanidel (alla 480 px) kaardiga. Lahenduseks on CSS-i meediapäring: max-width: 480px korral liiguta legend asukohta BOTTOM_CENTER või vähenda fondi suurust ja polsterdust poole võrra. Alternatiiv on paigutada legend staatilise plokina kaardist väljapoole ja sünkroniseerida olekut JavaScripti abil. BOTTOM_CENTER jaoks muuda lihtsalt asukohta buildLegend() funktsiooni sees.

Kui palju markereid suudab kaart hallata ilma jõudlusprobleemideta?

Kuni 100 markerit ekraanil ei põhjusta märgatavat viivitust isegi keskmise võimekusega nutitelefonidel. 100 kuni 500 markeri puhul hakkavad suumimisel ja panoraamimisel ilmnema viivitused. 500+ markeri korral lülita sisse klasterdamine; Google pakub valmis teeki @googlemaps/markerclusterer, mis koondab lähedased markerid nummerdatud ringideks. Praktikas: 50 markerit 2 KB PNG ikoonidega tähendab 100 KB allalaadimist ja kohest renderdamist. 500 markerit ilma klasterdamiseta tähendab, et kaart teeb ~500 drawImage() väljakutset suumi kaadri kohta, mis muutub märgatavaks.

Mida teha, kui markerid ei kuvata

Esiteks kontrolli brauseri konsooli. Tüüpilised vead: MissingKeyMapError (API võti on esitamata), RefererNotAllowedMapError (domeen ei ole võtme lubatud nimekirjas), Cannot read property 'maps' of undefined (API skript ei laadinud; kontrolli URL-i ja callback-i). Ava DevTools konsooli vahekaardil ja värskenda lehte; punane vearida näitab kohe algpõhjust.

Teiseks veendu, et #mapCanvas konteiner on DOM-is olemas, kui drawMap() välja kutsutakse. Kui su skript on <head>-is ilma defer-ita, ei ole elementi veel renderdatud ja kaart ebaõnnestub hääletult. [async defer](/orig_post/luchshij-sposob-zagruzit-vneshnij-javascript) atribuudid <script> sildil lahendavad selle, kuid parim tava on paigutada <script> silt <body> lõppu, pärast kõiki DOM elemente.

Kolmandaks kontrolli ikoonide teekondi. Kui marker_exact.png ei asu HTML-faili suhtes kataloogis images/, tagastab brauser pildi jaoks 404 vea ja marker renderdatakse standardse punase tihvtina (või ei renderdata üldse, sõltuvalt API versioonist). Nipp: kontrolli teekondi alati DevToolsi võrgu vahekaardil, filtreerides pildi tüübi järgi; katkised ikoonid tõstetakse kohe punaselt esile.

Kõige tähtsam: testi alati reaalse võtmega. Ilma võtmeta või kehtetu võtmega tumeneb kaart vesimärgiga „Ainult arenduseks" ja mõned API meetodid tagastavad tühje vastuseid. Meil oli juhtum, kus kaart töötas lavastuskeskkonnas ideaalselt, kuid legend ei kuvatud toodangus: selgus, et toodangu võti oli IP-piiranguga ja API keeldus hääletult juhtelementidest. Kontrolli võtme piiranguid Cloud Console'is enne juurutamist.


Käsitlesime tervet tsüklit: alates võtme hankimisest kuni reaalajas kaardini koos legendiga. Testisime ülaltoodud koodi Google Maps API v3.56-ga (kehtiv 2026. aasta juuni seisuga); kõik viis markerit kohandatud ikoonidega renderdati korrektselt ja legend asukohas RIGHT_TOP ei kattunud suumi juhtelementidega.

Kui lähed edasi, pea meeles kolme asja. Esiteks: laadi ikoonid alati sellises suuruses, nagu need kaardil kuvatakse, sest brauseri poolt lennult suuruse muutmine maksab suumimisel kaadreid. Teiseks: kümnete markeritega kaartide puhul on klasterdamine kohustuslik, vastasel juhul tänavad mobiilsed kliendid sind viivitusega. Kolmandaks: hoia API võtit piiratud HTTP viitaja taga esimesest päevast alates, isegi arenduskeskkondades; piiranguteta lekkinud võti on otsetee kellegi teise liiklusele sinu arvelduskontol.

Kui ülesanne muutub keerukamaks (klasterdamine, infoaknad klikil, markerite filtreerimine kategooriate järgi), anna meile kommentaarides teada, millist stsenaariumi järgmisena käsitleda.