Our Scenario
We are working on an app called BeeSecure that is being created with the intention of reducing rural crime. Well, rural crime initially but will hopefully do much more than just rural. We have two different types of hardware devices, one cellular, and another LoRaWan (Long Range Wide Area Network). These devices send information like GPS coordinates, direction, altitude, temperature to our app and the app relays the information back to the customers. The main initiative is GPS tracking assets. Even the smallest movements triggers events which send information to our app so people will know when things are happening. So you can probably see where the mapping comes into play. When people open up their breadcrumb maps or current location maps they can see where things are or have been. Having all the markers set to the default red pin isn’t very helpful for anyone when they are trying to figure out which point is which or which asset is which. What do we need? Ideally, a photo of each asset on the map in place of the pins.
HTMLMapMarker Class
Well let’s get straight to it. Here is the Javascript class you will require. Put this in the same Javascript file where you are initializing your Google map. We came across this resource but had to change things up a little bit. Credit where credit is due. It helped us a ton!
/* * HTMLMapMarker Javascript class * Extends the Google Maps OverlayView class * Set up to accept our latlng, html for the div, and the map to attach it to as arguments */ class HTMLMapMarker extends google.maps.OverlayView { // Constructor accepting args constructor(args) { super(); this.latlng = args.latlng; this.html = args.html; this.setMap(args.map); } // Create the div with content and add a listener for click events createDiv() { this.div = document.createElement('div'); this.div.style.position = 'absolute'; if (this.html) { this.div.innerHTML = this.html; } google.maps.event.addDomListener(this.div, 'click', event => { google.maps.event.trigger(this, 'click'); }); } // Append to the overlay layer // Appending to both overlayLayer and overlayMouseTarget which should allow this to be clickable appendDivToOverlay() { const panes = this.getPanes(); panes.overlayLayer.appendChild(this.div); panes.overlayMouseTarget.appendChild(this.div); } // Position the div according to the coordinates positionDiv() { const point = this.getProjection().fromLatLngToDivPixel(this.latlng); if (point) { this.div.style.left = `${point.x}px`; this.div.style.top = `${point.y}px`; } } // Create the div and append to map draw() { if (!this.div) { this.createDiv(); this.appendDivToOverlay(); } this.positionDiv(); } // Remove this from map remove() { if (this.div) { this.div.parentNode.removeChild(this.div); this.div = null; } } // Return lat and long object getPosition() { return this.latlng; } // Return whether this is draggable getDraggable() { return false; } }
The CSS Styling
The following styles will give you something that looks like our marker in the image above. Put these in your stylesheet or within style tags on the map page.
/* Outside white border */ .asset-map-image-marker { background-color: #ffffff; border-radius: 5px; cursor: pointer !important; height: 40px; margin-left: -20px; /* margin-left = -width/2 */ margin-top: -50px; /* margin-top = -height + arrow */ padding: 0px; position: absolute; width: 40px; } /* Arrow on bottom of container */ .asset-map-image-marker:after { border-color: #ffffff transparent; border-style: solid; border-width: 10px 10px 0; bottom: -10px; content: ''; display: block; left: 10px; position: absolute; width: 0; } /* Inner image container */ .asset-map-image-marker div.image { background-color: #cccccc; background-position: center center; background-size: cover; border-radius: 5px; height: 36px; margin: 2px; width: 36px; }
Using The HTMLMapMarker Class
Now putting it to use with a Google map. Use this Javascript code and it should all come together.
/* * Initialize Map */ function initialize_map() { var map = new google.maps.Map(document.getElementById('map'), { zoom: 18, mapTypeId: 'hybrid', mapTypeControlOptions: { mapTypeIds: ['roadmap', 'satellite', 'hybrid'] }, fullscreenControl: false, mapTypeControl: true, streetViewControl: false, rotateControl: false, clickableIcons: false, zoomControlOptions: { position: google.maps.ControlPosition.RIGHT_TOP }, }); var image = 'https://www.blackatlasyxe.com/wp-content/uploads/2019/02/blog-tardis.jpg'; var marker = new HTMLMapMarker({ latlng: new google.maps.LatLng(51.4921374, -0.1928784), map: map, html: '<div class="asset-map-image-marker"><div class="image" style="background-image: url(' + image + ')"></div></div>', }); marker.addListener("click", () => { // Your Javascript to run on click alert("You found the Tardis!"); }); map.setCenter(marker.getPosition()); }
Initialize The Map
Now we just need the div and a quick Javascript call in the page we want the map.
<div id="map"></div> <script> $( document ).ready(function() { google.maps.event.addDomListener(window, 'load', initialize_map()); }); </script>
Reminders
Don’t forget to have a link to the Google Map API Javascript library and as of recently you will need an API Key for things to work properly. You can find information on the API Key here:
https://developers.google.com/maps/documentation/javascript/get-api-key
Really appreciate you writing this article, was able to tweak this slightly to work with my project. 🙂
Glad it could help you out!