PDA

View Full Version : Resolved Local Value Lost?



bluewalrus
12-13-2010, 02:19 AM
I have this code/function which works most of the way through. I thought end, distanceArray, and the timeArray were local and should be accessible throughout the function (correct?) so at line 36 I get the correct output


alert(distanceArray[a]);

but at line 46 all the values are undefined. I figure I'm missing something here but am not sure what, this is using googles api but I think it's my JS that is incorrect. If you want to test it out yourself I got the full sample here http://174.120.151.156/~crazychr/test2.html.



function calcRoute() {
var new_address = document.getElementById('new_address').value;
// Retrieve the start and end locations and create
// a DirectionsRequest using WALKING directions.
end[0] = "Ithaca, New York, United States";
end[1] = "Fountain Valley, California, US";
end[2] = "Los Angeles, California, US";
end[3] = "San Francisco, California, US";
end[4] = "Huntsville, Alabama, US";
end[5] = "Atlanta, Georgia, US";
end[6] = "Berlin, Germany";
end[7] = "Boston, Massachusetts, US";
end[8] = "Chicago, Illinois, us";
end[9] = "Columbus, Ohio, US";
end[10] = "Detroit, Michigan, us";
end[11] = "Des Moines, Iowa, US";
end[12] = "London, England";
for (var a = 0; a < end.length; a++) {
var request = {
origin: new_address,
destination: end[a],
travelMode: google.maps.DirectionsTravelMode.DRIVING
};
// Route the directions and pass the response to a
// function to create markers for each step.
directionsService.route(request, function(response, status) {
// if (status == google.maps.DirectionsStatus.OK) {
// var warnings = document.getElementById("warnings_panel");
// warnings.innerHTML = "<b>" + response.routes[0].warnings + "</b>";
// directionsDisplay.setDirections(response);
// showSteps(response);
// }
if (response.status == "OK") {
distanceArray[a] = (response.routes[0].legs[0].duration.value * .000621371192) + " Miles";
TimeArray[a] = response.routes[0].legs[0].duration.text;
alert(distanceArray[a]);
} else {
// alert("Error with Request.");
distanceArray[a] = 9999999;
TimeArray[a] = "Never";
}
});
}
//distanceArray.sort(function(a,b){return a - b})
for (var m = 0; m < 12; m++) {
document.getElementById("output").innerHTML += "<br />\n" + m + ". " + distanceArray[m];
}
}

jscheuer1
12-13-2010, 07:04 AM
Hmm, I've looked at this some more. On the live page you have these arrays defined in the global scope, so your question was misleading. This seems to work, but you gotta click twice, change:


for (var m = 0; m < 12; m++) {
document.getElementById("output").innerHTML += "<br />\n" + m + ". " + distanceArray[m];
}

to:


for (var m = 0; m < distanceArray.length; m++) {
if (distanceArray[m]){
document.getElementById("output").innerHTML += "<br />\n" + m + ". " + distanceArray[m];
}
}

jscheuer1
12-13-2010, 09:34 AM
Gnaw we're getting somewhere:


<!DOCTYPE html>
<html>
<head>
<title>Google Maps JavaScript API v3 Example: Event Closure</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<!-- <link rel="stylesheet" type="text/css" media="screen" href="videomap.css" />
-->
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map, directionDisplay, directionsService, stepDisplay, markerArray = [], distanceArray = [], TimeArray = [], end = [];
end[0] = "Ithaca, New York, United States";
end[1] = "Fountain Valley, California, US";
end[2] = "Los Angeles, California, US";
end[3] = "San Francisco, California, US";
end[4] = "Huntsville, Alabama, US";
end[5] = "Atlanta, Georgia, US";
end[6] = "Berlin, Germany";
end[7] = "Boston, Massachusetts, US";
end[8] = "Chicago, Illinois, us";
end[9] = "Columbus, Ohio, US";
end[10] = "Detroit, Michigan, us";
end[11] = "Des Moines, Iowa, US";
function initialize() {
var myOptions = {
zoom: 10,
center: new google.maps.LatLng(0, 0),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(
document.getElementById("map_canvas"), myOptions);
setMarkers(map, videographer);
directionsService = new google.maps.DirectionsService();
var rendererOptions = {
map: map
}
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions)
// Instantiate an info window to hold step text.
stepDisplay = new google.maps.InfoWindow();
var opt = document.createElement('option'), topt;
for(var i = 0; i < end.length; ++i){
topt = opt.cloneNode(false);
topt.value = end[i];
topt.appendChild(document.createTextNode(end[i]));
document.getElementById('new_address').appendChild(topt);
}
}
var videographer = [
['One', 42.4433333, -76.5, 1],
['Two', 33.7091847, -117.9536697, 2],
['Three', 34.0522342, -118.2436849, 3],
['FOur', 37.7749295, -122.4194155, 4],
['Five', 34.7303688, -86.5861037, 5],
['Six', 33.7489954, -84.3879824, 6],
['Seven', 52.5234051, 13.4113999, 7],
['eight', 42.3584308, -71.0597732, 8],
['Nine', 41.850033, -87.6500523, 9],
['ten', 39.9611755, -82.9987942, 10],
['eleven', 42.331427, -83.0457538, 11],
['twelve', 41.6005448, -93.6091064, 12]
];
function setMarkers(map, locations) {
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < locations.length; i++) {
var videographer = locations[i], myLatLng = new google.maps.LatLng(videographer[1], videographer[2]), marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: videographer[0]
});
bounds.extend(myLatLng);
map.fitBounds(bounds);
}
}
function calcRoute(a) {
var request = {
origin: document.getElementById('new_address').value,
destination: end[a],
travelMode: google.maps.DirectionsTravelMode.DRIVING
}, output = document.getElementById('output'), r = '';
if(a === 0){
output.innerHTML = '&nbsp;';
}
directionsService.route(request, function(response, status){
if (response.status === 'OK'){
distanceArray[a] = (response.routes[0].legs[0].duration.value * .000621371192) + ' Miles';
TimeArray[a] = response.routes[0].legs[0].duration.text;
} else {
distanceArray[a] = 9999999;
TimeArray[a] = 'Never';
}
if(++a < end.length){
calcRoute(a);
} else {
for (a = 0; a < distanceArray.length; ++a) {
if (distanceArray[a]){
r += (a? '<br />\n' : '') + a + '. ' + distanceArray[a];
}
}
output.innerHTML = r;
}
});
}
function showSteps(directionResult) {
// For each step, place a marker, and add the text to the marker's
// info window. Also attach the marker to an array so we
// can keep track of it and remove it when calculating new
// routes.
var myRoute = directionResult.routes[0].legs[0];
for (var i = 0; i < myRoute.steps.length; i++) {
var marker = new google.maps.Marker({
position: myRoute.steps[i].start_point,
map: map
});
markerArray[i] = marker;
}
}
</script>
</head>
<body onload="initialize()">
<div id="form" style="width:300px; float:left; height:50px;">
<select name="new_address" id="new_address"></select>
<input type="Submit" value="Find Videographer" onclick="calcRoute(0)" />
</div>
<div id="output" style="background:#FF0000; width:200px; float:left;">&nbsp;</div>
<div id="map_canvas" style="width: 500px; height: 500px; float:left; border:3px #000000 solid; margin-left:20px;"></div>
<div id="warnings_panel"></div>
</body>
</html>

bluewalrus
12-13-2010, 07:39 PM
Thanks. This appears is functioning correctly now, except for the math which I will workout. Is there a way to search the array for the lowest value, similar to the sort but where it would display the key of the array rather than just reordering them?

Similiar to this in php



$rewritting_count = 0;
foreach ($date as $value) {
$lowest_date = min($date);
$lowest_value = array_search($lowest_date, $date);
$re_write .= "\n" . "$rewritting_count . Earlier: $month[$lowest_value]\"; \n More Detamils :$details[$lowest_value]\";\n";
unset($date[$lowest_value]);
$rewritting_count++;
}

jscheuer1
12-14-2010, 02:47 AM
I'm having trouble following. Remember, my PHP isn't so hot and you don't show the initial values going in for what look to be important variables in your snippet (at least $date, and $re_write). And these don't appear to relate to the matter at hand anyway. In other words, the snippet appears a bit more generic than I would hope, even if I could follow it precisely.

But I'm pretty sure all that can be mimicked in javascript. The min() function doesn't exist like that, but we could make one. However, in your snippet I see no key. For that:


foreach ($date as $value) {

would have to be:


foreach ($date as $key => $value) {

or some such. Or perhaps you're thinking in different terms that precludes the necessity of $key there.

Anyways, imitating PHP with javascript (or any language with another) has its limitations. Often it's better to just define the objective and use the language you're in to do it.

To that end, what's the ultimate objective here? I'm thinking it may be to display only the shortest distance, or perhaps to eliminate 0 distance(s) from the display, or something else? That's the real question here, what do you want the user to see?

Also - what if anything do you need to make a record of (like in a database) and/or pass over to another function (like one from the map API)?

Nile
12-14-2010, 02:59 AM
The min() function doesn't exist like that, but we could make one.
Math.min()? http://www.w3schools.com/jsref/jsref_min.asp But it doesn't use arrays.

traq
12-14-2010, 03:02 AM
could you use Math.min() ? Can that method accept an array of numbers, or is there a (fairly simple) way to pass every member of an array into the parameter list?

jscheuer1
12-14-2010, 03:12 AM
Yes Math.min() could be used. As I said it could be done. However, it's not a direct translation. In PHP min() can scan all the array's values in one pass. In javascript it could but it's not intended to, so could screw up. It would be much safer to iterate over the array to do so.

But, as I also said - it might be better to figure out the objective and work from there.

bluewalrus
12-14-2010, 03:14 AM
Yes, you are correct my goal here is to find the 3 shortest distances.

The $date was an array containing a serious of values. The min function finds the lowest value in the array. It then searchs the array for the found value and get its key. I then use that key to pull the data from other arrays that have the same key and store it all into one variable (this part isn't important here I just need the 3 lowest values). I unset the value so it won't be found again and the loop repeats.

Nile
12-14-2010, 03:14 AM
PHP.js: http://phpjs.org/functions/min:473

jscheuer1
12-14-2010, 04:00 AM
PHP.js: http://phpjs.org/functions/min:473

There has to be a simpler way. Give me some time and I'll get it for you.

@bluewalrus - Just to be clear, when we see for example (as a typical output for my most recent version from post #3):


0. 13.112796264776 Miles
1. 106.622946948856 Miles
2. 106.386204524704 Miles
3. 110.120645388624 Miles
4. 42.324077371888 Miles
5. 40.950225666376 Miles
6. 9999999
7. 0 Miles
8. 35.868030687008 Miles
9. 27.780884623128 Miles
10. 27.724961215848 Miles
11. 47.561615149256 Miles

We want that pared down to:


7. 0 Miles
0. 13.112796264776 Miles
10. 27.724961215848 Miles

Or, do we want to see instead more like:


Boston, Massachusetts, US - 0 Miles
Ithaca, New York, United States - 13 Miles
Detroit, Michigan, us - 28 Miles

I'm pretty sure it's this last. But just let me know for clarity's sake.

And though it shouldn't affect the code required to get that far, bear in mind the other points about possibly needing to save these values somewhere and/or pass them on to another function. Let me know if either of those will be the case, and if so tell me as much as you can about that as you conceive it.

bluewalrus
12-14-2010, 04:35 AM
We will just need the 3 closest points.

So your


7. 0 Miles
0. 13 Miles
10. 28 Miles

is correct. EDIT: I'd prefer the decimals be rounded up.

I figure with the keys there (7, 0, 10) I can just pull the address from the videographer array with that, right? Thanks.

jscheuer1
12-14-2010, 05:11 AM
Yes, sort of. But what do you want the user to see?

Also the videographer array:


var videographer = [
['One', 42.4433333, -76.5, 1],
['Two', 33.7091847, -117.9536697, 2],
['Three', 34.0522342, -118.2436849, 3],
['FOur', 37.7749295, -122.4194155, 4],
['Five', 34.7303688, -86.5861037, 5],
['Six', 33.7489954, -84.3879824, 6],
['Seven', 52.5234051, 13.4113999, 7],
['eight', 42.3584308, -71.0597732, 8],
['Nine', 41.850033, -87.6500523, 9],
['ten', 39.9611755, -82.9987942, 10],
['eleven', 42.331427, -83.0457538, 11],
['twelve', 41.6005448, -93.6091064, 12]
];

contains no addresses. Looks like Long/Lat to me. I guess those could be considered addresses. If that's what your after, what for? What're the strings for? Why is the upper and lower case of those strings inconsistent?

Most importantly though, again:


What do you want the user to see?


What if anything do you want saved?


What if anything do you want passed to another function?

bluewalrus
12-14-2010, 05:58 AM
The videographer array is used for the initial points on the map they are plotted via the lat/lng. The String in the first column(?) of the videographer array will contain the videographers name and the fourth doesnt have a use yet I was just playing around with that one. The values in the first column(?) are just place holders right now so I figured anything was fine there.

I'd want the user to see the mileage (distanceArray[]), the location (end[]), and the name (videographer[]) of the shortest 3 distances.

Do you mean saved in JS variables or for later, I don't need any of the displayed data saved for later. For JS variables I think just the 3 of the 3 above .

After the calculations are complete and the outcome is displayed nothing needs to pass, not sure if that answers your question about passing from the functions.

jscheuer1
12-14-2010, 06:18 AM
I think I get it now. That fourth column (value may be the best term) in each videographer array (videographer is a multidimensional array) may come in handy as a sort of index once we cut it up, if we do.

Now you haven't said it yet that I can tell, but I'm thinking the map could then be updated to show only the three closest points. And I believe the map API may allow for the addition of some goodies - tooltips and extra features when clicked to those points. Also the starting point could maybe be marked with an X or something. But let's leave all that aside for now.

I'll play with getting the output into the desired format and get back to you on that when I have something viable.

jscheuer1
12-14-2010, 07:08 AM
Take this one out for a spin:


<!DOCTYPE html>
<html>
<head>
<title>Google Maps JavaScript API v3 Example: Event Closure</title>
<meta http-equiv="content-type" content="text/html; charset=utf-8"/>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<!-- <link rel="stylesheet" type="text/css" media="screen" href="videomap.css" />
-->
<base href="http://174.120.151.156/~crazychr/" />
<script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=false"></script>
<script type="text/javascript">
var map, directionDisplay, directionsService, stepDisplay, markerArray = [], distanceArray = [], TimeArray = [], end = [];
end[0] = "Ithaca, New York, US";
end[1] = "Fountain Valley, California, US";
end[2] = "Los Angeles, California, US";
end[3] = "San Francisco, California, US";
end[4] = "Huntsville, Alabama, US";
end[5] = "Atlanta, Georgia, US";
end[6] = "Berlin, Germany";
end[7] = "Boston, Massachusetts, US";
end[8] = "Chicago, Illinois, US";
end[9] = "Columbus, Ohio, US";
end[10] = "Detroit, Michigan, US";
end[11] = "Des Moines, Iowa, US";
function initialize() {
var myOptions = {
zoom: 10,
center: new google.maps.LatLng(0, 0),
mapTypeId: google.maps.MapTypeId.ROADMAP
}
var map = new google.maps.Map(
document.getElementById("map_canvas"), myOptions);
setMarkers(map, videographer);
directionsService = new google.maps.DirectionsService();
var rendererOptions = {
map: map
}
directionsDisplay = new google.maps.DirectionsRenderer(rendererOptions)
// Instantiate an info window to hold step text.
stepDisplay = new google.maps.InfoWindow();
var opt = document.createElement('option'), topt;
/* for(var i = 0; i < end.length; ++i){
topt = opt.cloneNode(false);
topt.value = end[i];
topt.appendChild(document.createTextNode(end[i]));
document.getElementById('new_address').appendChild(topt);
} */
}
var videographer = [
['One', 42.4433333, -76.5, 1],
['Two', 33.7091847, -117.9536697, 2],
['Three', 34.0522342, -118.2436849, 3],
['FOur', 37.7749295, -122.4194155, 4],
['Five', 34.7303688, -86.5861037, 5],
['Six', 33.7489954, -84.3879824, 6],
['Seven', 52.5234051, 13.4113999, 7],
['eight', 42.3584308, -71.0597732, 8],
['Nine', 41.850033, -87.6500523, 9],
['ten', 39.9611755, -82.9987942, 10],
['eleven', 42.331427, -83.0457538, 11],
['twelve', 41.6005448, -93.6091064, 12]
];
function setMarkers(map, locations) {
var bounds = new google.maps.LatLngBounds();
for (var i = 0; i < locations.length; i++) {
var videographer = locations[i], myLatLng = new google.maps.LatLng(videographer[1], videographer[2]), marker = new google.maps.Marker({
position: myLatLng,
map: map,
title: videographer[0]
});
bounds.extend(myLatLng);
map.fitBounds(bounds);
}
}
function calcRoute(a) {
var request = {
origin: document.getElementById('new_address').value,
destination: end[a],
travelMode: google.maps.DirectionsTravelMode.DRIVING
}, output = document.getElementById('output'), r = [];
if(a === 0){
output.innerHTML = '&nbsp;';
distanceArray = [];
}
directionsService.route(request, function(response, status){
if (response.status === 'OK'){
distanceArray[a] = [a, (response.routes[0].legs[0].distance.value * .000621371192)];
TimeArray[a] = response.routes[0].legs[0].duration.text;
} else {
distanceArray[a] = [a, 9999999];
TimeArray[a] = 'Never';
}
if(++a < end.length){
calcRoute(a);
} else {
distanceArray.sort(function(a, b){var x = +a[1], y = +b[1]; return x < y? -1 : x > y? 1 : 0;});
for (a = 0; a < 3; ++a) {
if (distanceArray[a]){
r .push([videographer[distanceArray[a][0]][0], '. ',
end[distanceArray[a][0]], ': ',
Math.ceil(distanceArray[a][1]), ' Miles'].join(''));
}
}
output.innerHTML = r.join('<br />\n');
}
});
}
function showSteps(directionResult) {
// For each step, place a marker, and add the text to the marker's
// info window. Also attach the marker to an array so we
// can keep track of it and remove it when calculating new
// routes.
var myRoute = directionResult.routes[0].legs[0];
for (var i = 0; i < myRoute.steps.length; i++) {
var marker = new google.maps.Marker({
position: myRoute.steps[i].start_point,
map: map
});
markerArray[i] = marker;
}
}
</script>
</head>
<body onload="initialize()">
<form style="width:300px; float:left; height:50px;" onsubmit="calcRoute(0); return false;">
<input type="text" name="new_address" id="new_address" />
<input type="submit" value="Find Videographer" />
</form>
<div id="output" style="background:#f77; width:300px; padding:0.5em; float:left;">&nbsp;</div>
<div id="map_canvas" style="width: 500px; height: 500px; float:left; border:3px #000000 solid; margin-left:20px;"></div>
<div id="warnings_panel"></div>
</body>
</html>

Note: No Math.min() required - I used a numerical sort.

bluewalrus
12-14-2010, 05:13 PM
Yup, that did it. Thanks, did you rewrite the mileage calculation as well I noticed it is correct now.

jscheuer1
12-14-2010, 05:28 PM
Yup, that did it. Thanks, did you rewrite the mileage calculation as well I noticed it is correct now.

Yes (changed duration to distance):


directionsService.route(request, function(response, status){
if (response.status === 'OK'){
distanceArray[a] = [a, (response.routes[0].legs[0].distance.value * .000621371192)];
TimeArray[a] = response.routes[0].legs[0].duration.text;
} else {
distanceArray[a] = [a, 9999999];
TimeArray[a] = 'Never';
}
if(++a < end.len . . .

You already had the correct multiplier for converting meters to miles. And I reformatted some of the entries in the end array so it would yield more consistent results layout and appearance wise as far as the place names in the output go.

vinaykant
02-08-2011, 08:46 AM
Hello Friends,

I am working on show direction using Google map API, There is a thing
for which I need help of you guys.

Let suppose there is a route between Point A and Point B displaying
using getdirection() method of Google Map API. which is generating
successfully.

Now there is a point / marker at particular location (lang/lat) and my
user want to check,is that point belongs to suggested route
direction ?
On map its showing it belongs or not , but I need to check this thing
using programing to use result in other method.

Please can any expert help in this?
Thanks & regards
Vinaykant