Bryan Hughes Bryan Hughes - 6 months ago 7
HTML Question

how can the same item be undefined in one instance yet defined in another

4 days and still can't figure it out. The script below will calculate how many miles driven in each state starting with the origin, and ending with the destination.
if your route goes through more than one state, the table is populated with the 2 letter state abbreviation and in the 2nd column with the miles for that state. if your route stays within the same state however, the mileage is correctly calculated and displayed in column 2 of the table, but the 2 letter state abbreviation is not displayed in column 1, instead it says undefined. how can it be defined when 2 or more states are traveled in, and undefined if only one state is traveled in. shouldn't it be one way or the other in both situations???

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
<meta name="dcterms.created" content="Tue, 03 May 2016 17:18:33 GMT">
<meta name="description" content="">
<meta name="keywords" content="">
<title></title>

<!--[if IE]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->


<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= &callback"></script>
<body>
<div id="map" style="height:400px"></div>
<div id="status"></div>
<div id="results"></div>
<div id="table"></div>


<div style=" text-align: left; text-indent: 0px; padding: 0px 0px 0px 0px; margin: 0px 0px 0px 0px;">
<table>
<table width="40%" border="1" cellpadding="2" cellspacing="2" style="border-color: #000000; border-style: solid; background-color: #ffffff;">
<tr valign="top">
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state1"><br />
</td>
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile1"><br />
</td>
<tr valign="top">
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state2"><br />
</td>
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile2"><br />
</td>
<tr valign="top">
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state3"><br />
</td>
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile3"><br />
</td>

<tr valign="top">
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state4"><br />
</td>
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile4"><br />
</td>
<tr valign="top">
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state5"><br />
</td>
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile5"><br />
</td>
<tr valign="top">
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state6"><br />
</td>
<td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile6"><br />
</td>




</tr>

</table>
</div>

</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]){
(JSON.stringify(borderLatLngs[step][state][statename],null, 4));
orderedLatLngs.push([borderLatLngs[step][state][statename], statename]);
}
}
}
compileMiles(true);
return;
//$("#results").append("<br>Cross into "+statename+" at "+

}
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"];


var txt = "";
var i = 0;



for(state in stateMiles)
{
i++;
$("#results").append

$(".state"+i).append(state);
$(".mile"+i).append(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>

</script>




</script>





</head>

</script>



</body>
</html>

Answer

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="generator" content="CoffeeCup HTML Editor (www.coffeecup.com)">
    <meta name="dcterms.created" content="Tue, 03 May 2016 17:18:33 GMT">
    <meta name="description" content="">
    <meta name="keywords" content="">

    <!--[if IE]>
        <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <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"></script>
</head>

<body>
    <div id="map" style="height:400px"></div>
    <div id="status"></div>
    <div id="results"></div>
    <div id="table"></div>
    <div style=" text-align: left; text-indent: 0px; padding: 0px 0px 0px 0px; margin: 0px 0px 0px 0px;">

        <table width="40%" border="1" cellpadding="2" cellspacing="2" style="border-color: #000000; border-style: solid; background-color: #ffffff;">
            <tr valign="top">
                <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state1"><br />
                </td>
                <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile1"><br />
                </td>
                <tr valign="top">
                    <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state2"><br />
                    </td>
                    <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile2"><br />
                    </td>
                    <tr valign="top">
                        <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state3"><br />
                        </td>
                        <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile3"><br />
                        </td>

                        <tr valign="top">
                            <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state4"><br />
                            </td>
                            <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile4"><br />
                            </td>
                            <tr valign="top">
                                <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state5"><br />
                                </td>
                                <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile5"><br />
                                </td>
                                <tr valign="top">
                                    <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="state6"><br />
                                    </td>
                                    <td style="border-color : #000000 #000000 #000000 #000000; border-style: solid;" class="mile6"><br />
                                    </td>
                                </tr>
                            </tr>
                        </tr>
                    </tr>
                </tr>
        </table>
    </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]) {
                            (JSON.stringify(borderLatLngs[step][state][statename], null, 4));
                            orderedLatLngs.push([borderLatLngs[step][state][statename], statename]);
                        }
                    }
                }
                compileMiles(true);
                return;
                //$("#results").append("<br>Cross into "+statename+" at "+

            }
            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) {
                    // HERE'S THE FIX -- BEGIN
                    if (!stepEndState) {
                        stepEndState = startState;
                    }
                    // HERE'S THE FIX -- END
                    stateMiles[stepEndState] = data.routes[0].legs[0].distance["text"];

                    var txt = "";
                    var i = 0;
                    for (state in stateMiles) {
                        i++;
                        $("#results").append
                        $(".state" + i).append(state);
                        $(".mile" + i).append(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>

</body>
</html>

The problem is that stepEndState doesn't have a value if the step doesn't cross a state boundary. One fix: add a check to the function compileMilesReciever() so that if stepEndState doesn't have a value, use startState instead:

if(compileMilesIndex == orderedLatLngs.length) {
  if (!stepEndState) {
    stepEndState = startState;
  }
  stateMiles[stepEndState]=data.routes[0].legs[0].distance["text"];