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 lng=l.lng
      onMouseover=(action (mut true)
      onMouseleave=(action (mut false)}}
      <div class="tooltip {{if "active"}}">
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.

zIndex – Set the z-index CSS property of the overlay. Use this to control the stack order of the order elements.

Positioning the overlay

Warning Your overlay content will not be centered over the coordinates by default. You have to do it yourself!

While the overlay will be positioned exactly at the coordinates specified, your overlay content will expand to the bottom-right and remain anchored to the top-left. In other words, the top-left corner of your content will lie on the coordinates. This is probably not what you want.

By using the transform CSS property, you can move your overlay content relative to its coordinates. We'll look at a few common examples now.

Centering overlay content

Let's first center our overlay over the coordinates. To do so we will wrap our overlay content with an element and apply our transform to it.

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

Notice how the transform uses percentages. This lets us define the offset using the dimensions of the overlay content. If your content is 100px wide and 100px tall, then the above transform will move it 50px up and 50px to the left.

Tooltip positioning

Another common need is to center the overlay horizontally and place it above the coordinate. This is ideal for tooltips, which usually have the "tip" or "anchor" at the middle and bottom of their element.

{{#g.overlay lng=l.lng}}
  <div style="transform: translateX(-50%) translateY(-100%);">
    <p>I'm a tooltip!</p>

While custom styles get the job done, you should consider adding a class to your stylesheet and use that instead. You can, of course, use other units of measurement, like pixels.

/* Not included in the addon. Just an example. */
.anchor-middle-bottom {
  transform: translateX(-50%) translateY(-100%);

.anchor-center {
  transform: translateX(-50%) translateY(-50%);

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

Complex UI ›