To follow along with this video, you need to have geolocation data associated to the Salesforce objects in your Salesforce Maps instance. If you still need to augment objects with geolocation data, check out Part I of the video series here.
In Part 2 of our Salesforce Developer Deep Dive series on Salesforce Maps, TruSummit Solutions’ Senior Salesforce Developer Mike Chandler presents a comprehensive demo unlike anything else publicly available, taking you step-by-step through leveraging Salesforce Maps to determine driving time and driving distance between two locations. In just under 30 minutes, Mike demos how to build a custom Apex component, highlights mission-critical dependencies and considerations, walks through data conversions, and ultimately ends with a working data structure for determining drive time and distance in Salesforce Maps.
TRANSCRIPT:
Hi, I’m Mike, a Salesforce developer with TruSummit Solutions. In this video, I’ll cover what you need to know in order to leverage Salesforce maps to determine driving time and driving distance between two locations. This video is part two in a series of development focused Salesforce maps tutorials. We’ll be looking at time calculations and driving distances between two locations. Before we begin, you need to make sure that you have geolocation data associated to the objects you intend to work with. If you don’t have that in place, be sure to check part one of this series. The link for that video can be found in the video description. If you already have geolocation data apply to your object records, then you’re ready to begin. I’m working in a developer org for this example and I’m on an account page. There’s not much to see on this example account record, aside from the fact that it is an actual account and I’ve got a billing address on the record.
If you’re following this series of videos, then you know that I’ve created a Salesforce Maps base object for accounts of this type, and I’ve made sure that these records have geolocation data, specifically longitude and latitude values, and that’s very important to derive the drive times and the distances between locations. Using Salesforce maps, a longitude and a latitude value is required on both the starting location and the destination record. I’m going to use a handy Chrome plugin to inspect all the field values on this record to confirm that I have a longitude and a latitude value. So I’ll go ahead and select show all data, and I’ll just cruise down here and look at my fields, and I do see that I’ve got a billing latitude and a billing longitude, so that’s good. It confirms that I’ve got the data that I need and that I’m in good shape.
I’ve already created a custom component that leverages drive times and driving distances, so let’s have a look at that to see what I’m doing. I’m just going to click on my driving distance tab here. Salesforce maps ships with really great tools for rendering maps of nearby records, but that’s actually not what we’re looking at here. This is a custom component that shows records that are filtered by drive time calculations and restricted to show only locations that are 20 minutes away or less. The map on the left side of the component plots, markers on the map representing nearby account records, and then of course, the data table here on the right provides the details for each of these matches, specifically the driving distance and miles and the number of minutes it will take to reach that destination from the billing address of the account that we’re looking at.
To build a component yourself that does something similar, you need to get drive time and drive distance data from the Salesforce Maps API so that you can access those data points in Apex. Let’s talk about that and cover not only how that works, but what to consider before designing your solution. To start, I recommend conducting a Google search with this search term Salesforce Maps distance matrix. That very first result is a gold mine of helpful information. I’m just going to go ahead and select that, confirm that that’s what we need and it definitely is. This is going to give us what we want. We’ve landed on a Salesforce Maps Apex developer guide, so let’s just go ahead and make sure to look at the overview to have a good sense of what we’re about to get ourselves into. One of the first things you’ll see is a warning from Salesforce indicating that heavy dependencies on the Salesforce maps API may result in a performance problem.
And one of the things to keep in mind is that Salesforce maps is largely driven by data obtained from the Google Maps API. I’m uncertain of the circumstances there, but it’s likely that Salesforce and Google have an agreement in place that allows them to transform and delegate Salesforce Maps API requests directly to the Google Maps API, which exists of course outside the realm of Salesforce’s technology stack. So to that end, Salesforce is going to have very limited control when it comes to handling speed and performance of certain requests, and they want all of us as developers just to be aware of that and be prepared to handle it. So we’ll talk about that in greater detail later in the video. Let’s look at the requirements for Salesforce maps customizations in Apex and just make sure that we’re covered. Obviously, you need Salesforce maps installed on your org and your org needs to be either enterprise or unlimited or of course a developer org.
The running user that’s going to be executing your Apex based solution will need to have the proper permission sets assigned as well. Make note of the warning that appears on this page right here, you can’t miss it. Actually, I’ll scroll down a little bit. Since the API is effectively making call outs from Apex classes to Google Maps under the hood, you face a risk of uncommitted work exceptions and you’ll need to account for that based on your use case. That’s an important thing. Obviously Salesforce wants to make that perfectly clear, which is why it’s called out in the documentation. Let’s jump back to the documentation on the distance matrix so that we can understand what’s necessary to build out these distance calculations. So I’m going to comb over here to the Apex methods portion of the documentation, and I see this get the distance matrix link.
I’ll click that. The documentation informs us that the distance matrix when calculating distances between two points referred to as A and B will return drive time and drive distance calculations for a route from location A to B as well as for a route from location B to A. That’s because the driving routes and times can differ based on which location is being used as the starting point. Also, drive time calculations returned in the matrix include more than one travel time window, which is really quite interesting and helpful. Consider that driving from point A to point B in the morning during commuter traffic at 7:00 AM or 8:00 AM may take longer if you were making that same drive at 12:00 PM in the afternoon. The distance matrix accounts for the possibility that you may be looking for such granular details. So drive times are calculated for eight predefined time windows based on historical traffic data.
Scrolling down a little, we see that the method signature doesn’t really us much of a clue as to what we’re sending or getting back from the API. We’re sending it a list of maps and we’re getting back a map. We need to do a little bit more research to fully understand what’s going on here. Take note of this critical heads up in the allocations portion of the documentation. You can calculate times and distances between no more than 20 locations in a single request. You may need to resolve times and distances between many more than 20 locations overall. So this is a very important consideration based on the specifics of your solution. Let’s keep this 20 location limited in mind while we talk through our solution possibilities here. We know that the API accepts a list of maps and returns a map, but we have to look at some sample code to get a better idea of what they’re actually looking for.
In this sample apex, we see two map data structures being created. Each one appears to represent a location. Each map includes a key called location underscore id. This value is what the matrix will use to identify your location. So it could be a name or an object id or really any unique string value that represents your location. Additionally, each map includes a longitude and latitude value. So if you look closely at this example, you can see two map data structures being created, each representing a location with longitudinal latitude. Both maps are included in a single list called locations, and then the locations are submitted as an argument to the get distance matrix function on the maps API class. So let’s go do some work in Apex in our org. Try this out. I’m going to make use of anonymous Apex that we can make some requests to the API and get a response and then we’ll want to inspect that response.
Okay, I’m working in anonymous apex right now. It might look a little bit different because I am in the IDE as opposed to the standard developer console, but the window that we’re looking at right now is really just going to be my composition window and then we’ve got the window next to it, which represents our Apex logs. So let’s just go ahead and start typing away. The first thing I’ve done is I’ve created a list of maps called locations, and I’ve just really initialized that variable. It’s not doing anything yet. Let’s go ahead and define some map data structures that represent the locations that we want to work with. So what we’ll do for this example is we’ll just see if we can calculate drive times and drive distances between two popular Southern California amusement parks. One of ’em of course is Disneyland. The other one is an amusement park called Knots Berry Farm. I’ll start by creating a location for Disneyland. So this map represents our first location. Like I said, this is Disneyland. So we identify the location ID as Disneyland. That’s going to be a very memorable marker for us. And then we identify the latitude and the longitude values, and then that represents a data structure of our first location. So we’ll just add this location to our collection.
And now we’ll go ahead and we will define our second location, which is Knot Berry Farm. So we’ve got our second location defined and I’m going to go ahead and add that one to the locations collection as well.
Okay, so I’ve added my second location of Knottsberry Farm and I’m going to go ahead and add it to my collection of locations, which we’ll then send to the Salesforce Maps API. Now we selected Disneyland and Knottsberry Farm as our two locations to test with because we know that those two amusement parks are 10 miles or less away from each other. So as we test this, we just want to make sure that those are the results that we’re getting back. So we’ll send this now to the Salesforce maps API to do that, we just referenced the get distance matrix function on the API class. Let’s do that. Now we know that the get distance matrix function is going to return a map, so we will initialize a variable called response as the type map with a string object parameters and we’ll say maps API get distance matrix and we will send it our two locations.
And now we know that we want to see the output of this response. So for the purposes of our test, we’ll just go ahead and include a debug statement and output the value of response just to make sure that we’re getting what we are expecting. I’ll go ahead and test this by clicking the execute button. Oops, live coding. We do have a syntax error that I need to fix. Let me fix that and then we’ll try this again. I’ll execute that. And this time it looks like it’s going to think a little bit more. Now, one of the things that you’ll notice when you’re invoking this API is that it’s not super quick. That was just two locations and it came back in about a second and a half. Let’s examine what we’ve got here in our APEX logs and just see if this is everything that we want.
Now it’s outputting the data in a map and it’s not always easy to kind of traverse the values that you see in a data structure of this type in your Apex log. So we’re going to do something that’s going to give us a little bit more insight into what our data is. I’m just going to go back over to Apex and we know from the documentation that it’s giving this to us in a map, but what we want to do is we just want to just serialize this back into JSON so that we can see the raw JSON string. And the way I’m going to do that is just by saying debug JSON serialize my response and I’ll save that. Now, I’ll execute this again and I should get two debug statements this time.
The first is the debug statement that represents the map. The second is a debug statement that represents the JSON string. So let’s go ahead and grab that, and I’m just going to go ahead and paste my JSON into this JSON formatter. I really enjoy using this JSON format. I’ve been using it for a number of years. There’s probably a variety of different tools that I could use, but muscle memory, I always come here. I’m going to go ahead and process this JSON, and this will give me just a better view into what we’re getting back. I’ll minimize some of the things that I know I don’t want to look at immediately. What’s going to be important to me is going to be the data that we’ve got in this data node as well as the value of this success node here. So I’m always going to expect that.
I’ll want to look at the success node and just evaluate whether or not I have a true or a false. It seems to me like that’s a pretty easy way to determine whether or not I need to proceed with my processing or if I need to account for an error. So assuming that in most cases you get back a success value of true, let’s inspect the data node and see what we have there. So I’ve minimized a few things just to make it a little bit easier to read, but let’s go ahead and start talking about them. I think what we want to do is expand what we’ve got here in the data node specifically in this node called solutions. So let’s open that up and we see we’ve got some details such as the locations so we can specify more details about the locations that are in our request. We get some time zones here that are associated to each of our respective location IDs. I’ll minimize that. The traffic windows, this is going to make a little bit more sense when I show you what we’ve got in the travel costs. Value travel costs is really where our most valuable data exists in this response. So let’s expand that.
So the first thing that you see is the Knotts Berry Farm node. And what this is going to do is it’s going to tell us that Knotts Berry farm being the starting point, what are the location and distance details between location, Knotts Berry farm and location Knotts Berry Farm? Well, those are both the same location, so unsurprisingly, we get a bunch of zeros. So let’s minimize that. Let’s instead look at the distance between Knotts Berry Farm and Disneyland. So what you get in the response value here, you can see that it’s showing us an array of numeric figures, and that’s one of the things that you need to decipher to make sure that you’re getting the data that you need here. The first element in this array represents a value in meters, and this value is the distance. Every value after that distance is something else. It’s not distance, it’s time.
So attribute number one represents distance in meters. And you can see here that the distance between Knottsberry farm and Disneyland is 12,000 hundred meters. And then all of these figures here, like I’d said, they represent time, but they are time in seconds. It’s how many seconds does it take to drive from Knotts Berry Farm to Disneyland given 12,000 meters as the distance? So obviously you’ve got some conversion work to do here to get what you want. If you are in the United States and you want to represent distance in miles, you’ve got to convert that. If you are in Europe and you want to represent distance in kilometers, you would have to convert that as well. The most obvious first question would be why do we have multiple figures that represent time? And that’s where the travel windows come into play. So let’s take a look at those.
I’m going to scroll down in my data a little bit and I’m going to open up the traffic windows node so that we can have a look at what that is. So the traffic windows represent start times and end times throughout the course of a given day. You’ll see here that the first traffic window represented as traffic window index zero has start times and end times of midnight and 6:30 AM Let’s go to the second traffic window represented as traffic window index One has start times of six 30 to seven 30. Traffic window index number two has start times of seven 30 to eight 30 and it goes on from there. Hopefully you get the idea of what they’re trying to represent here. Let’s scroll back up and look at the data. The figure that I’ve highlighted is the first figure representing times between Knottsberry farm and Disneyland.
And you can see here that it’s 1,318 seconds. If you recall, that traffic window is midnight to 6:30 AM The second traffic window is this one, and you can see that’s 1,423 seconds. That traffic window is six 30 to 7:30 AM This is the third time figure that I’m highlighting here, and this represents the other, sorry, the last traffic window that we were looking at, which is seven 30 to eight 30 in the morning. I’ve minimized a variety of different keys in this data structure. I want to start working with data. So let’s go back to Apex and see if we can get a handle on this data node here. To get a handle on the data node, I’m going to first declare a map called data node, and I’m going to set that by just getting that data key in the data structure and this line with the semi, but that syntax error indicates that we don’t have the correct type on this.
So I’m going to go ahead and cast to a map parameterized with string and object and then that’s going to make it happy. So now that we’ve got the data node as its own data structure, let’s traverse deeper into it so that we can get additional data. And we’ll do that by going back to the browser. And what we want to do is we want to dig into everything that we’ve got under solution and travel costs. So let’s do that. So back in Apex, I’m going to go ahead and create two additional maps and I’m going to derive these maps from these keys solution and travel costs. So let’s do that. Okay, so first I’ve got the solution node and I was able to derive that by making use of the data node that we just collected, and I’m invoking the get method and grabbing the solution key. And the next one I want to grab is travel costs, and we know that that’s going to be on the solution node, so let’s get that.
And so my second line makes use of the solution node that we just created. We’re going to invoke get, and we’re going to identify the key as travel costs, and we’ll set that to a node called the travel cost node. Now, let’s go ahead and run what we’ve got so far and just make sure that we don’t have any syntax errors or any exceptions that are being thrown. Okay, and so far so good, no exceptions. Let’s jump back to the browser and just look again at the JSO that we’re inspecting and see what we need to do next. So we’ve been able to navigate into the data structure and we’ve been able to retrieve this data node and go into the solution node and the travel cost node, and we’re now at the point where we can start to identify some of our locations. So let’s do that.
We’re going to start with Knottsberry Farm and what we want to understand is what are the distance values between Knottsberry Farm and Disneyland? So we’re currently in the travel costs node right now, and the next key down is going to be our locations. So let me minimize Knots Berry Farm and I’ll minimize Disneyland. And you can see that travel costs consists of just our two locations, knots, Berry Farm and Disneyland. And in each of these locations we have additional structures. One of them is Knots Berry Farm to Knots, Berry Farm, and the other is Knot Berry Farm to Disneyland. What we want to know is Knot Berry Farm to Disneyland. So first thing we need to do is we need to get a handle on this data structure specifically related to Knottsberry Farm. Let’s do that back in my Apex. I’m going to retrieve the Knottsberry Farm key off of the travel costs node.
So leveraging the travel costs node I’m invoking get and I’m specifying the key Knottsberry farm, I’m setting that to a map called Knotts location. So now Knotts location theoretically should consist of all of the data that’s relevant to navigate from Knottsberry Farm to its locations, but we only have one that we’re concerned about, and that’s the distance between Knottsberry Farm and Disneyland. So let’s get the data that we know that we’ve got in the data structure for Disneyland to get that. Let’s go again and inspect the data that we’ve got in our JSON. So we know that we’re now working with the data structure that’s representative of data from here and below. Now we don’t care about the distance between Knottsberry farm and itself, so we’re just going to ignore this key in this data structure. And we’re instead going to get this key. We want Disneyland. So let’s go back to Apex and do that. So we need to talk a little bit about what the data structure is that you’re going to retrieve here. So before we actually set this in stone, I’m just going to make a generic and I’m going to call it an object and I want to call this Disneyland data, and I want to get that by working off of the Knots location data structure. So we’ll say Knots, location get, and we want to invoke the Disneyland key.
So theoretically this should give us everything that we want in our Disneyland key in the Knots location data structure. Let’s go back to the browser and just look at that again. So if we look at the Disneyland structure here, you’ll see that it’s going to end here. There’s not anything else below Disneyland at this point. And what this data structure is is it’s not an actual map. It is instead an array of numeric values. So we want to make sure that we cast it accordingly so that we can work with that data. So let’s go back to Apex, and what I’m going to do is I’m going to change the type here to be representative of a list of decimal values. Now, it doesn’t like that initially, so let’s make sure that we cast this object to that value.
And with that done, let’s just run it one more time just to make sure we don’t have any syntax errors. So it does look like it’s not happy with what we’re doing here. It’s complaining that I’m trying to convert at runtime a list of objects to a list of decimals, which it doesn’t like. So that’s fine. We’ll go ahead and we’ll play nice with Apex and we’ll just convert this to a list of objects instead. I’ll save that and then I’ll run it again and I expect to see that error go away and it does. With that being completed, let’s actually look and see what we’ve got. I’m going to go ahead and remove the debug statements that we have up here, and I’m going to put a new debug statement at the very end of my script, and all I want to output is what we have as Disneyland data.
Now, before I show you what we’ve got, let’s just jump back to the browser one more time. What I want to output is every single value that we have in this array. So let’s see if that’s what we actually have. I’m going to execute this again and I’m going to look at the debug data that we have in the Apex log and that’s complete. And you can see when we look at the debug data that’s in the Apex log, we in fact do have all of this data. So those values are now being output based on what we’ve got here on line 26 and line 27. So that’s great. Looking again at the debug data, you can see that we have nine different values here, all of which are decimals, but they represent completely different things. And if you recall from our discussion earlier in this video, the very first element represents the distance between the two locations and then all of the rest of these values represent time in seconds for each of the traffic windows.
We want to know what the traffic time between Knottsberry farm and Disneyland is like between seven 30 and eight 30. So that’s going to be the third traffic window. The third traffic window is actually the fourth element in this array. So we want the fourth element in this array and we want the first element in this array. The first element represents the distance, and the fourth element represents the time for the traffic window that we care about. So let’s extract that data and do some conversions. Let’s go ahead now and get that value. I want to set a decimal, and I’m going to call this distance in meters, and we will retrieve this data from the Disneyland data structure, and I just want to get the first element of that array. Now that’s going to come to us as an object. So I just want to cast that object as a decimal. And the other value that I want is the fourth element in the array, and that is the time in seconds. I’m going to get that again from the Disneyland data and because that’s the fourth element in the array, I would specify the number three index, and then we want to cast that to a decimal as well.
Now I’ve got the distance and meters and I have the time in seconds. Let’s do a little bit of conversion so that we can get the figures that we actually want to output. So I’ve created a variable called total miles, and I’m calculating the total miles based on this calculation using the distance in meters that we retrieve from our Disneyland data structure. Now I need to make sure that I understand how many minutes it takes for us to get there. So my next line sets a variable called Time in Minutes, and it calculates that by this calculation leveraging our variable called time in seconds. Now let’s output this data and see what we’ve got a very simple debug statement that makes use of the variables that we’ve just created. I’m just going to go ahead and execute this one more time and see what we’ve got.
Alright, and that executed successfully. So you can see by our debug output here in the Apex log that knots to Disneyland is 7.9 miles, which is accurate with a travel time of 25.6 minutes at the time that we selected, which is the morning rush hour time. Now that may seem like perhaps it’s off, but this is Southern California that we’re talking about and these freeways are abysmal, so this is actually quite accurate. So the data structure that you get back from the API is rather complicated and it takes a little bit of work to get to the data that you need. I’m hoping that this gives you a really good idea of what you need to do to get to the data that’s interesting to you. Go ahead and subscribe to our videos so that you can follow along with the next video in the series. I want to share with you an implementation that makes use of the distance matrix so that you get a good handle on some of the strategies for producing that data and managing that data. That’s going to be it for this video. Thank you so much for watching and I will see you in the next one.
Need help leveraging the latest Salesforce features and functionalities? Our developers are here for you! You know where to find TruSummit Solutions.
Featured Articles
How to Dynamically Set Einstein Bot Language in Messaging for In-App and Web
When deploying Einstein Bots in Salesforce’s Messaging for In-App and Web, providing a localized and personalized experience for your users…
TruSummit Solutions Achieves Salesforce Crest Consulting Partner Status
At TruSummit Solutions, we’re constantly striving to deliver exceptional value to our clients and push the boundaries of what’s possible…
Boosting Agent Productivity in Salesforce: Keeping Conversations in View with Pinned Regions
Salesforce’s new Messaging for In-App and Web feature offers a seamless way to engage customers across multiple channels, but one…