Google Maps interactive SVG overlay

In this example below you will see how to do a Google Maps interactive SVG overlay with some HTML / CSS and Javascript

https://stackoverflow.com/questions/50327032/google-maps-overlayview-make-only-svg-clickable http://serversideguy.com/2017/10/31/how-do-i-place-svgs-on-a-google-map-using-custom-overlays/

Thumbnail
This awesome code was written by Sphinxxxx, you can see more from this user in the personal repository.
You can find the original code on Codepen.io
Copyright Sphinxxxx ©

Technologies

  • HTML
  • CSS
  • JavaScript
<!DOCTYPE html>
<html lang="en" >

<head>
  <meta charset="UTF-8">
  <title>Google Maps interactive SVG overlay</title>
  
  
  
      <link rel="stylesheet" href="css/style.css">

  
</head>

<body>

  <script src="https://maps.googleapis.com/maps/api/js"></script>


<div id="map"></div>

<!-- This is the SVG element we'll place on top of the map -->
<svg id="svg1" xmlns="http://www.w3.org/2000/svg" width="400" height="400" viewBox="0 0 32 32">
    <g>
        <circle cx="7.5" cy="7" r=".8"/>
        <path fill="green" d="M21.8 4.2c-4-1-7.2-.7-11.4 1.8C10.4 5 8 2.3 5 4.3 1.8 3.9 1.8 7 1.8 7S0 10.1 0 11.3c0 .8.4 1 .9 1.1 2.3-1.3 4.3-1 6-.7 1 .1 1.7.2 2.2 0a.4.4 0 0 1 .2.8c-.7.2-1.5 0-2.5 0a8.2 8.2 0 0 0-5.3.5c1.9 3.2 7 4.3 10.9 1.7l3 .3c.2 0 0 .7-.2 1.4 0 .2-2.8.8-2.9 1 0 .4 2.5 0 2.7.3.2.3-.3 1.5 0 2.1.1.4 1.4 0 1.8-.9.2-.4-.6-1.4-.4-1.7l1-2H19l3.1-.3c.2 0 .4.4.6.9.1.2-1.8.6-1.7.8.2.5 1.9.2 2.5.7.6.6.6 2.2 1.1 2.4.3 0 1.3-.7 1.1-1.7-.3-1.4-2-3.2-2-3.2a6 6 0 0 1 3 .3c2.5 1.3.6 11-5.7 11.5-3.4.3-4.6-2.4-4.2-4 .5-1.5 2.4-2.3 3.7-2.1 1.3.2 1.5 1.4 1 2.2l-.3.3a1.2 1.2 0 0 0-2.1.9 1.2 1.2 0 0 0 2.4.2 2 2 0 0 0 1-.6c1-1.1.9-3.2-1.3-4-2.3-.8-5.7.7-5.8 3.3 0 2.5 2.3 5.5 6.3 5.2 5.9-.3 10.2-6.5 10-12.2a12 12 0 0 0-9.9-11.6zM6.8 9.7a2.4 2.4 0 1 1 .1 0z"/>
        <path fill="tomato" d="M15,25  q2.6,7.5 -8.0,5.0  c-8.0,-2.5 -5.3,-12.5 -2.6,-12.5"/>
    </g>
</svg>
  
  

    <script  src="js/index.js"></script>




</body>

</html>

/*Downloaded from https://www.codeseek.co/Sphinxxxx/google-maps-interactive-svg-overlay-wjEyMm */
body {
  margin: 0;
  height: 100vh;
}

#map {
  height: 100%;
}

svg {
  pointer-events: none;
}
svg path {
  pointer-events: auto;
}
svg path {
  cursor: pointer;
  opacity: .7;
}
svg path:hover {
  opacity: 1;
}


/*Downloaded from https://www.codeseek.co/Sphinxxxx/google-maps-interactive-svg-overlay-wjEyMm */
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

(function () {
    "use strict";
    //console.clear();

    /**
        Our custom overlay class, based on this example:
        http://serversideguy.com/2017/10/31/how-do-i-place-svgs-on-a-google-map-using-custom-overlays/
         More info:
        https://developers.google.com/maps/documentation/javascript/customoverlays
    */

    var SVGOverlay = function (_google$maps$OverlayV) {
        _inherits(SVGOverlay, _google$maps$OverlayV);

        function SVGOverlay(bounds, svg, map) {
            _classCallCheck(this, SVGOverlay);

            var _this = _possibleConstructorReturn(this, (SVGOverlay.__proto__ || Object.getPrototypeOf(SVGOverlay)).call(this));

            _this.bounds = bounds;
            _this.svg = svg;

            _get(SVGOverlay.prototype.__proto__ || Object.getPrototypeOf(SVGOverlay.prototype), 'setMap', _this).call(_this, map);
            return _this;
        }

        /**
            Will be called when the map is ready for the overlay to be attached.
        */


        _createClass(SVGOverlay, [{
            key: 'onAdd',
            value: function onAdd() {
                var svg = this.svg;
                svg.style.position = 'absolute';

                //Add the SVG element to a map pane/layer that is able to receive mouse events:
                var panes = _get(SVGOverlay.prototype.__proto__ || Object.getPrototypeOf(SVGOverlay.prototype), 'getPanes', this).call(this);
                panes.overlayMouseTarget.appendChild(svg);
            }

            /**
                Whenever we need to (re)draw the overlay on the map, including when first added.
            */

        }, {
            key: 'draw',
            value: function draw() {
                //Here, we need to find the correct on-screen position for our image.
                //To achieve that, we simply ask the map's projection to calculate viewport pixels from the image's lat/lng bounds:
                var projection = _get(SVGOverlay.prototype.__proto__ || Object.getPrototypeOf(SVGOverlay.prototype), 'getProjection', this).call(this),
                    bounds = this.bounds,
                    sw = projection.fromLatLngToDivPixel(bounds.getSouthWest()),
                    ne = projection.fromLatLngToDivPixel(bounds.getNorthEast());

                //Place/resize the SVG element:
                var s = this.svg.style;
                s.left = sw.x + 'px';
                s.top = ne.y + 'px';
                s.width = ne.x - sw.x + 'px';
                s.height = sw.y - ne.y + 'px';
            }
        }]);

        return SVGOverlay;
    }(google.maps.OverlayView); //SVGOverlay


    function addEvent(target, type, handler) {
        var targets = typeof target === 'string' ? Array.from(document.querySelectorAll(target)) : [target];
        targets.forEach(function (t) {
            return google.maps.event.addDomListener(t, type, handler);
        });
    }

    function initMap() {
        var map = new google.maps.Map(document.getElementById('map')),
            mySVG = document.querySelector('#svg1');

        //Say which area we want the image to occupy:
        var svgBounds = new google.maps.LatLngBounds(new google.maps.LatLng(62.281819, -150.287132), new google.maps.LatLng(62.400471, -150.005608));
        new SVGOverlay(svgBounds, mySVG, map);

        //For convenience, zoom in on that area:
        map.setCenter(svgBounds.getCenter());
        map.fitBounds(svgBounds);

        //Handle normal DOM events on the SVG element(s):
        addEvent('path', 'click', function (e) {
            console.log('Clicked!');
            e.currentTarget.style.fill = '#' + Math.floor(Math.random() * 0xfffff);
        });
        addEvent('path', 'dblclick', function (e) {
            //Avoid zooming here:
            e.stopPropagation();
        });
    }

    addEvent(window, 'load', initMap);
})();

Comments