Skip to content

Kaikki WordPressistä, web-kehityksestä — ja paljon muuta

📍 Näin lisäät useita mukautettuja markkereita selitteellä Google Mapsiin

📍 Näin lisäät useita mukautettuja markkereita selitteellä Google Mapsiin

Merkit ovat ensisijainen tapa osoittaa piste kartalla. Tavallinen punainen Google Mapsin "nasta" on tunnistettava, mutta kun sinulla on viisi erityyppistä pistettä, katsojat menevät sekaisin: mikä on tarkka osoite ja mikä karkea maamerkki?

Näin kähtyy jatkuvasti: myymälähakemisto, joka on jaettu "omistamiin" ja "kumppani"-toimipisteisiin, jakelukartta vyöhykkeineen, logistiikkanäkymä lastityyppeineen. Aina kun sinulla on yli kolme pistettä, joilla on eri merkitys, syntyy kaaos ilman mukautettuja kuvakkeita ja selitettä.

Ratkaisu on mukautetut merkkikuvakkeet ja selite, joka selittää jokaisen symbolin. Kahdessakymmenessä minuutissa rakennat kartan, jossa on useita merkkityyppejä, ja käyttäjät ymmärtävät ensisilmäyksellä, mikä on mitäkin. Käytännössä olemme nähneet kerta toisensa jälkeen, että pari erilaista nastaa ja selitelohko nurkassa säästävät käyttäjiltä minuuttien tulkinnan ja tukitiimeiltä kymmeniä "mitä sininen ympyrä tarkoittaa?" -kysymyksiä.

Alla on vaiheittainen erittely käyttäen pelkkää JavaScriptiä, ilman sovelluskehyksiä. Käytämme koordinaatteja Eiffel-tornin ympärillä, joka on kätevä maamerkki tunnistettavine geometrioineen. Koodi on tarkoituksella minimaalista, ja jokainen metodi selitetään rivi riviltä, jotta voit mukauttaa sen omaan tehtävääsi lukematta koko dokumentaatiota.

Materiaali etenee yksinkertaisesta monimutkaiseen: ensin hankit API-avaimen ja renderöit peruskartan, sitten lisäät merkkejä eri kuvakkeilla, rakennat selitteen ja lopulta sinulla on toimiva HTML-tiedosto, joka toimii suoraan laatikosta. Kaikki esimerkit on testattu Google Chromella 120+, Firefoxilla 121+ ja Safarilla 17+.

💡 Pikakatsaus:

  • Hanki Google Maps API -avain ja sisällytä kirjasto
  • Valmistele joukko pisteitä JSON-muodossa: nimi, koordinaatit, tyyppi (tarkka/likimääräinen)
  • Määritä jokaiselle tyypille oma kuvakkeensa icon-ominaisuuden kautta
  • Rakenna selite HTML-elementtinä ja liitä se karttaan map.controls-komennolla
  • Lopputulos: yksi kartta, kaksi visuaalista merkkityyppiä, selite oikeassa yläkulmassa

Google Maps API -avaimen hankkiminen

JavaScript Maps API:n käyttö vaatii avaimen. Jos sinulla ei ole sellaista, luo se Google Cloud Consolessa.

Pikavaiheet: mene Consoleen, luo projekti (tai valitse olemassa oleva), ota Maps JavaScript API käyttöön, luo avain. Paikalliseen kehitykseen riittää avaimen rajoittaminen HTTP-referrerin perusteella; tuotantoa varten lisää verkkotunnuksesi sallittujen listalle. Oikeissa projekteissa luomme aina erillisen avaimen jokaiselle sovellukselle: kiintiöiden seuranta Cloud Consolessa on helpompaa ja pääsyn voi peruuttaa tarkasti, jos avain vuotaa.

Kirjaston sisällyttäminen vie yhden rivin <script>-tagissa:

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

callback-attribuutti määrittää, mikä funktio suoritetaan API:n latauduttua. Kirjoitamme sen seuraavaksi.

Merkit kartalla: mukautetut kuvakkeet Google Mapsiin

Tärkeää: helmikuusta 2024 lähtien google.maps.Marker-luokka on virallisesti merkitty vanhentuneeksi. Sen on korvannut google.maps.marker.AdvancedMarkerElement, joka tarjoaa paremman suorituskyvyn ja tukee mukautettua HTML:ää. Alla oleva koodi käyttää klassista Marker-luokkaa (se toimii edelleen ja on helpompi aloittaa), ja UKK-osio sisältää linkin migraatio-oppaaseen AdvancedMarkerElementiin siirtymiseksi.

Kartan alustaminen ja datan valmistelu

Ensin kartalle kontti ja joukko koordinaatteja. Käytä mitä tahansa koordinaatteja; tässä meillä on viisi pistettä Eiffel-tornin ympärillä Pariisissa, kolme tarkkaa ja kaksi likimääräistä.

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

Paketoimme datan oliotaulukkoon. is_exact-kenttä erottelee merkit kahteen tyyppiin: ne, jotka osoittavat tarkan osoitteen, ja ne, jotka ilmaisevat yleisen alueen.

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 tässä yksinkertaisesti kätevä muoto: luettava, laajennettava, ja mikä tahansa taustajärjestelmä voi palauttaa tällaisen taulukon yhdellä rivillä.

Itse kartta alustetaan google.maps.Map-oliolla. Keskitä se taulukon ensimmäiseen pisteeseen, aseta zoomaus niin, että kaikki viisi mahtuvat:

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

Mukautettujen merkkien lisääminen eri kuvakkeilla

Ilman mukautettua kuvaketta jokainen google.maps.Marker-kutsu piirtää tavallisen punaisen neulan. Erottaaksesi pistetyypit toisistaan, anna oma kuva icon-ominaisuudessa.

Valmistele kaksi kuvaketta, esimerkiksi marker_exact.png (vihreä neula tarkoille osoitteille) ja marker_approx.png (sininen ympyrä likimääräisille sijainneille). Sijoita tiedostot images/-kansioon HTML-tiedoston rinnalle.

Kuvakkeen valintalogiikka käyttää ternary-operaattoria is_exact-lipun perusteella:

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}

Sijoittaaksesi kaikki merkit kerralla, käy taulukko läpi:

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

Valmista. Viisi pistettä, kaksi kuvaketta, kartta tietää jokaisesta merkistä. Kokemuksemme mukaan tässä vaiheessa kannattaa avata konsoli ja varmistaa, että kaikki viisi merkkiä renderöityivät: jos kuvaketta ei löydy määritetystä polusta, merkki palautuu hiljaisesti oletusneulaan, etkä välttämättä edes huomaa sitä visuaalisesti. Mutta katsoja ei vielä ymmärrä. Hän tarvitsee selitteen.

Muutama sana kuvakkeista. Optimaalinen koko on 40×40 px tavallisille näytöille ja 80×80 px Retina-näytöille (määritä suurempi tiedosto icon-attribuutissa ja aseta scaledSize arvoon new google.maps.Size(40,40); kuva on terävä retina-näytöillä). Formaatti voi olla mikä tahansa PNG/SVG/WebP, mutta mukautetuille neuloille suosimme SVG:tä: se painaa vähemmän, skaalautuu ilman pikselöitymistä ja on helppo muokata. Jos käytät edelleen PNG:tä, valitse 24-bittinen alfakanavalla; muuten neulan ympärille ilmestyy valkoinen tausta, joka näyttää vieraalta tummilla kartoilla.

Yleinen virhe: kuvaketiedoston polun määrittäminen suhteessa HTML:ään eikä palvelimen juureen. Sijoita marker_exact.png samaan kansioon kuin index.html ja määritä "marker_exact.png" ilman alkavaa kauttaviivaa. Jos kuvakkeet ovat alikansiossa kuten images/, polku on "images/marker_exact.png", täsmälleen kuten yllä olevassa koodissa näytetään.

Selitteen luominen merkeille

Selite on vain tavallinen DOM-elementti, jonka sijoitamme kartan hallintavyöhykkeelle. Google Maps antaa sinun sijoittaa hallintaelementin johonkin vakiopaikoista: esimerkiksi TOP_LEFT, TOP_CENTER tai RIGHT_TOP. Selitteelle oikea yläkulma on järkevä.

Kuvaa ensin säiliö HTML:ssä ja tyylittele se:

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}

Täytä nyt selite "kuvake + teksti" -riveillä ja anna se kartalle:

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ärjestyksellä on väliä: kokoa ensin legend DOM-solmuksi ja työnnä se sitten. Jos teet tämän päinvastoin, hallintaelementti jää tyhjäksi.

Koko koodi: kaiken yhdistäminen

Yhdistä HTML, CSS ja JavaScript yhdeksi tiedostoksi. Tallenna se nimellä index.html, korvaa YOUR_API_KEY toimivalla avaimella ja avaa se selaimessa.

Kartta, jossa mukautetut merkit ja selite Google Mapsissa

Tässä lopullinen listaus:

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>

Korvaa YOUR_API_KEY, ja kartta herää eloon. Kolmannen merkkityypin lisääminen tarkoittaa uutta kuvaketta, uutta div-elementtiä selitteessä ja uutta ehtoa plotMarker-funktiossa. Se skaalautuu lineaarisesti.

Kun siirrät tämän koodin projektiisi, kiinnitä huomiota kahteen asiaan. Ensinnäkin: oikeassa sovelluksessa locations-data tulee todennäköisesti backendistä fetch- tai XMLHttpRequest-kutsun kautta sen sijaan, että se olisi kovakoodattu <script>-elementtiin. Toiseksi: jos sinulla on yli kymmenen pistettä, siirrä taulukko erilliseen .json-tiedostoon ja lataa se asynkronisesti; tämä pitää HTML:n luettavana ja estää karttaa estämästä sivun renderöintiä.

Tuotantoon, jossa on kymmeniä merkkejä, lisää klusterointi @googlemaps/markerclusterer-kirjaston avulla: se ryhmittelee lähekkäiset pisteet ympyröiksi numeroineen ja laajentaa ne sitten yksittäisiksi neuloiksi zoomattaessa. Asenna npm:n kautta (npm i @googlemaps/markerclusterer) ja yhdistä kolmella rivillä: new MarkerClusterer({ map, markers }). Ilman klusterointia viisikymmentä merkkiä kaupunkizoomilla muuttaa kartan lukukelvottomaksi päällekkäisten kuvakkeiden sekamelskaksi.

⁉️🤔 Usein kysytyt kysymykset

Voinko käyttää SVG:tä PNG:n sijaan merkkikuvakkeissa?

Kyllä, Google Maps hyväksyy minkä tahansa formaatin, jonka selain pystyy renderöimään: PNG, SVG, WebP. SVG on erityisen kätevä, koska se ei pikselöidy zoomattaessa ja painaa vähemmän. Anna .svg-tiedoston polku icon-ominaisuudessa aivan kuten PNG:lle. Aseta kuvakkeen koko itse SVG-tiedoston width/height-attribuuteilla: Google Maps käyttää niitä perustana ja skaalaa näyttötiheyksien mukaan.

Miten siirryn google.maps.Markerista AdvancedMarkerElementiin?

Helmikuusta 2024 alkaen google.maps.Marker on merkitty vanhentuneeksi. Uusi google.maps.marker.AdvancedMarkerElement-luokka käyttää HTML-sisältöä icon-ominaisuuden sijaan, joten voit lisätä painikkeen, merkin tai animoidun SVG:n suoraan markkeriin. Sisällytä marker-kirjasto (&libraries=marker API-URL:ssa) ja korvaa konstruktorissa icon content-kentällä, joka sisältää DOM-elementin:

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>

Sisältö voi olla mikä tahansa DOM-elementti: <img>, taustan sisältävä <div> tai SVG. Virallinen migraatio-opas käy läpi jokaisen korvaustilanteen vaihe vaiheelta esimerkkien kera.

Miten lisään selitteen kartan mobiiliversioon?

RIGHT_TOP-ohjain peittää kartan kapeilla näytöillä (alle 480 px). Ratkaisu on CSS-media query: max-width: 480px -säännöllä siirrä selite kohtaan BOTTOM_CENTER tai puolita fonttikoko ja täyte. Vaihtoehto on sijoittaa selite kartan ulkopuolelle staattisena lohkona ja synkronoida tila JavaScriptillä. BOTTOM_CENTER-sijaintia varten muuta vain sijainti buildLegend()-funktion sisällä.

Kuinka monta markkeria kartta kestää ilman suorituskykyongelmia?

Jopa 100 markkeria ruudulla ei aiheuta havaittavaa viivettä edes keskitason älypuhelimilla. 100:sta 500:aan alkaa näkyä viiveitä zoomatessa ja panoroidessa. Yli 500 markkerille ota käyttöön klusterointi; Google tarjoaa valmiin @googlemaps/markerclusterer-kirjaston, joka ryhmittelee lähekkäiset markkerit numeroituihin ympyröihin. Käytännössä: 50 markkeria 2 kt:n PNG-kuvakkeilla tarkoittaa 100 kt:n latauksia ja välitöntä renderöintiä. 500 markkeria ilman klusterointia tarkoittaa, että kartta tekee noin 500 drawImage()-kutsua zoomaustasoa kohden, mikä alkaa tuntua.

Mitä tehdä, jos markkerit eivät näy

Tarkista ensin selaimen konsoli. Tyypillisiä virheitä: MissingKeyMapError (API-avainta ei annettu), RefererNotAllowedMapError (verkkotunnus ei ole avaimen sallittujen listalla), Cannot read property 'maps' of undefined (API-skripti ei latautunut; tarkista URL ja callback). Avaa DevTools Console-välilehdellä ja päivitä sivu; punainen virherivi näyttää heti perimmäisen syyn.

Toiseksi, varmista, että #mapCanvas-säiliö on olemassa DOMissa, kun drawMap() kutsutaan. Jos skriptisi on <head>-osiossa ilman defer-määrettä, elementtiä ei ole vielä renderöity ja kartta epäonnistuu hiljaisesti. <script>-tagin [async defer](/orig_post/luchshij-sposob-zagruzit-vneshnij-javascript)-attribuutit ratkaisevat tämän, mutta paras käytäntö on sijoittaa <script>-tagi <body>-osion loppuun, kaikkien DOM-elementtien jälkeen.

Kolmanneksi, tarkista kuvakkeiden polut. Jos marker_exact.png ei ole images/-kansiossa suhteessa HTML-tiedostoon, selain palauttaa kuvalle 404-virheen ja markkeri näkyy tavallisena punaisena neulana (tai ei näy ollenkaan API-versiosta riippuen). Vinkki: tarkista polut aina DevToolsin Network-välilehdeltä suodattamalla Img-tyypillä; rikkinäiset kuvakkeet korostuvat punaisella välittömästi.

Tärkeintä: testaa aina oikealla avaimella. Ilman avainta tai virheellisellä avaimella kartta tummuu ja siinä lukee "For development purposes only" -vesileima, ja jotkin API-metodit palauttavat tyhjiä vastauksia. Meillä oli tapaus, jossa kartta toimi täydellisesti staging-ympäristössä, mutta selite ei näkynyt tuotannossa: kävi ilmi, että tuotantoavain oli rajattu IP-osoitteella, ja API kieltäytyi hiljaisesti ohjaimista. Tarkista avaimen rajoitukset Cloud Consolesta ennen julkaisua.


Kävimme läpi koko syklin: avaimen hankinnasta toimivaan karttaan selitteineen. Testasimme yllä olevan koodin Google Maps API v3.56:lla (ajantasainen kesäkuussa 2026); kaikki viisi markkeria mukautetuilla kuvakkeilla renderöityivät oikein, eikä RIGHT_TOP-kohdassa oleva selite peittänyt zoomausohjaimia.

Jos etenet pidemmälle, pidä mielessä kolme asiaa. Ensinnäkin: lataa kuvakkeet aina siinä koossa, jossa ne näkyvät kartalla, sillä selaimen lennossa tekemä koonmuutos maksaa ruutuja zoomauksen aikana. Toiseksi: kartoissa, joissa on kymmeniä markkereita, klusterointi on pakollinen, muuten mobiilikäyttäjät kiittävät sinua viiveellä. Kolmanneksi: pidä API-avain rajatun HTTP-referrerin takana heti ensimmäisestä päivästä lähtien, myös dev-ympäristöissä; vuotanut, rajoittamaton avain on suora tie jonkun toisen liikenteeseen omalla laskutustililläsi.

Jos tehtävä muuttuu monimutkaisemmaksi (klusterointi, info-ikkunat klikkauksesta, markkereiden suodatus kategorioiden mukaan), kerro kommenteissa, minkä skenaarion käsittelemme seuraavaksi.