Unable to process GoogleMaps DirectionsResult Object for deserialization

Currently, I am facing an issue with the GoogleMaps API v3.0 where I am trying to store a DirectionsResult in my database and then retrieve it later for use on a map. The problem arises when I attempt to restore the saved object by extracting its JSON representation from the database - the re-hydrated object turns out to be just plain JSON without the original methods and functions of its constituent objects. To combat this, I created a correction routine that takes the raw JSON and reconstructs it by rebuilding all the LatLng and LatLngBound objects. However, there seems to be something missing as my corrected object does not fully replicate the functionality of the original; although the two points are displayed on the map, the purple line connecting them is absent.

I would greatly appreciate any suggestions regarding better techniques for serialization/hydration or insights into what might be lacking in my correction routine.

Thank you.

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);  //<<==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);
  }
 }
} 

Answer №1

It appears that the issue lies in the way you are accessing the latitude and longitude values in your code. The Google Maps API library is minified, so variable names are often shortened to random characters. Instead of directly accessing x and y properties, it is recommended to use getters like lat() and lng() to prevent issues with future updates. This could be why your directions are not rendering correctly.

The correct way to retrieve lat and lng values is as follows:

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

For example, instead of the following lines:

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

You should use:

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());

Storing Google Map Data is subject to terms of service restrictions. Please review the following limitations before proceeding with 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, prohibited actions include: (i) modifying map tiles on a server-side; (ii) combining multiple static map images for a larger map display than allowed in the Maps APIs Documentation; (iii) using the Content for generating mailing or telemarketing lists; or (iv) exporting or saving the Content to third-party location-based platforms or services.

    (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 instance, avoid creating an independent database of “places” using the Content.

    (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, refrain from offering batch geocoding services that utilize Content from the Maps API(s).

Answer №2

The code provided above was not working for me, so I decided to create my own solution. I have developed two functions that can serialize and deserialize a DirectionsResult object. These functions are designed to only include the essential data required for plotting a route. However, if you find that the deserialized DirectionsResult is missing certain features you need, you will have to customize the code by adding any additional attributes of the DirectionsResult object that you require.

I urge you not to misuse this code. Google has specific rules regarding the storage of Maps data, and it should only be stored temporarily (no longer than 30 calendar days).

//This function takes Google Maps API v3 directionsRequest and directionsResult objects as input.
//It returns a 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;
}

//This function takes a serialized directionResult object string as input.
//It returns a 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;
}

Answer №3

If you're still trying to resolve this particular issue, the solution lies in converting the Lat/Lng properties into google.maps.LatLng objects.

function processDirectionsResult(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;   
}

Answer №4

If you're looking for another option, you might want to consider using lodash's _.cloneDeepWith method:

function convertToLatLng(previouslySerializedData) {
    return _.cloneDeepWith(previouslySerializedData, function (data) {
        if (data.lat !== undefined && data.lng !== undefined) {
            return new google.maps.LatLng(data.lat, data.lng);
        }
    });
}

This function will transform any LatLngLiteral into a LatLng object at all levels within the original data structure.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unraveling JSON through DOJO AJAX and REST techniques

I have been attempting to send a request to a REST server using DOJO AJAX, but unfortunately I am receiving a null object as the result in the console: When CLICKED = click clientX=34, clientY=13 JSON loaded from server: null Below is the code snippet I ...

Unable to receive output from PHP script

The code snippet provided above does not display anything in the browser. All the database and table names seem to be correct. Interestingly, when a line of code echo json_encode($temp) is added within the while loop, it shows the results as objects. & ...

What is the best way to iterate through results in a Realm custom resolver function when receiving a response from the

My goal is to develop a function for my custom resolver that retrieves all documents in a collection and updates the payload with new data. The code snippet below illustrates how I am currently getting one client and modifying its information: exports = (i ...

The battle between dynamic PDF and HTML to PDF formats has been a hot

In my current project, I am developing multiple healthcare industry dashboards that require the functionality to generate PDF documents directly from the screen. These dashboards do not involve typical CRUD operations, but instead feature a variety of char ...

Days and Their Corresponding Names Listed in Table

Currently, I am working on creating a "timesheet" feature that requires the user to input 2 dates. The goal is to calculate each month and year based on the input dates and then display them in a dropdown menu combobox. I would like to dynamically update ...

What is the best way to handle parsing of an empty dictionary JSON in Swift?

When working with Swift, I encountered a scenario where a dictionary returned empty while parsing JSON. How can I properly parse this into a custom object? ** Specifically focusing on the Image section ** }, "name": "Al bake", "image": { ...

A variant of setTimeout designed specifically for family members

I am currently working on a program that involves creating a "health" variable which decreases by random amounts at random intervals. This means that a player may encounter scenarios like the following: 5 seconds Lose 20 health 3 more seconds Lose 25 healt ...

Here's a unique version: "A guide on using jQuery to dynamically adjust the background color of table

I need some assistance with changing the background color of td elements based on the th class. Specifically, I want to target all td elements under the bots class in the HTML code provided below. <table border="1" class="CSSTableGenerator" id="myTab ...

'When trying to access the 'get' attribute in Python Flask's login function, an AttributeError was raised indicating that the object was of type 'None

I am currently working on implementing a login feature using Python Flask to authenticate my APIs. However, I am encountering an issue when trying to extract the email and password for authentication, leading to the following error message: 'NoneType& ...

Exploring the World of Metaprogramming with AngularJS Filters

Can we generate filters dynamically in Angular? Below are some basic filters that extract specific properties from an array of objects. module.filter("firstAndLastName", function() { return function(input) { return input.map(function(obj) { ...

Adapt appearance according to the length of the text

Currently, I have an array that stores multiple strings based on displayed charts. My objective is to find the longest string within this array. So far, this task has been executed without any issues. The code snippet for this process is as follows: var ...

Ways to retrieve the complete user object in passport

Recently, I've been diving into utilizing Express authentication with Passport and React for the frontend. While working on this project, a question came up: How can I access the entire authenticated user object? This is what my database model looks l ...

When utilizing Vuetify's v-for directive, each list item will reveal its menu upon being clicked

How can I make each item in my Vuetify list open a menu individually on click, instead of opening all menus at once when any item is selected? <v-list-item-group> <RecycleScroller v-if="drive_stop_info.drive_stop_list.lengt ...

What steps can I take to restrict a draggable element to the body, prevent text selection, and allow form inputs to be enabled?

I'm currently utilizing the react-draggable library for my project. In order to ensure that the element remains within the confines of the body element, prevent text selection, and allow interaction with form inputs inside the draggable element, I en ...

Multiple requests were made by Ajax

I am facing an issue with my ajax code where it is being called multiple times. Below is my php code: (While loop extracts results from a database. For brevity, I have included just the modal and dropdown menu sections.) $rezPet = mysqli_query($kon, "SEL ...

Exclude JSON NULL values in R

Hello Everyone, I'm working on a simple R script to parse a JSON file: json <- rjson::fromJSON(readLines('http://data.rada.gov.ua/ogd/zpr/skl8/bills- skl8.json', warn=F)) bills <- data.frame( id = numeric(), title = cha ...

iterating over a list of files using JavaScript

I am currently working on setting up individual ajax requests for each file being uploaded. I have a functioning ajax call that creates a record, returns some html, and provides the tempID of the record which is then used in another ajax call that triggers ...

In a React/Redux component, there is a requirement to automatically fill a specified number of fields based on the selection made

Although this question is reminiscent of a previous one I asked, I have since restructured my project to incorporate Redux. Currently, I have a component that dynamically generates dropdown contents based on a data response from the app. One of the dropd ...

What is the correct way to transform a list of lists into JSON using Python?

Recently, I encountered an issue with converting a list of lists with strings containing double quotes into JSON in Python. Here is the scenario: new_row = [['<a href=/account_dtls/risks/edit/ACC-RISK-136053>ACC-RISK-136053</a>', &apo ...

Angular animation not firing on exit

I am encountering an issue with my tooltip component's animations. The ":enter" animation is working as expected, but the ":leave" animation never seems to trigger. For reference, here is a link to stackblitz: https://stackblitz.com/edit/building-too ...