Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Google map markers not working with Shadow DOM in Safari

If you load a map with a marker in Safari, having the map inside a Shadow DOM, it seems to get hung up in an infinite page reload loop, until that infinite loop is stopped by the browser, which then shows the following error (translated from Spanish):

There has been a problem repeatedly with http://localhost:8000/index.html. Try loading the web page again.

I created the following very simple Polymer project to reproduce the problem.

Index.html

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=no">
    <meta charset="utf-8">
    <title>Markers test</title>
    <style>
      /* Always set the map height explicitly to define the size of the div
       * element that contains the map. */
      #map {
        height: 300px;
        width: 300px;
      }
      /* Optional: Makes the sample page fill the window. */
      html, body {
        height: 100%;
        margin: 0;
        padding: 0;
      }
    </style>
    <script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script>

    <!-- Load your application shell -->
    <link rel="import" href="test-el.html">
  </head>
  <body>
    <test-el></test-el>
    <div id="map"></div>
    <script>
        function initMap() {
            const mapsEvent = new CustomEvent('map-ready');
            document.dispatchEvent(mapsEvent);
            window.MAP_READY = true;
        }
    </script>
    <script async defer
      src="https://maps.googleapis.com/maps/api/js?key=YOUR_MAPS_API_KEY_HERE&callback=initMap">
    </script>
  </body>
</html>

test-el.html, which is the Poylmer test element I created to encapsulate the map inside a Shadow DOM

<link rel="import" href="bower_components/polymer/polymer-element.html">

<dom-module id="test-el">
  <template>
    <style>
      #map {
        width: 300px;
        height: 300px;
      }
    </style>

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

  <script>
    class TestEl extends Polymer.Element {
      static get is() { return 'test-el'; }
      static get properties() {
        return {

          // This shouldn't be neccessary, but the Analyzer isn't picking up
          // Polymer.Element#rootPath
          rootPath: String,
        };
      }

      ready() {
        super.ready();

        if (window.MAP_READY) {
            this.loadMap();
        } else {
            document.addEventListener('map-ready', () => this.loadMap());
        }
      }

      loadMap() {
        var myLatLng = {lat: -25.363, lng: 131.044};

        var map = new google.maps.Map(document.getElementById('map'), {
          zoom: 4,
          center: myLatLng
        });

        var marker = new google.maps.Marker({
          position: myLatLng,
          map: map,
          title: 'Hello World!'
        });


        var mapShadowDom = new google.maps.Map(this.$.map, {
          zoom: 4,
          center: myLatLng
        });

        var markerShadowDom = new google.maps.Marker({
          position: myLatLng,
          map: mapShadowDom,
          title: 'Hello World!'
        });
      }
    }

    window.customElements.define(TestEl.is, TestEl);
  </script>
</dom-module>

If you want to run the same test I did, you would need the following small bower.json file, and running bower install in the folder where you save these three documents, for bower to install webcomponents and Polymer dependencies.

{
  "name": "markers_test",
  "dependencies": {
    "polymer": "Polymer/polymer#^2.5.0",
    "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0"
  },
  "resolutions": {
    "polymer": "^2.0.0"
  },
  "private": true
}

Finally, serve index.html with a local server.

The test

As you can see, there is actually a <div id="map"></div> right below the test-el instantiation <test-el></test-el> in index.html. That div is not inside a Shadow DOM, so it is only there to show that the map and marker work perfectly fine if not inside a Shadow DOM.

In the <script> section of the test-el.html file, inside the loadMap() function, you can see I create 2 Google Maps with a marker each. The first Google Maps instantiation is assigned to the non-Shadow DOM div located in index.html, while the mapShadowDom is assigned to the <div id="map"></div> that is inside test-el's Shadow DOM.

Running this example code in Google Chrome, for instance, should render two maps of Australia, each with a marker right on its center. enter image description here

Running this same code on Safari (I have tested on Safari 11.1) should lead to the error scenario I described at the top.

However, if you were to comment the following lines in test-el.html

var markerShadowDom = new google.maps.Marker({
    position: myLatLng,
    map: mapShadowDom,
    title: 'Hello World!'
});

the result in Safari should look something like this: enter image description here

So it seems like the problem is related to painting a Google Marker in a Google Map located inside a Shadow DOM.

like image 372
jaime.ferbec Avatar asked Jun 20 '18 16:06

jaime.ferbec


People also ask

How do you refresh a marker on Google Maps?

To reload the markers, when you create then, push them to an array. Then create a function where you iterate through the array, setting the markers map as null. After this, erase the array.

How do I change the color of a marker in Google Maps API?

Add different color markerspng at the end of the URL to get a blue marker. To add a green marker simply change it to green-dot. png so that the URL will be http://maps.google.com/mapfiles/ms/icons/green-dot.png .


2 Answers

Had the same problem. This is what I ended up doing for a temporary fix

var markerShadowDom = new google.maps.Marker({
  icon: 'https://maps.gstatic.com/mapfiles/api-3/images/spotlight-poi.png',
  position: myLatLng,
  map: mapShadowDom,
  title: 'Hello World!'
});

Custom markers seems to be ok with safari

like image 177
Sohaib Avatar answered Jan 03 '23 12:01

Sohaib


Thank you for the very detailed info and repro steps!

Here's an issue that was reported on a Google Maps web component that seems to represent the same problem. Like you said, it only manifests when a marker is added to a map in shadow DOM.

It happens in Safari 11.1 (I still had Safari 11.0 this morning and couldn't repro with that version). It seems to be fixed in Tech Preview (Safari 12).

If you need a workaround quickly you could try forcing Safari 11.1 to use the shady DOM polyfill. Something like

<script>
  // Force Safari 11.1.* to use shady DOM because of a bug
  // See https://github.com/GoogleWebComponents/google-map/issues/419

  // i don't know how to parse user agents
  // this is probably bad
  var s1 = 'Version/11.1';
  var s2 = 'Safari/605.1.15';
  var agent=navigator.userAgent;

  if ((agent.search(s1) >= 0 ) && (agent.search(s2) >= 0 )) {
    ShadyDOM = { force: true };
  }
</script>
<script src="/bower_components/webcomponentsjs/webcomponents-loader.js"></script>
like image 27
Kate Jeffreys Avatar answered Jan 03 '23 11:01

Kate Jeffreys