[GIS] google maps V3 : in javascript api, render route obtained with web api

directiongoogle maps

I have to obtain route directions with the Google maps v3 WEB (http request) api (computations are made server-side, based on this data, without client interaction, so no JS available). Then, the routes are sorted out with internal logic, and the server (apache/PHP) send a web html/js/jQuery page to the client, which displays a page with a Google map (displayed with JS (ajax) api)

On this map, i would like to render the routes obtained earlier by the server with the web api.

So I tried to give the DirectionsResult to the google.maps.DirectionsRenderer::setDirections() but it does nothing, and firebug doesn't trace any error (and google JS if obfuscated, of course)

Yes, I first set the map with setMap(), and the directionsRenderer is initialized correctly, all that is OK !

It seems that de DirectionsResult is not the same when obtained from Web API and from JS API. Is there a way to "translate" it, so that it could be rendered ?

The alternative would be to do the route computations again on the client side with the ajax api, only to render them, but I think this is stupid to recompute directions as I already have them; so I don't want to do it this way unless it is the only way.

Thank you for your help !

Best Answer

You need to typecast each Object on the JSON response to the proper kind.

The web service API also doesn't return the ub property of the DirectionsResult (undocumented property), you need that as well. The DirectionsRenderer expects ub.travelMode, ub.origin and ub.destination (all strings). The origin and destination are only used if you enable the draggable property on the DirectionsRendererOptions - they are basically the same value that you pass on the DirectionsService#route() call.

Assuming you are on a browser that supports the ES5 Array#forEach method:

function typecastRoutes(routes){
    routes.forEach(function(route){
        route.bounds = asBounds(route.bounds);
        // I don't think `overview_path` is used but it exists on the
        // response of DirectionsService.route()
        route.overview_path = asPath(route.overview_polyline);

        route.legs.forEach(function(leg){
            leg.start_location = asLatLng(leg.start_location);
            leg.end_location   = asLatLng(leg.end_location);

            leg.steps.forEach(function(step){
                step.start_location = asLatLng(step.start_location);
                step.end_location   = asLatLng(step.end_location);
                step.path = asPath(step.polyline);
            });

        });
    });
}

function asBounds(boundsObject){
    return new google.maps.LatLngBounds(asLatLng(boundsObject.southwest),
                                    asLatLng(boundsObject.northeast));
}

function asLatLng(latLngObject){
    return new google.maps.LatLng(latLngObject.lat, latLngObject.lng);
}

function asPath(encodedPolyObject){
    return google.maps.geometry.encoding.decodePath( encodedPolyObject.points );
}

So you would use it like this:

var renderer = new google.maps.DirectionsRenderer();

function renderDirections(map, response, request){
    renderer.setOptions({
        directions : {
            routes : typecastRoutes(response.routes),
            // "ub" is important and not returned by web service it's an
            // object containing "origin", "destination" and "travelMode"
            ub : request
        },
        draggable : true,
        map : map
    });
}

PS: make sure you load the Geometry Library otherwise the google.maps.geometry.encoding.decodePath method won't be available.

Related Question