开发者

Can't Deserialize GoogleMaps DirectionsResult Object

I'm using the GoogleMaps API v3.0 and trying to save a DirectionsResult to my database and then retrieve it later to use on a map. My problem is that when I try to re-hydrate the saved object by pulling its JSON representation from my database, the object is just dumb JSON, it doesn't have the original methods and functions of its constituent objects. So, I built a fix routine that takes the dumbalt text JSON and rebuilds it by reconstructing all the LatLng and LatLngBound objects. But, something is still missing because my fixed object doesn't work like the original, the two points show up on my map but the purple line between them is missing.

Would appreciate any advice on either a better technique for serialization/hydration or any ideas as to what my fix routine might be missing.

Thanks

Can't Deserialize GoogleMaps DirectionsResult Object

Can't Deserialize GoogleMaps DirectionsResult Object

request = {
   origin: homeLocation, 
   destination: jobLocation,
   travelMode: google.maps.DirectionsTravelMode.DRIVING
};
directionsService.route(request, function(response, status) {
   if (status == google.maps.DirectionsStatus.OK) {
      var str = Ext.encode(response);  //<&l开发者_StackOverflowt;==SAVING RAW JSON OBJECT TO DB (I USE ExtJs)
      var z = eval('(' + str + ')');   //<<==REHYDRATING DirectionsResult RAW JSON OBJECT
      FixDirectionResult(z);           //<<==ATTEMPT TO RE-ESTABLISH ORIGINAL OBJECTS
      directionsRenderer.setDirections(z);  //<<==THIS WORKS WITH response BUT NOT WITH z
   }
);
function FixDirectionResult(rslt) {
 for(r=0; r<rslt.routes.length; r++) {
  var route = rslt.routes[r];
  var bounds = route.bounds;
  route.bounds = new google.maps.LatLngBounds(
   new google.maps.LatLng(bounds.U.b,bounds.O.d), 
   new google.maps.LatLng(bounds.U.d,bounds.O.b));

  for(l=0; l<route.legs.length;l++) {
   var leg = route.legs[l];
   leg.start_location = new google.maps.LatLng(leg.start_location.wa,leg.start_location.ya);
   leg.end_location = new google.maps.LatLng(leg.end_location.wa,leg.end_location.ya);

   for(s=0; s<leg.steps.length;s++) {
    var step = leg.steps[s];
    step.start_location = 
     new google.maps.LatLng(step.start_location.wa,step.start_location.ya);
    step.end_location = 
     new google.maps.LatLng(step.end_location.wa,step.end_location.ya);

    for(p=0;p<step.path.length;p++) {
     var path=step.path[p];
     step.path[p] = new google.maps.LatLng(step.path.wa,step.path.ya);
    }
   }
  }

  for(o=0; o<route.overview_path.length;o++) {
   var overview = route.overview_path[o];
   route.overview_path[o] = new google.maps.LatLng(overview.wa,overview.ya);
  }
 }
} 


It seems from the look of your code you aren't accessing the lat and lng properly. The google maps api library is minified. The variable names are often shortened to a random set of characters. You shouldn't approach the x and y through these variables but through their getters: ie. lat() and lng() to avoid the same issue with future versions. Hopefully, this is the issue that's causing your direction to not render.

The proper recommended way to obtain lat and lng is similar to the following:

results[0].geometry.location.lat().toFixed(3);
results[0].geometry.location.lng().toFixed(3);

So, for instance this following line should be:

step.start_location = new google.maps.LatLng(step.start_location.wa,step.start_location.ya);
step.end_location = new google.maps.LatLng(step.end_location.wa,step.end_location.ya);

To:

step.start_location = new google.maps.LatLng(step.start_location.lat(), step.start_location.lng());
step.end_location = new google.maps.LatLng(step.end_location.lat(), step.end_location.lng());

Storage of Google Map Data is within term of service. Here is the restriction that you might want to take a look before you go further with your data storage:

 10.1.3 Restrictions against Data Export or Copying.

    (a) No Unauthorized Copying, Modification, Creation of Derivative

Works, or Display of the Content. You must not copy, translate, modify, or create a derivative work (including creating or contributing to a database) of, or publicly display any Content or any part thereof except as explicitly permitted under these Terms. For example, the following are prohibited: (i) creating server-side modification of map tiles; (ii) stitching multiple static map images together to display a map that is larger than permitted in the Maps APIs Documentation; (iii) creating mailing lists or telemarketing lists based on the Content; or (iv) exporting, writing, or saving the Content to a third party’s location-based platform or service.

    (b) No Pre-Fetching, Caching, or Storage of Content. You must not

pre-fetch, cache, or store any Content, except that you may store: (i) limited amounts of Content for the purpose of improving the performance of your Maps API Implementation if you do so temporarily, securely, and in a manner that does not permit use of the Content outside of the Service; and (ii) any content identifier or key that the Maps APIs Documentation specifically permits you to store. For example, you must not use the Content to create an independent database of “places.”

    (c) No Mass Downloads or Bulk Feeds of Content. You must not use the

Service in a manner that gives you or any other person access to mass downloads or bulk feeds of any Content, including but not limited to numerical latitude or longitude coordinates, imagery, visible map data, or places data (including business listings). For example, you are not permitted to offer a batch geocoding service that uses Content contained in the Maps API(s).


I couldn't get the above code to work so I wrote my own. The following two functions will serialize and deserialize a DirectionsResult object. However, it will only serialize the minimum amount of data necessary to plot a route. If you find that the returned deserialized DirectionsResult lacks the features you need, you must modify the code to add whatever additional DirectionsResult object attributes you need.

Please don't abuse this code. Google only allows you to store Maps data under specific circumstances, and only temporarily (i.e. never any longer than 30 calendar days).

//Takes Google Maps API v3 directionsRequest and directionsResult objects as input.
//Returns serialized directionsResult string.
function serializeDirectionsResult (directionsRequest, directionsResult) {
        var copyright = directionsResult.routes[0].copyrights;
        var travelMode = directionsRequest.travelMode;
        var startLat = directionsResult.routes[0].legs[0].start_location.lat();
        var startLng = directionsResult.routes[0].legs[0].start_location.lng();
        var endLat = directionsResult.routes[0].legs[0].end_location.lat();
        var endLng = directionsResult.routes[0].legs[0].end_location.lng();
        var steps = [];
        for (var i = 0; i < directionsResult.routes[0].legs[0].steps.length; i++){
                var pathLatLngs = [];
                for (var c = 0; c < directionsResult.routes[0].legs[0].steps[i].path.length; c++){
                        var lat = directionsResult.routes[0].legs[0].steps[i].path[c].lat();
                        var lng = directionsResult.routes[0].legs[0].steps[i].path[c].lng();
                        pathLatLngs.push( { "lat":lat , "lng":lng }  );
                }
                steps.push( pathLatLngs );
        }
        var serialSteps = JSON.stringify(steps);
        //Return custom serialized directions result object.
        return copyright + "`" + travelMode + "`" + startLat + "`" + startLng + "`" + endLat + "`" + endLng + "`" + serialSteps;
}

//Takes serialized directionResult object string as input.
//Returns directionResult object.
function deserializeDirectionsResult (serializedResult) {
        var serialArray = serializedResult.split("`");
        const travMode = serialArray[1];
        var directionsRequest = {
            travelMode: travMode,
            origin: new google.maps.LatLng(serialArray[2], serialArray[3]),
            destination: new google.maps.LatLng(serialArray[4], serialArray[5]),
        };
        var directionsResult = {};
        directionsResult.request = directionsRequest;
        directionsResult.routes = [];
        directionsResult.routes[0] = {};
        directionsResult.routes[0].copyrights = serialArray[0];
        directionsResult.routes[0].legs = [];
        directionsResult.routes[0].legs[0] = {};
        directionsResult.routes[0].legs[0].start_location = directionsRequest.origin;
        directionsResult.routes[0].legs[0].end_location = directionsRequest.destination;
        directionsResult.routes[0].legs[0].steps = [];
        var deserializedSteps = JSON.parse(serialArray[6]);
        for (var i = 0; i < deserializedSteps.length; i++){
                var dirStep = {};
                dirStep.path = [];
                for (var c = 0; c < deserializedSteps[i].length; c++){
                        var lat = deserializedSteps[i][c].lat;
                        var lng = deserializedSteps[i][c].lng;
                        var theLatLng = new google.maps.LatLng(lat, lng);
                        dirStep.path.push( theLatLng );
                }
                dirStep.travel_mode = travMode;
                directionsResult.routes[0].legs[0].steps.push( dirStep );
        }
        return directionsResult;
}


For anyone still looking to solve this issue, you really just need to convert the Lat/Lng properties to google.maps.LatLng objects.

function deserializeDirectionsResult(directions) {
    directions.routes.forEach(function (route) {
        route.legs.forEach(function (leg) {
            leg.end_location = new google.maps.LatLng(leg.end_location.lat, leg.end_location.lng)
            leg.start_location = new google.maps.LatLng(leg.start_location.lat, leg.start_location.lng)

            leg.steps.forEach(function (step) {
                step.end_location = new google.maps.LatLng(step.end_location.lat, step.end_location.lng);
                step.end_point = new google.maps.LatLng(step.end_point.lat, step.end_point.lng);
                step.start_location = new google.maps.LatLng(step.start_location.lat, step.start_location.lng);
                step.start_point = new google.maps.LatLng(step.start_point.lat, step.start_point.lng);

                step.lat_lngs.forEach(function (lat_lng) {
                    lat_lng = new google.maps.LatLng(lat_lng.lat, lat_lng.lng);
                });

                // Optional property
                if (step.hasOwnProperty('steps')) { 
                    step.steps.forEach(function (stepStep) {
                        stepStep.end_location = new google.maps.LatLng(stepStep.end_location.lat, stepStep.end_location.lng);
                        stepStep.start_location = new google.maps.LatLng(stepStep.start_location.lat, stepStep.start_location.lng);

                        stepStep.lat_lngs.forEach(function (lat_lng) {
                            lat_lng = new google.maps.LatLng(lat_lng.lat, lat_lng.lng);
                        });

                        stepStep.path.forEach(function (path_item) {
                            path_item = new google.maps.LatLng(stepStep.path.lat, stepStep.path.lng);
                        });
                    });
                }
            });
        });
    });

    return directions;   
}


You could also try lodash's _.cloneDeepWith:

function deserializeAnything(previouslyStringified) {
    return _.cloneDeepWith(previouslyStringified, function (value) {
        if (value.lat !== undefined && value.lng !== undefined) {
            return new google.maps.LatLng(value.lat, value.lng);
        }
    });
}

This basically turns every LatLngLiteral into a LatLng at any level within the original object (or array)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜