Google Maps API: Setting up callbacks for adding m

2019-02-19 11:30发布

I'm trying to add a polyline to the Google Map generated. The coordinates for the polyline are taken from a JSON file on my web server using jQuery (getJSON function). However, I'm having trouble with callbacks. I've defined three functions in a separate JavaScript file, and these are:

function initMap(callback) {

    map = new google.maps.Map(document.getElementById('map-canvas'), {
        center: {lat: 34.397, lng: 150.644},
        scrollwheel: false,
        zoom: 2
    });

    callback();
}

.

function setPath(callback) {

   $.getJSON('./expOneActivityData.json',

       function (data) {

           //Some looping contstruct to navigate through my JSON file.   
       }
   })

   callback();
};

.

function addPath() {

    var trekLine = new google.maps.Polyline({

        path: expeditionCoordinates,
        geodisc: true,
        stokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2
    });

    trekLine.setMap(map);

}

expeditionCoordinates being an array, each element being an object with latitude and longitude property. This is declared as a global variable, with value initialisation happening in setPath()'s loop.

In my HTML file, I have:

<script src="https://maps.googleapis.com/maps/api/js?key=myKey&callback=initMap">

When I try to replace initMap with initMap(setPath(addPath)) in the script tag, I get a 400 Bad request from Google. Ofcourse having just "callback=initMap" in the script tag gives a:

TypeError: callback is not a function

occuring at line with callback() in initMap's definition.

So how can I pass a function to googleapis, where the function itself also has callbacks? (My looping construct is fine btw). I tried adding 'defer' to the googleapi script tag, and also to the one linking to my JavaScript file. I removed all the callbacks stuff, and only excecuted the loop. I hoped the expeditionCoordinates array would finish initialisation before the googleapi script tag is excecuted, though that didnt work either (map still loads, just with no polyline).

I'm fairly new to Javascript and it's asynchronous nature, though I do understand how they work and have been succesfully working with them at a basic level for a week or so.

(Which actually leads me to a side question. Up until now I've only worked with one callback. I would expect something like:

initMap(setPath)

to work as setPath does not have () attached when its definition is passed as a parameter, and hence is not excecuting immediately. Though adding a set of brackets to setPath, as it also takes a callback (addPath), would mean it does get excecuted immediately?)

3条回答
Fickle 薄情
2楼-- · 2019-02-19 11:54

There are several issues with the provided example:

1) When loading the Google Maps API, callback parameter accepts callback function name where the function itself should have the following signature:

function initMap() {
   //...
}

where

<script src="https://maps.googleapis.com/maps/api/js?key=myKey&callback=initMap" async defer></script>

Only parameter-less callback function could be specified this way.

2) Since jQuery.getJSON() is async by default and you are passing function callback, the implementation of setPath function should like this:

function setPath(callback) {
    $.getJSON('./expOneActivityData.json',
        function (data) {
            callback(data);
        }
    );
};

Working example

function initMap() {
    var map = new google.maps.Map(document.getElementById('map-canvas'), {
        center: { lat: 34.397, lng: 150.644 },
        scrollwheel: false,
        zoom: 2
    });

    setPath(function(data) {
        addPath(map,data);
    });
}

function setPath(callback) {
    $.getJSON('https://gist.githubusercontent.com/vgrem/91ba4d694157169b112c/raw/5bdd81c6f5bdfa5ba2d0ca8d5494129b329399d8/expOneActivityData.json',
        function (data) {
            callback(data);
        }
    );
};


function addPath(map,expeditionCoordinates) {
    var trekLine = new google.maps.Polyline({
        path: expeditionCoordinates,
        geodisc: true,
        stokeColor: '#FF0000',
        strokeOpacity: 1.0,
        strokeWeight: 2
    });
    trekLine.setMap(map);
}
html, body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#map-canvas {
    height: 100%;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<div id="map-canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?libraries=places&callback=initMap"
            async defer></script>

查看更多
叛逆
3楼-- · 2019-02-19 11:54

You can, however, add a one-time event listener to mimic sending a callback.

var map;

function initMap(mapId, latLong, callback) {
    //...

    map = new google.maps.Map(document.getElementById(mapId), {
        zoom: 16,
        center: latlng
    });


    // This is what you're interested in...
    if ($.isFunction(callback)) {
        google.maps.event.addListenerOnce(map, 'tilesloaded', callback);
    }
}

That keeps the callback out of the script src URL and your code procedural, though adding the event listener after you're already cut the new Map code loose seems a little odd.

And note that though its logic is a little more linear, it might not load quite as fast as doing async "the right way" as in Vadim's answer.

查看更多
We Are One
4楼-- · 2019-02-19 12:01

You can't pass parameters in the callback parameter of the Google Maps Javascript API v3 script include.

This won't work:

<script src="https://maps.googleapis.com/maps/api/js?key=myKey&callback=initMap(setPath(addPath))"></script>

as you discovered. Something like this should:

function initMap() {
    map = new google.maps.Map(document.getElementById('map-canvas'), {
        center: {lat: 34.397, lng: 150.644},
        scrollwheel: false,
        zoom: 2
    });
    setPath(addPath));
}

function setPath(callback) {
  $.getJSON('./expOneActivityData.json',
    function(data) {
      // Some looping contstruct to navigate through my JSON file.
      // create the expeditionCoordinates array
      callback(expeditionCoordinates);
    }
  );
};

function addPath(expeditionCoordinates) {
  var trekLine = new google.maps.Polyline({
    path: expeditionCoordinates,
    geodisc: true,
    stokeColor: '#FF0000',
    strokeOpacity: 1.0,
    strokeWeight: 2
  });

  trekLine.setMap(map);
}

Using this to asynchronously load the API:

<script src="https://maps.googleapis.com/maps/api/js?key=myKey&callback=initMap" async defer></script>
查看更多
登录 后发表回答