The following is a fully functional implementation using the Google Maps Javascript API. All you need to add is your own Google Maps API. As noted in the messages mentioned above, Google Maps throttles requests at an asymptotic rate, and thus, the longer the route, the longer it will take to compute. To give the stadium, the route from New Haven CT to the NJ / PA border takes about 5 minutes. The drive from New Haven to Los Angeles takes 45 minutes to index. One more note. There are several state borders that cross water bodies. Google believes that they are not in any state and therefore report undefined as the name of the state. These sections are obviously only a few tenths of a mile in most cases, but I felt that I should mention it simply to clarify what happens when it happens.
UPDATED:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://maps.googleapis.com/maps/api/js?key=<YOUR-KEY-HERE>"></script> <div id="map" style="height:400px"></div> <div id="status"></div> <div id="results" style="height:400px"><b>Results:</b></div> <script> var directionsRequest = { origin: "New York, NY", //default destination: "Los Angeles, LA", //default optimizeWaypoints: true, provideRouteAlternatives: false, travelMode: google.maps.TravelMode.DRIVING, drivingOptions: { departureTime: new Date(), trafficModel: google.maps.TrafficModel.PESSIMISTIC } }; directionsRequest.origin = prompt("Enter your starting address"); directionsRequest.destination = prompt("Enter your destination address"); var starttime = new Date(); var geocoder = new google.maps.Geocoder(); var startState; var currentState; var routeData; var index = 0; var stateChangeSteps = []; var borderLatLngs = {}; var startLatLng; var endLatLng; directionsService = new google.maps.DirectionsService(); directionsService.route(directionsRequest, init); function init(data){ routeData = data; displayRoute(); startLatLng = data.routes[0].legs[0].start_location; endLatLng = data.routes[0].legs[0].end_location; geocoder.geocode({location:data.routes[0].legs[0].start_location}, assignInitialState) } function assignInitialState(data){ startState = getState(data); currentState = startState; compileStates(routeData); } function getState(data){ for (var i = 0; i < data.length; i++) { if (data[i].types[0] === "administrative_area_level_1") { var state = data[i].address_components[0].short_name; } } return state; } function compileStates(data, this_index){ if(typeof(this_index) == "undefined"){ index = 1; geocoder.geocode({location:data.routes[0].legs[0].steps[0].start_location}, compileStatesReceiver); }else{ if(index >= data.routes[0].legs[0].steps.length){ console.log(stateChangeSteps); index = 0; startBinarySearch(); return; } setTimeout(function(){ geocoder.geocode({location:data.routes[0].legs[0].steps[index].start_location}, compileStatesReceiver); $("#status").html("Indexing Step "+index+"... ("+data.routes[0].legs[0].steps.length+" Steps Total)"); }, 3000) } } function compileStatesReceiver(response){ state = getState(response); console.log(state); if(state != currentState){ currentState = state; stateChangeSteps.push(index-1); } index++; compileStates(routeData, index); } var stepIndex = 0; var stepStates = []; var binaryCurrentState = ""; var stepNextState; var stepEndState; var step; var myLatLng = {lat:39.8282, lng:-98.5795}; var map = new google.maps.Map(document.getElementById('map'), { zoom: 4, center: myLatLng }); function displayRoute() { directionsDisplay = new google.maps.DirectionsRenderer(); directionsDisplay.setMap(map); directionsDisplay.setDirections(routeData); } var orderedLatLngs = []; function startBinarySearch(iterating){ if(stepIndex >= stateChangeSteps.length){ for(step in borderLatLngs){ for(state in borderLatLngs[step]){ for(statename in borderLatLngs[step][state]){ $("#results").append("<br>Cross into "+statename+" at "+JSON.stringify(borderLatLngs[step][state][statename], null, 4)); orderedLatLngs.push([borderLatLngs[step][state][statename], statename]); } } } compileMiles(true); return; } step = routeData.routes[0].legs[0].steps[stateChangeSteps[stepIndex]]; console.log("Looking at step "+stateChangeSteps[stepIndex]); borderLatLngs[stepIndex] = {}; if(!iterating){ binaryCurrentState = startState; } geocoder.geocode({location:step.end_location}, function(data){ if(data === null){ setTimeout(function(){startBinarySearch(true);}, 6000); }else{ stepNextState = getState(data); stepEndState = stepNextState; binaryStage2(true); } }); } var minIndex; var maxIndex; var currentIndex; function binaryStage2(init){ if (typeof(init) != "undefined"){ minIndex = 0; maxIndex = step.path.length - 1; } if((maxIndex-minIndex)<2){ borderLatLngs[stepIndex][maxIndex]={}; borderLatLngs[stepIndex][maxIndex][stepNextState]=step.path[maxIndex]; var marker = new google.maps.Marker({ position: borderLatLngs[stepIndex][maxIndex][stepNextState], map: map, }); if(stepNextState != stepEndState){ minIndex = maxIndex; maxIndex = step.path.length - 1; binaryCurrentState = stepNextState; stepNextState = stepEndState; }else{ stepIndex++; binaryCurrentState = stepNextState; startBinarySearch(true); return; } } console.log("Index starts: "+minIndex+" "+maxIndex); console.log("current state is "+binaryCurrentState); console.log("next state is "+ stepNextState); console.log("end state is "+ stepEndState); currentIndex = Math.floor((minIndex+maxIndex)/2); setTimeout(function(){ geocoder.geocode({location:step.path[currentIndex]}, binaryStage2Reciever); $("#status").html("Searching for division between "+binaryCurrentState+" and "+stepNextState+" between indexes "+minIndex+" and "+maxIndex+"...") }, 3000); } function binaryStage2Reciever(response){ if(response === null){ setTimeout(binaryStage2, 6000); }else{ state = getState(response) if(state == binaryCurrentState){ minIndex = currentIndex +1; }else{ maxIndex = currentIndex - 1 if(state != stepNextState){ stepNextState = state; } } binaryStage2(); } } var currentStartPoint; var compileMilesIndex = 0; var stateMiles = {}; var trueState; function compileMiles(init){ if(typeof(init)!= "undefined"){ currentStartPoint = startLatLng; trueState = startState; } if(compileMilesIndex == orderedLatLngs.length){ directionsRequest.destination = endLatLng; }else{ directionsRequest.destination = orderedLatLngs[compileMilesIndex][0]; } directionsRequest.origin = currentStartPoint; currentStartPoint = directionsRequest.destination; directionsService.route(directionsRequest, compileMilesReciever) } function compileMilesReciever(data){ if(data===null){ setTimeout(compileMiles, 6000); }else{ if(compileMilesIndex == orderedLatLngs.length){ stateMiles[stepEndState]=data.routes[0].legs[0].distance["text"]; $("#results").append("<br><br><b>Distances Traveled</b>"); for(state in stateMiles){ $("#results").append("<br>"+state+": "+stateMiles[state]); } var endtime = new Date(); totaltime = endtime - starttime; $("#results").append("<br><br>Operation took "+Math.floor(totaltime/60000)+" minute(s) and "+(totaltime%60000)/1000+" second(s) to run."); return; }else{ stateMiles[trueState]=data.routes[0].legs[0].distance["text"]; } trueState = orderedLatLngs[compileMilesIndex][1]; compileMilesIndex++; setTimeout(compileMiles, 3000); } } </script> </script>
Isaac ray
source share