Last updated: Nov 23, 2022
Â
You’ve got a Google Map set up and want to place markers on it. You don’t want to go with the default, red markers — you want your brand to stand out.
In this step-by-step guide we’ll analyze four hands-on approaches and help you understand & implement advanced map markers.
Also check out our Google Maps Handbook, esp. the chapters on 💠Markers, Lines, & Shapes and 🏷️ Custom Marker Labels.
Need a professional to take a look at your use case? Book a consulting session.
Â
Approach #1 — Image URLs (jpg, png, …) DemoApproach #2 — Encoded SVGs as Data URLsA Primer on SVG EncodingMarker InteractionsDemoApproach #3 — Native Advanced MarkersPrerequisitesFrom SVG Markup to DOM ElementsCustom HTML with StylingDemoApproach #4 — WebGL Markers Using Deck.glHigh-Level Deck.gl ProcessWhen should I use Deck.gl to display markers?ImplementationDemoLooking for Google Maps pros?
Â
Approach #1 — Image URLs (jpg, png, …)
Assuming you’ve initialized your map:
const myMap = new google.maps.Map({ ... });
const marker = new google.maps.Marker({ map: myMap, position: { lat: 48.7277, lng: 21.2453, }, icon: { url: 'https://...', } });
Google Maps will now take this image and render it in its original size.
Â
If you need to downsize the image, eg. to 36 Ă— 36px, you can use
scaledSize
:const marker = new google.maps.Marker({ ... icon: { url: '...', scaledSize: new google.maps.Size(36, 36), } });
Â
Depending on your image dimensions and shape, the marker placement may appear off. That’s because, by default, “the anchor is located along the center point of the bottom of the image”.
Let’s say you don’t like this default behavior (left) and you’d want your custom marker fully centered (right):
You can use the
anchor
property to position the image to your liking:const marker = new google.maps.Marker({ ... icon: { url: '...', scaledSize: new google.maps.Size(36, 36), anchor: new google.maps.Point(18, 18), } });
Note that
Point(0,0)
starts top-left and Point(imgWidth,imgHeight)
ends bottom-right. To fully center your image, divide its dimensions in half — e.g. Point(18, 18)
as in the case above.Demo
Â
Approach #2 — Encoded SVGs as Data URLs
Â
SVGs are great for map use because they’re vector-based — they scale well and, unlike with JPEGs or PNGs, you’ll avoid pixelation.
But SVGs are also notoriously hard to understand. And edit. You’ll need a tool like Figma to efficiently customize & export them.
Â
Though once you’ve got working understanding of SVGs, you’ll be able to take your map markers to the next level.
See, thegoogle.maps.Icon
interface supports Data URLs inside theurl
property. This means that virtually ANY svg, if correctly encoded, can be passed onto the map canvas.
A Primer on SVG Encoding
In short, you’ll need to take your tag-based SVG:
<svg xmlns="http://www.w3.org/2000/svg" width="40" height="56" viewBox="0 0 40 56" fill="none"> ... </svg>
and URL-encode it so that it starts with
data:image/svg+xml,
:data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='40' height='56' viewBox='0 0 40 56' fill='none'%3E%3Cpath d='M20 0C14.6957 0 9.60859 2.10714 5.85786 5.85786C2.10714 9.60859 0 14.6957 0 20C0 36 18 43 18 53V54C18 54.5304 18.2107 55.0391 18.5858 55.4142C18.9609 55.7893 19.4696 56 20 56C20.5304 56 21.0391 55.7893 21.4142 55.4142C21.7893 55.0391 22 54.5304 22 54V53C22 43 40 36 40 20C40 14.6957 37.8929 9.60859 34.1421 5.85786C30.3914 2.10714 25.3043 0 20 0Z' fill='white'/%3E%3Cpath d='M40 20.0755C40 29.1094 34.2421 35.4279 29.1579 40.9962C24.9895 45.5608 22 48.4283 22 53.5C22 55.5 21.1974 55.8018 21 56C20.8026 56.1982 20.2792 56 20 56C19.7208 56 19.6974 56.1982 19.5 56C19.3026 55.8018 19.5 56.5 18 55C18 49.9283 15.0211 45.5608 10.8526 40.9962C5.76842 35.4279 0 29.1094 0 20.0755C0 14.7511 2.10714 9.64485 5.85787 5.87997C9.60859 2.11509 14.6957 0 20 0C25.3043 0 30.3914 2.11509 34.1421 5.87997C37.8929 9.64485 40 14.7511 40 20.0755Z' fill='%2330455D'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12.7722 25.7398C12.7722 25.9242 12.7722 26.1087 12.7722 26.2932C12.6818 27.5974 12.7741 28.8886 13.0489 30.1668C16.8656 32.0283 20.647 31.9821 24.393 30.0284C27.6995 26.7802 27.6995 23.5522 24.393 20.3444C22.0842 19.3292 19.7785 18.3146 17.4759 17.3009C16.0494 15.2791 16.5106 13.8034 18.8593 12.8739C21.295 12.5786 23.5546 13.0859 25.6381 14.3957C25.8673 13.0947 25.8212 11.8035 25.4998 10.522C22.0528 9.02938 18.6403 9.07548 15.2624 10.6604C12.5914 12.5875 11.8075 15.1238 12.9106 18.2693C13.7824 19.5564 14.9353 20.4787 16.3691 21.0361C16.2769 21.2206 16.1847 21.405 16.0924 21.5895C15.65 21.5154 15.2811 21.6076 14.9857 21.8662C14.8012 21.8662 14.709 21.9584 14.709 22.1429C13.244 21.164 12.0912 19.8728 11.2504 18.2693C10.2345 12.8598 12.3096 9.49344 17.4759 8.17022C20.5183 7.76324 23.4696 8.08605 26.3298 9.13862C26.7042 9.46658 27.027 9.83548 27.2982 10.2454C28.5309 15.7458 26.6864 17.1293 21.7645 14.3957C20.995 14.4977 20.2572 14.4977 19.551 14.3957C18.1599 14.9029 18.0215 15.5946 19.136 16.4708C21.228 17.1479 23.257 17.978 25.2231 18.961C28.3743 21.6342 29.1581 24.9083 27.5749 28.7833C26.3137 30.9606 24.423 32.2981 21.9029 32.7953C18.518 33.3118 15.29 32.8509 12.2188 31.4118C11.0597 29.7523 10.8292 27.9539 11.5271 26.0165C11.8382 25.0918 12.2533 24.9996 12.7722 25.7398Z' fill='%23293E56'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M12.7722 26.2932C14.4518 27.3758 16.2964 28.0214 18.3059 28.23C19.4698 28.3835 20.4843 28.1068 21.3494 27.3999C22.5969 26.6501 23.0119 25.5434 22.5945 24.0797C22.3985 23.836 22.168 23.6516 21.9028 23.5263C21.059 22.9199 20.1367 22.4588 19.1359 22.1429C18.2339 21.7862 17.3116 21.4173 16.3691 21.0361C14.9352 20.4787 13.7823 19.5564 12.9105 18.2693C11.8074 15.1238 12.5913 12.5875 15.2623 10.6604C18.6403 9.07548 22.0528 9.02939 25.4997 10.5221C25.8211 11.8035 25.8672 13.0947 25.6381 14.3957C23.5546 13.0859 21.2949 12.5786 18.8593 12.8739C16.5105 13.8034 16.0494 15.2791 17.4758 17.3009C19.7784 18.3146 22.0841 19.3292 24.393 20.3444C27.6995 23.5522 27.6995 26.7802 24.393 30.0284C20.6469 31.9821 16.8656 32.0283 13.0488 30.1668C12.774 28.8886 12.6818 27.5974 12.7722 26.2932Z' fill='%23F7F8F8'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M16.3691 21.0361C17.3116 21.4173 18.2339 21.7862 19.136 22.1428C19.136 22.2351 19.136 22.3273 19.136 22.4195C18.5956 22.0048 18.1345 22.0971 17.7525 22.6962C17.1125 22.4194 16.5591 22.0505 16.0924 21.5895C16.1846 21.405 16.2769 21.2206 16.3691 21.0361Z' fill='%23587697'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M14.9857 21.8662C15.2811 21.6076 15.65 21.5154 16.0925 21.5895C16.5592 22.0505 17.1125 22.4194 17.7526 22.6962C18.1345 22.0971 18.5957 22.0048 19.136 22.4195C19.0096 23.0484 18.6407 23.4173 18.0293 23.5263C16.9705 23.0432 15.9559 22.4898 14.9857 21.8662Z' fill='%2381AB70'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M14.9857 21.8662C15.956 22.4899 16.9705 23.0432 18.0293 23.5263C18.0768 23.8007 17.9845 23.9852 17.7526 24.0797C17.2327 24.3125 16.6793 24.4047 16.0925 24.3564C16.0925 24.7253 16.0925 25.0942 16.0925 25.4631C15.485 25.0929 14.9316 24.6318 14.4324 24.0797C14.4324 23.803 14.4324 23.5263 14.4324 23.2496C14.6909 22.9543 14.7832 22.5853 14.7091 22.1429C14.7091 21.9584 14.8013 21.8662 14.9857 21.8662Z' fill='%23D9F2A4'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M19.136 22.1429C20.1367 22.4587 21.059 22.9199 21.9029 23.5263C21.6949 24.4248 21.5566 25.347 21.4878 26.2931C21.3725 26.6407 21.1419 26.8251 20.7961 26.8465C20.3808 26.5002 19.9197 26.2236 19.4127 26.0165C18.9515 25.832 18.4904 25.6476 18.0292 25.4631C17.9936 24.9883 17.9014 24.5271 17.7526 24.0797C17.9845 23.9851 18.0767 23.8006 18.0292 23.5263C18.6407 23.4173 19.0096 23.0484 19.136 22.4195C19.136 22.3273 19.136 22.2351 19.136 22.1429Z' fill='%232746A7'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M17.7525 24.0797C17.9014 24.5271 17.9936 24.9883 18.0292 25.4631C17.7738 25.2409 17.4971 25.1948 17.1992 25.3247C17.5343 25.5718 17.5343 25.8023 17.1992 26.0165C16.7771 25.8797 16.4082 25.6952 16.0924 25.4631C16.0924 25.0942 16.0924 24.7252 16.0924 24.3563C16.6792 24.4047 17.2326 24.3125 17.7525 24.0797Z' fill='%236CAFCE'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M14.4323 24.0797C14.9316 24.6317 15.4849 25.0928 16.0925 25.4631C16.4082 25.6952 16.7771 25.8797 17.1992 26.0165C17.5343 25.8023 17.5343 25.5718 17.1992 25.3247C17.4971 25.1948 17.7738 25.2409 18.0293 25.4631C18.4904 25.6475 18.9515 25.832 19.4127 26.0165C18.7524 25.9497 18.1991 26.1342 17.7526 26.5698C17.736 26.4196 17.6438 26.3273 17.4759 26.2931C15.2602 27.3113 14.2457 26.5734 14.4323 24.0797Z' fill='%234C94CF'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M21.9028 23.5263C22.168 23.6516 22.3986 23.836 22.5945 24.0796C23.0119 25.5434 22.5969 26.6501 21.3495 27.3999C21.165 27.2154 20.9805 27.031 20.7961 26.8465C21.1419 26.8251 21.3724 26.6407 21.4878 26.2931C21.5566 25.347 21.6949 24.4248 21.9028 23.5263Z' fill='%2320285D'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M14.4323 23.2496C14.4323 23.5263 14.4323 23.803 14.4323 24.0797C14.2456 26.5735 15.2602 27.3113 17.4759 26.2932C17.6437 26.3274 17.7359 26.4196 17.7525 26.5698C17.6685 26.7497 17.5762 26.9341 17.4759 27.1232C17.7593 27.4972 18.036 27.8661 18.3059 28.23C16.2964 28.0215 14.4519 27.3758 12.7722 26.2932C12.7722 26.1087 12.7722 25.9243 12.7722 25.7398C12.7528 24.3949 13.2601 23.2881 14.294 22.4196C14.4276 22.6819 14.4737 22.9585 14.4323 23.2496Z' fill='%23376ABC'/%3E%3Cpath fill-rule='evenodd' clip-rule='evenodd' d='M19.4127 26.0165C19.9197 26.2235 20.3808 26.5002 20.7961 26.8465C20.9806 27.031 21.165 27.2154 21.3495 27.3999C20.4843 28.1068 19.4698 28.3835 18.3059 28.2299C18.036 27.8661 17.7593 27.4972 17.4759 27.1232C17.5762 26.9341 17.6685 26.7496 17.7526 26.5698C18.1991 26.1342 18.7524 25.9497 19.4127 26.0165Z' fill='%236F9048'/%3E%3C/svg%3E
and thus becomes a valid Data URL.
Â
For testing purposes you can use a tool like yoksel.github.io to encode the SVGs. But at some point, you’ll need to do it programmatically:
/** * Given a `rawSvgString` like `<svg>...</svg>`, return its URI-encoded representation. * @param {string} rawSvgString */ export function encodeSVG(rawSvgString: string): string { const symbols = /[\r\n%#()<>?\[\\\]^`{|}]/g; // Use single quotes instead of double to avoid URI encoding rawSvgString = rawSvgString .replace(/'/g, '"') .replace(/>\s+</g, '><') .replace(/\s{2,}/g, ' '); return ( 'data:image/svg+xml;utf-8,' + rawSvgString.replace(symbols, encodeURIComponent) ); }
Â
Once you’ve got both the raw SVG and its Data URL, you can proceed to construct your first SVG marker:
import { brandSvgRaw, encodeSVG } from './svg'; const marker = new google.maps.Marker({ map, position: { lat: 48.7277, lng: 21.2453 }, icon: { url: encodeSVG(brandSvgRaw), scaledSize: new google.maps.Size(40, 56), } });
Â
The same applies to dynamically generated SVGs. If the “contents” of your markup change (e.g. prices), you can use the following:
// text centering borrowed from https://stackoverflow.com/a/31522006/8160318 const tagSvgRaw = (price: string) => ` <svg xmlns="http://www.w3.org/2000/svg" width="71" height="45" viewBox="0 0 71 45" fill="none"> <rect width="71" height="37" rx="10" fill="#cb372b"/> <path d="M35 45L27 37H43L35 45Z" fill="#cb372b"/> <text x="50%" y="24" text-anchor="middle" fill="#FFF" font-size="14px" font-family="sans-serif" font-weight="bold"> ${price} </text> </svg>`; const price = '€2.5M'; const priceTagSvg = tagSvgRaw(price); const priceTagMarker = new google.maps.Marker({ ... icon: { url: encodeSVG(priceTagSvg), scaledSize: new google.maps.Size(71, 45), }, });
Â
Marker Interactions
You may want to modify the marker background and/or size upon hover. The trick here is to attach the native
mouseover
and mouseout
events and set a different icon
in the event callbacks:const iconDefaults: google.maps.Icon = { scaledSize: new google.maps.Size(71, 45) } priceTagMarker.addListener('mouseover', () => { priceTagMarker.setIcon({ ...iconDefaults, url: encodeSVG(tagSvgRaw(price, "yellow")) // or use SVG transforms like `scale` }) }); priceTagMarker.addListener('mouseout', () => { priceTagMarker.setIcon({ ...iconDefaults, url: encodeSVG(tagSvgRaw(price)) // back to the original Data URL }) });
Demo
Cons
- Requires knowledge of SVGs
- CSS styling must be inlined
- No support for pure HTML tags (there are hacks for this like html2canvas and others)
- Updates based on user interaction (mouseover, click, etc) must happen inside callbacks by regenerating underlying Data URLs
Â
Approach #3 — Native Advanced Markers
Â
This functionality was announced on Oct 7, 2022 and is considered experimental. Production use is not yet recommended because the API is subject to change.
Prerequisites
- You’ll need a
mapId
. Follow the official guides to obtain one. You can use theraster
map type becausevector
requires WebGL which may not work properly on your site’s visitors’ devices. Sidenote: map IDs can fully replace your embedded JSON style declarations. You can visualize your edits and save your changes without bothering your frontend teams. With versioning, you can easily revert to a previous style — again without needing a developer.
- You’ll need to update your map initialization code with
v=beta
andlibraries=marker
:
/maps/api/js?key=YOUR_API_KEY&v=beta&libraries=marker   ^^^^^^   ^^^^^^^^^^^^^^^^
If you were previously using other libraries like
geometry
, you can concatenate them using a comma:&libraries=geometry,marker
Â
From SVG Markup to DOM Elements
In Approach #2 you had to URL-encode your SVG markup and pass it to
icon.url
of the Marker
's constructor options. Native advanced markers elevate the concept of google.maps.Marker
to google.maps.marker.AdvancedMarkerView
and you can now work with actual DOM nodes.
That’s a lot of big words so let’s look at the differences side by side:
maps.Marker
const brandSvgRaw = `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="56" viewBox="0 0 40 56" fill="none"><path d="M20 0C14.6957 0 9.60859 2.10714 5.85786 5.85786C2.10714 9.60859 0 14.6957 0 20C0 36 18 43 18 53V54C18 54.5304 18.2107 55.0391 18.5858 55.4142C18.9609 55.7893 19.4696 56 20 56C20.5304 56 21.0391 55.7893 21.4142 55.4142C21.7893 55.0391 22 54.5304 22 54V53C22 43 40 36 40 20C40 14.6957 37.8929 9.60859 34.1421 5.85786C30.3914 2.10714 25.3043 0 20 0Z" fill="white"/><path d="M40 20.0755C40 29.1094 34.2421 35.4279 29.1579 40.9962C24.9895 45.5608 22 48.4283 22 53.5C22 55.5 21.1974 55.8018 21 56C20.8026 56.1982 20.2792 56 20 56C19.7208 56 19.6974 56.1982 19.5 56C19.3026 55.8018 19.5 56.5 18 55C18 49.9283 15.0211 45.5608 10.8526 40.9962C5.76842 35.4279 0 29.1094 0 20.0755C0 14.7511 2.10714 9.64485 5.85787 5.87997C9.60859 2.11509 14.6957 0 20 0C25.3043 0 30.3914 2.11509 34.1421 5.87997C37.8929 9.64485 40 14.7511 40 20.0755Z" fill="#30455D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7722 25.7398C12.7722 25.9242 12.7722 26.1087 12.7722 26.2932C12.6818 27.5974 12.7741 28.8886 13.0489 30.1668C16.8656 32.0283 20.647 31.9821 24.393 30.0284C27.6995 26.7802 27.6995 23.5522 24.393 20.3444C22.0842 19.3292 19.7785 18.3146 17.4759 17.3009C16.0494 15.2791 16.5106 13.8034 18.8593 12.8739C21.295 12.5786 23.5546 13.0859 25.6381 14.3957C25.8673 13.0947 25.8212 11.8035 25.4998 10.522C22.0528 9.02938 18.6403 9.07548 15.2624 10.6604C12.5914 12.5875 11.8075 15.1238 12.9106 18.2693C13.7824 19.5564 14.9353 20.4787 16.3691 21.0361C16.2769 21.2206 16.1847 21.405 16.0924 21.5895C15.65 21.5154 15.2811 21.6076 14.9857 21.8662C14.8012 21.8662 14.709 21.9584 14.709 22.1429C13.244 21.164 12.0912 19.8728 11.2504 18.2693C10.2345 12.8598 12.3096 9.49344 17.4759 8.17022C20.5183 7.76324 23.4696 8.08605 26.3298 9.13862C26.7042 9.46658 27.027 9.83548 27.2982 10.2454C28.5309 15.7458 26.6864 17.1293 21.7645 14.3957C20.995 14.4977 20.2572 14.4977 19.551 14.3957C18.1599 14.9029 18.0215 15.5946 19.136 16.4708C21.228 17.1479 23.257 17.978 25.2231 18.961C28.3743 21.6342 29.1581 24.9083 27.5749 28.7833C26.3137 30.9606 24.423 32.2981 21.9029 32.7953C18.518 33.3118 15.29 32.8509 12.2188 31.4118C11.0597 29.7523 10.8292 27.9539 11.5271 26.0165C11.8382 25.0918 12.2533 24.9996 12.7722 25.7398Z" fill="#293E56"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7722 26.2932C14.4518 27.3758 16.2964 28.0214 18.3059 28.23C19.4698 28.3835 20.4843 28.1068 21.3494 27.3999C22.5969 26.6501 23.0119 25.5434 22.5945 24.0797C22.3985 23.836 22.168 23.6516 21.9028 23.5263C21.059 22.9199 20.1367 22.4588 19.1359 22.1429C18.2339 21.7862 17.3116 21.4173 16.3691 21.0361C14.9352 20.4787 13.7823 19.5564 12.9105 18.2693C11.8074 15.1238 12.5913 12.5875 15.2623 10.6604C18.6403 9.07548 22.0528 9.02939 25.4997 10.5221C25.8211 11.8035 25.8672 13.0947 25.6381 14.3957C23.5546 13.0859 21.2949 12.5786 18.8593 12.8739C16.5105 13.8034 16.0494 15.2791 17.4758 17.3009C19.7784 18.3146 22.0841 19.3292 24.393 20.3444C27.6995 23.5522 27.6995 26.7802 24.393 30.0284C20.6469 31.9821 16.8656 32.0283 13.0488 30.1668C12.774 28.8886 12.6818 27.5974 12.7722 26.2932Z" fill="#F7F8F8"/><path fill-rule="evenodd" clip-rule="evenodd" d="M16.3691 21.0361C17.3116 21.4173 18.2339 21.7862 19.136 22.1428C19.136 22.2351 19.136 22.3273 19.136 22.4195C18.5956 22.0048 18.1345 22.0971 17.7525 22.6962C17.1125 22.4194 16.5591 22.0505 16.0924 21.5895C16.1846 21.405 16.2769 21.2206 16.3691 21.0361Z" fill="#587697"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.9857 21.8662C15.2811 21.6076 15.65 21.5154 16.0925 21.5895C16.5592 22.0505 17.1125 22.4194 17.7526 22.6962C18.1345 22.0971 18.5957 22.0048 19.136 22.4195C19.0096 23.0484 18.6407 23.4173 18.0293 23.5263C16.9705 23.0432 15.9559 22.4898 14.9857 21.8662Z" fill="#81AB70"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.9857 21.8662C15.956 22.4899 16.9705 23.0432 18.0293 23.5263C18.0768 23.8007 17.9845 23.9852 17.7526 24.0797C17.2327 24.3125 16.6793 24.4047 16.0925 24.3564C16.0925 24.7253 16.0925 25.0942 16.0925 25.4631C15.485 25.0929 14.9316 24.6318 14.4324 24.0797C14.4324 23.803 14.4324 23.5263 14.4324 23.2496C14.6909 22.9543 14.7832 22.5853 14.7091 22.1429C14.7091 21.9584 14.8013 21.8662 14.9857 21.8662Z" fill="#D9F2A4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.136 22.1429C20.1367 22.4587 21.059 22.9199 21.9029 23.5263C21.6949 24.4248 21.5566 25.347 21.4878 26.2931C21.3725 26.6407 21.1419 26.8251 20.7961 26.8465C20.3808 26.5002 19.9197 26.2236 19.4127 26.0165C18.9515 25.832 18.4904 25.6476 18.0292 25.4631C17.9936 24.9883 17.9014 24.5271 17.7526 24.0797C17.9845 23.9851 18.0767 23.8006 18.0292 23.5263C18.6407 23.4173 19.0096 23.0484 19.136 22.4195C19.136 22.3273 19.136 22.2351 19.136 22.1429Z" fill="#2746A7"/><path fill-rule="evenodd" clip-rule="evenodd" d="M17.7525 24.0797C17.9014 24.5271 17.9936 24.9883 18.0292 25.4631C17.7738 25.2409 17.4971 25.1948 17.1992 25.3247C17.5343 25.5718 17.5343 25.8023 17.1992 26.0165C16.7771 25.8797 16.4082 25.6952 16.0924 25.4631C16.0924 25.0942 16.0924 24.7252 16.0924 24.3563C16.6792 24.4047 17.2326 24.3125 17.7525 24.0797Z" fill="#6CAFCE"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.4323 24.0797C14.9316 24.6317 15.4849 25.0928 16.0925 25.4631C16.4082 25.6952 16.7771 25.8797 17.1992 26.0165C17.5343 25.8023 17.5343 25.5718 17.1992 25.3247C17.4971 25.1948 17.7738 25.2409 18.0293 25.4631C18.4904 25.6475 18.9515 25.832 19.4127 26.0165C18.7524 25.9497 18.1991 26.1342 17.7526 26.5698C17.736 26.4196 17.6438 26.3273 17.4759 26.2931C15.2602 27.3113 14.2457 26.5734 14.4323 24.0797Z" fill="#4C94CF"/><path fill-rule="evenodd" clip-rule="evenodd" d="M21.9028 23.5263C22.168 23.6516 22.3986 23.836 22.5945 24.0796C23.0119 25.5434 22.5969 26.6501 21.3495 27.3999C21.165 27.2154 20.9805 27.031 20.7961 26.8465C21.1419 26.8251 21.3724 26.6407 21.4878 26.2931C21.5566 25.347 21.6949 24.4248 21.9028 23.5263Z" fill="#20285D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.4323 23.2496C14.4323 23.5263 14.4323 23.803 14.4323 24.0797C14.2456 26.5735 15.2602 27.3113 17.4759 26.2932C17.6437 26.3274 17.7359 26.4196 17.7525 26.5698C17.6685 26.7497 17.5762 26.9341 17.4759 27.1232C17.7593 27.4972 18.036 27.8661 18.3059 28.23C16.2964 28.0215 14.4519 27.3758 12.7722 26.2932C12.7722 26.1087 12.7722 25.9243 12.7722 25.7398C12.7528 24.3949 13.2601 23.2881 14.294 22.4196C14.4276 22.6819 14.4737 22.9585 14.4323 23.2496Z" fill="#376ABC"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.4127 26.0165C19.9197 26.2235 20.3808 26.5002 20.7961 26.8465C20.9806 27.031 21.165 27.2154 21.3495 27.3999C20.4843 28.1068 19.4698 28.3835 18.3059 28.2299C18.036 27.8661 17.7593 27.4972 17.4759 27.1232C17.5762 26.9341 17.6685 26.7496 17.7526 26.5698C18.1991 26.1342 18.7524 25.9497 19.4127 26.0165Z" fill="#6F9048"/></svg>`; function encodeSVG(rawSvgString: string): string { const symbols = /[\r\n%#()<>?\[\\\]^`{|}]/g; rawSvgString = rawSvgString.replace(/'/g, '"').replace(/>\s+</g, '><').replace(/\s{2,}/g, ' '); return ('data:image/svg+xml;utf-8,' + rawSvgString.replace(symbols, encodeURIComponent)); } const marker = new google.maps.Marker({ map, icon: { url: encodeSVG(brandSvgRaw), scaledSize: new google.maps.Size(40, 56), }, position: { lat: 48.7277, lng: 21.2453, }, title: 'Spatialized HQ', });
Â
maps.marker.AdvancedMarkerView
// SVG Markup const brandSvgRaw = `<svg xmlns="http://www.w3.org/2000/svg" width="40" height="56" viewBox="0 0 40 56" fill="none"><path d="M20 0C14.6957 0 9.60859 2.10714 5.85786 5.85786C2.10714 9.60859 0 14.6957 0 20C0 36 18 43 18 53V54C18 54.5304 18.2107 55.0391 18.5858 55.4142C18.9609 55.7893 19.4696 56 20 56C20.5304 56 21.0391 55.7893 21.4142 55.4142C21.7893 55.0391 22 54.5304 22 54V53C22 43 40 36 40 20C40 14.6957 37.8929 9.60859 34.1421 5.85786C30.3914 2.10714 25.3043 0 20 0Z" fill="white"/><path d="M40 20.0755C40 29.1094 34.2421 35.4279 29.1579 40.9962C24.9895 45.5608 22 48.4283 22 53.5C22 55.5 21.1974 55.8018 21 56C20.8026 56.1982 20.2792 56 20 56C19.7208 56 19.6974 56.1982 19.5 56C19.3026 55.8018 19.5 56.5 18 55C18 49.9283 15.0211 45.5608 10.8526 40.9962C5.76842 35.4279 0 29.1094 0 20.0755C0 14.7511 2.10714 9.64485 5.85787 5.87997C9.60859 2.11509 14.6957 0 20 0C25.3043 0 30.3914 2.11509 34.1421 5.87997C37.8929 9.64485 40 14.7511 40 20.0755Z" fill="#30455D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7722 25.7398C12.7722 25.9242 12.7722 26.1087 12.7722 26.2932C12.6818 27.5974 12.7741 28.8886 13.0489 30.1668C16.8656 32.0283 20.647 31.9821 24.393 30.0284C27.6995 26.7802 27.6995 23.5522 24.393 20.3444C22.0842 19.3292 19.7785 18.3146 17.4759 17.3009C16.0494 15.2791 16.5106 13.8034 18.8593 12.8739C21.295 12.5786 23.5546 13.0859 25.6381 14.3957C25.8673 13.0947 25.8212 11.8035 25.4998 10.522C22.0528 9.02938 18.6403 9.07548 15.2624 10.6604C12.5914 12.5875 11.8075 15.1238 12.9106 18.2693C13.7824 19.5564 14.9353 20.4787 16.3691 21.0361C16.2769 21.2206 16.1847 21.405 16.0924 21.5895C15.65 21.5154 15.2811 21.6076 14.9857 21.8662C14.8012 21.8662 14.709 21.9584 14.709 22.1429C13.244 21.164 12.0912 19.8728 11.2504 18.2693C10.2345 12.8598 12.3096 9.49344 17.4759 8.17022C20.5183 7.76324 23.4696 8.08605 26.3298 9.13862C26.7042 9.46658 27.027 9.83548 27.2982 10.2454C28.5309 15.7458 26.6864 17.1293 21.7645 14.3957C20.995 14.4977 20.2572 14.4977 19.551 14.3957C18.1599 14.9029 18.0215 15.5946 19.136 16.4708C21.228 17.1479 23.257 17.978 25.2231 18.961C28.3743 21.6342 29.1581 24.9083 27.5749 28.7833C26.3137 30.9606 24.423 32.2981 21.9029 32.7953C18.518 33.3118 15.29 32.8509 12.2188 31.4118C11.0597 29.7523 10.8292 27.9539 11.5271 26.0165C11.8382 25.0918 12.2533 24.9996 12.7722 25.7398Z" fill="#293E56"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12.7722 26.2932C14.4518 27.3758 16.2964 28.0214 18.3059 28.23C19.4698 28.3835 20.4843 28.1068 21.3494 27.3999C22.5969 26.6501 23.0119 25.5434 22.5945 24.0797C22.3985 23.836 22.168 23.6516 21.9028 23.5263C21.059 22.9199 20.1367 22.4588 19.1359 22.1429C18.2339 21.7862 17.3116 21.4173 16.3691 21.0361C14.9352 20.4787 13.7823 19.5564 12.9105 18.2693C11.8074 15.1238 12.5913 12.5875 15.2623 10.6604C18.6403 9.07548 22.0528 9.02939 25.4997 10.5221C25.8211 11.8035 25.8672 13.0947 25.6381 14.3957C23.5546 13.0859 21.2949 12.5786 18.8593 12.8739C16.5105 13.8034 16.0494 15.2791 17.4758 17.3009C19.7784 18.3146 22.0841 19.3292 24.393 20.3444C27.6995 23.5522 27.6995 26.7802 24.393 30.0284C20.6469 31.9821 16.8656 32.0283 13.0488 30.1668C12.774 28.8886 12.6818 27.5974 12.7722 26.2932Z" fill="#F7F8F8"/><path fill-rule="evenodd" clip-rule="evenodd" d="M16.3691 21.0361C17.3116 21.4173 18.2339 21.7862 19.136 22.1428C19.136 22.2351 19.136 22.3273 19.136 22.4195C18.5956 22.0048 18.1345 22.0971 17.7525 22.6962C17.1125 22.4194 16.5591 22.0505 16.0924 21.5895C16.1846 21.405 16.2769 21.2206 16.3691 21.0361Z" fill="#587697"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.9857 21.8662C15.2811 21.6076 15.65 21.5154 16.0925 21.5895C16.5592 22.0505 17.1125 22.4194 17.7526 22.6962C18.1345 22.0971 18.5957 22.0048 19.136 22.4195C19.0096 23.0484 18.6407 23.4173 18.0293 23.5263C16.9705 23.0432 15.9559 22.4898 14.9857 21.8662Z" fill="#81AB70"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.9857 21.8662C15.956 22.4899 16.9705 23.0432 18.0293 23.5263C18.0768 23.8007 17.9845 23.9852 17.7526 24.0797C17.2327 24.3125 16.6793 24.4047 16.0925 24.3564C16.0925 24.7253 16.0925 25.0942 16.0925 25.4631C15.485 25.0929 14.9316 24.6318 14.4324 24.0797C14.4324 23.803 14.4324 23.5263 14.4324 23.2496C14.6909 22.9543 14.7832 22.5853 14.7091 22.1429C14.7091 21.9584 14.8013 21.8662 14.9857 21.8662Z" fill="#D9F2A4"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.136 22.1429C20.1367 22.4587 21.059 22.9199 21.9029 23.5263C21.6949 24.4248 21.5566 25.347 21.4878 26.2931C21.3725 26.6407 21.1419 26.8251 20.7961 26.8465C20.3808 26.5002 19.9197 26.2236 19.4127 26.0165C18.9515 25.832 18.4904 25.6476 18.0292 25.4631C17.9936 24.9883 17.9014 24.5271 17.7526 24.0797C17.9845 23.9851 18.0767 23.8006 18.0292 23.5263C18.6407 23.4173 19.0096 23.0484 19.136 22.4195C19.136 22.3273 19.136 22.2351 19.136 22.1429Z" fill="#2746A7"/><path fill-rule="evenodd" clip-rule="evenodd" d="M17.7525 24.0797C17.9014 24.5271 17.9936 24.9883 18.0292 25.4631C17.7738 25.2409 17.4971 25.1948 17.1992 25.3247C17.5343 25.5718 17.5343 25.8023 17.1992 26.0165C16.7771 25.8797 16.4082 25.6952 16.0924 25.4631C16.0924 25.0942 16.0924 24.7252 16.0924 24.3563C16.6792 24.4047 17.2326 24.3125 17.7525 24.0797Z" fill="#6CAFCE"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.4323 24.0797C14.9316 24.6317 15.4849 25.0928 16.0925 25.4631C16.4082 25.6952 16.7771 25.8797 17.1992 26.0165C17.5343 25.8023 17.5343 25.5718 17.1992 25.3247C17.4971 25.1948 17.7738 25.2409 18.0293 25.4631C18.4904 25.6475 18.9515 25.832 19.4127 26.0165C18.7524 25.9497 18.1991 26.1342 17.7526 26.5698C17.736 26.4196 17.6438 26.3273 17.4759 26.2931C15.2602 27.3113 14.2457 26.5734 14.4323 24.0797Z" fill="#4C94CF"/><path fill-rule="evenodd" clip-rule="evenodd" d="M21.9028 23.5263C22.168 23.6516 22.3986 23.836 22.5945 24.0796C23.0119 25.5434 22.5969 26.6501 21.3495 27.3999C21.165 27.2154 20.9805 27.031 20.7961 26.8465C21.1419 26.8251 21.3724 26.6407 21.4878 26.2931C21.5566 25.347 21.6949 24.4248 21.9028 23.5263Z" fill="#20285D"/><path fill-rule="evenodd" clip-rule="evenodd" d="M14.4323 23.2496C14.4323 23.5263 14.4323 23.803 14.4323 24.0797C14.2456 26.5735 15.2602 27.3113 17.4759 26.2932C17.6437 26.3274 17.7359 26.4196 17.7525 26.5698C17.6685 26.7497 17.5762 26.9341 17.4759 27.1232C17.7593 27.4972 18.036 27.8661 18.3059 28.23C16.2964 28.0215 14.4519 27.3758 12.7722 26.2932C12.7722 26.1087 12.7722 25.9243 12.7722 25.7398C12.7528 24.3949 13.2601 23.2881 14.294 22.4196C14.4276 22.6819 14.4737 22.9585 14.4323 23.2496Z" fill="#376ABC"/><path fill-rule="evenodd" clip-rule="evenodd" d="M19.4127 26.0165C19.9197 26.2235 20.3808 26.5002 20.7961 26.8465C20.9806 27.031 21.165 27.2154 21.3495 27.3999C20.4843 28.1068 19.4698 28.3835 18.3059 28.2299C18.036 27.8661 17.7593 27.4972 17.4759 27.1232C17.5762 26.9341 17.6685 26.7496 17.7526 26.5698C18.1991 26.1342 18.7524 25.9497 19.4127 26.0165Z" fill="#6F9048"/></svg>`; const parser = new DOMParser(); const pinSvgElement = parser.parseFromString( brandSvgRaw, 'image/svg+xml' ).documentElement; // Or even more simply via // DOM Element const pinSvgElementFromDOM = document.querySelector('#spatializedLogo'); const marker = new google.maps.marker.AdvancedMarkerView({ map, position: { lat: 48.7277, lng: 21.2453, }, content: pinSvgElement, title: 'Spatialized HQ', });
Previously, you could only work with pre-processed, URL-encoded SVG markup strings.
Now you can directly access a DOM node of type Element because that’s what
AdvancedMarkerView.content
accepts.Â
Custom HTML with Styling
In the old days, people used to employ third-party libraries like js-map-label to associate markers with HTML-friendly “labels”. This was by far the most widely adopted solution for real-estate websites like Compass.com and Airbnb.com because developers could freely display HTML content and conveniently style it using CSS.
The whole idea was based around what’s called
OverlayView
. Even 3rd party google maps utilities for frameworks like React, Angular, Vue, and Svelte were wrapping their logic around it. But it always felt wrong because overlays were supposed to be reserved for proper raster imagery like satellite images.With
AdvancedMarkerView
you can now render HTML- & CSS-powered markers!Â
Demo
Â
Approach #4 — WebGL Markers Using Deck.gl
Â
Deck.gl is a WebGL-powered framework for large-scale geospatial exploration. It supports multiple base maps — including Google Maps via
GoogleMapsOverlay
.Deck.gl works with both raster and vector map IDs. As a matter of fact, you don’t even need a map ID — though we do recommend you get one.
High-Level Deck.gl Process
- Declare one or more “icon layers”.
- Feed the layers your marker data.
- Define how the markers should appear on the map.
- Let Deck.gl compute the view based on the current viewport and zoom level.
- Automatically display the computed view onto the map canvas.
When should I use Deck.gl to display markers?
We recommend going for Deck.gl only if all of the following points apply:
- Your end users use reasonably performant devices which support WebGL.
- You need to display hundreds/thousands of markers, your current implementation is laggy, you have considered marker clustering, and clustering doesn’t suit your use case.
- You don’t need your markers to be draggable and you’re OK with the Deck.gl Google Maps integration’s other limitations.
Implementation
We’ll be using Deck.gl’s
IconLayer
which is usually implemented as follows:import { IconLayer } from '@deck.gl/layers'; import { GoogleMapsOverlay } from '@deck.gl/google-maps'; const map = new google.maps.Map({ ... }); const points = [{ lat: 1.23, lng: 4.56 }, {...}]; const markers = new IconLayer({ id: 'markers-layer', data: points, // Deck.gl uses the GeoJSON point convention getPosition: (element) => [element.lng, element.lat], getIcon: () => ({ url: '...', width: 40, height: 56, }), sizeMinPixels: 56, // `pickable` needs to be set for `onClick` and `onHover` to work pickable: true, onClick: () => { ... }, onHover: () => { ... }, }); const overlay = new GoogleMapsOverlay({ layers: [markers] }); overlay.setMap(map);
To run the example above, you’ll need to first install these packages:
npm i @deck.gl/core @deck.gl/google-maps @deck.gl/layers @loaders.gl/core @luma.gl/constants @luma.gl/core @math.gl/core
Â
The
getIcon
function can reuse the logic from Approach #2 — i.e. encoded SVG Data URLs.Demo
Pros
- High customizability
- Top-notch performance
- Full vector support
- Next-gen technology
- Multitude of layers to choose from
Â
Â
Looking for Google Maps pros?
Talk to us at hello@spatialized.io đź‘‹
Â
Spatialized s.r.o.
hello@spatialized.io
spatialized.io