Custom overlays

Now we're getting serious. 😬 Getting your own HTML elements on the map, instead of the default markers, has always been a bit of a pain point with Google Maps. Sure, you could get away custom marker icons for some things, but what if you want to display dynamic content? Enter the humble overlay – the secret map-foo-voodoo passed down from one generation of front-end programmer to the next in endless StackOverflow threads. Tell me more.

What's an overlay?

The Google docs actually call this an OverlayView. Basically, you can add any HTML element to the map as an "overlay" by messing around with DOM elements in javascript. I hope you can image that doing this manually can get messy real fast. The guides have an example where they overlay a section of a terrain map or something along those lines – very cool 🤔. What this feature is way more useful for are custom HTML markers! And not just plain old markers, but markers with bound data and actions and CSS animations!

Let's first talk about how the OverlayView actually works. OverlayView ↗ reveals that it requires us to define 3 methods: onAdd, draw and onRemove. Since on-prefixed parameters are reserved in our case, we rename the methods to add and remove. Now in ember-speak, these are basically equivalent to insert, render and destroy – three tasks ember components absolutely excel at! All we really have to do is wait for the map to initialise before we insert the component into the DOM and register it with the map. The overlay component does this and more to make it dead easy to create complex custom map elements.

Creating custom overlays

Create your custom overlay using the overlay component. It works like most of the other components in this addon, except for one twist: you can pass a block template to the component that will be rendered on the map. This makes overlays incredibly powerful in ember.

Your imagination is the limit here. Let's render some fake rental prices and add some fun hover effects as a start.

Test Hover over the overlay markers to trigger a CSS transform.

{{#g-map lat="51.507568" lng="-0.127762" zoom=9 styles=primaryMapStyle as |g|}}
  {{#each londonLocations as |l|}}
    {{#g.overlay lat=l.lat lng=l.lng
      onMouseover=(action (mut l.active) true)
      onMouseleave=(action (mut l.active) false)}}
      <div class="tooltip {{if l.active "active"}}">
        £{{l.price}}
      </div>
    {{/g.overlay}}
  {{/each}}
{{/g-map}}
Custom options

There are also two custom options:

paneName – Select which map pane to render your overlay in. See MapPanes ↗ for the options. The default pane is overlayMouseTarget.

innerContainerStyle – This lets you override the style applied to the container element holding your overlay content. By using the transform CSS property, you can move your overlay content relative to its coordinates. For example, the default transform centers the element horizontally and positions it above the coordinates. This is ideal for tooltips, which usually have the "tip" or "anchor" at the middle and bottom of their element.

/* Not a real class. For illustration purposes only. */
.anchor-middle-bottom {
  transform: translateX(-50%) translateY(-100%);
}

Notice how the transform uses percentages. This lets us define the offset using the dimensions of the overlay content. Here is what the transform should look like if you want your content centered on the coordinates.

{{#g.overlay lat=l.lat lng=l.lng
  innerContainerStyle="transform: translateX(-50%) translateY(-50%);"}}
  <p>I'm centered on my coordinates!</p>
{{/g.overlay}}

You can of course use other units of measurement, like pixels.

Private API usage

Warning The overlay component uses the experimental -in-element Glimmer feature to teleport the component into the map's overlay pane. It works like a charm and will soon be part of the public API, but is still currently an experimental, private feature. You've been warned. 😉

Let's see what we can build with these components.

Complex UI ›