Search code examples
javascriptgoogle-mapsgoogle-maps-api-3callbackpolyline

Google Maps API: Setting up callbacks for adding markers/polyline


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?)


Solution

  • 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>