I am having an issue running a bit of javascript I have made (converted from existing Google python code) to define a zoom level based on latitude and longitude values of a rectangle in a google map. I am currently having an issue with the output of a couple variables.. I have attached an image showing the variables in question and their outputs using the console.log() command.
As you can see the bottom_left and top_right variables differ from their assignments bounds[0] and bounds[1] respectively. I'm sure that I am doing something wrong here in this function, as the output is different from what I mean to assign the variables as. I was also wondering why there is a problem when using console.log(bottom_left) or console.log(top_right) in the console? Is it because these variables aren't globally defined?
Overall, the code fails to run properly as it outputs the maximum Zoom no matter what Lat / Long values are inputted (Theoretically the zoom level should get smaller and smaller with the increase in Lat / Long extents).
Below is the entire code from the sample:
//Define initial variables
var southWestLat = 10;
var southWestLng = -180;
var northEastLat = 60;
var northEastLng = -50;
var bounds = new Array ();
bounds[0] = new Array (southWestLat,southWestLng);
bounds[1] = new Array (northEastLat,northEastLng)
//------------------------------------
//------------------------------------
//------------------------------------
//Point constructor
function Point(x, y) {
this.x = x;
this.y = y;
}
//------------------------------------
//------------------------------------
//------------------------------------
function CalcWrapWidth(zoom) {
return pixel_range[zoom]
}
//------------------------------------
//------------------------------------
//------------------------------------
function range(lowEnd,highEnd){
var arr = [],
c = highEnd - lowEnd + 1;
while ( c-- ) {
arr[c] = highEnd--
}
return arr;
}
//------------------------------------
//------------------------------------
//------------------------------------
function Bound(value,opt_min,opt_max) {
if (opt_min != null) {
value = Math.max(value,opt_min);
}
if (opt_max != null) {
value = Math.min(value,opt_max);
}
return value;
}
//------------------------------------
//------------------------------------
//------------------------------------
//Converts from degrees to radians
function DegToRad(deg) {
return deg*(Math.pi/180);
}
//------------------------------------
//------------------------------------
//------------------------------------
//Gets center bounds, bounds as ['lat','lng']
function GetCenter(bounds) {
var center_lat = (bounds[1][0] + bounds[0][0])/2;
var center_lng = (bounds[0][1] + bounds[1][1])/2;
var center = new Array ();
center[0] = center_lat;
center[1] = center_lng;
return center;
}
//------------------------------------
//------------------------------------
//------------------------------------
//Prepare the calculation...
var pixels_per_lon_deg = new Array ();
var pixels_per_lon_rad = new Array ();
var pixel_origo = new Array ();
var pixel_range = new Array ();
var pixels = 640;
var zoom_levels = [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18];
var pointObj = new Array ();
var origin;
function prime() {
for (i in zoom_levels) {
origin = pixels/2;
pixels_per_lon_deg.push(pixels/360);
pixels_per_lon_rad.push(pixels/(2*Math.pi));
pixel_origo.push({x:origin,y:origin});
pixel_range.push(pixels);
pixels = pixels*2;
}
}
//------------------------------------
//------------------------------------
//------------------------------------
//Convert from Lat Lng to pixel
function FromLatLngToPixel(lat_lng, zoom) {
o=pixel_origo[zoom];
x_cord=Math.round(o.x+lat_lng[1]*pixels_per_lon_deg[zoom]);
siny=Bound(Math.sin(DegToRad(lat_lng[0])),-0.9999,0.9999);
y_cord=Math.round(o.y+0.5*Math.log((1+siny) / (1-siny))*-pixels_per_lon_rad[zoom]);
pointObj = ({x:x_cord,y:y_cord}); //Potential error here?
return pointObj
}
//------------------------------------
//------------------------------------
//------------------------------------
/**Main function bounds: A list of length 2, each holding a list of length 2. It holds
the southwest and northeast lat/lng bounds of a map. It should look
like this: [[southwestLat, southwestLng], [northeastLat, northeastLng]]**/
function CalculateBoundsZoomLevel(bounds) {
var zmax=18;
var zmin=0;
var bottom_left=bounds[0];
var top_right=bounds[1];
var backwards_range=range(zmin,zmax).reverse();
var lng_dsc = Math.abs(bounds[0][1] - bounds[1][1]);
var lat_dsc = Math.abs(bounds[0][0] - bounds[1][0]);
var rrun = lat_dsc/lng_dsc;
var runr = lng_dsc/lat_dsc;
var vs_height;
var vs_length;
console.log(bottom_left) //Delete
console.log(top_right) //Delete
if (rrun<1) {
vs_height = 640*rrun;
vs_length = 640;
} else {
vs_height = 640;
vs_length = 640*runr;
}
var view_size = new Array (vs_length,vs_height);
for (z in backwards_range) {
var bottom_left_pixel=FromLatLngToPixel(bottom_left,z);
var top_right_pixel=FromLatLngToPixel(top_right,z);
if (bottom_left_pixel.x > top_right_pixel.x) {
bottom_left_pixel.x -= CalcWrapWidth(z);
}
if (Math.abs(top_right_pixel.x - bottom_left_pixel.x) <= view_size[0] && Math.abs(top_right_pixel.y - bottom_left_pixel.y) <= view_size[1]) {
return z
}
}
return 0
}
//------------------------------------
//------------------------------------
//------------------------------------
//Run function
prime()
CalculateBoundsZoomLevel([southWestLat,southWestLng],[northEastLat,northEastLng])
console.log(z)
As always any help is greatly appreciated. Thanks!
Simple you are passing in two arguments to a function that expects one.
function CalculateBoundsZoomLevel(bounds) {
^^^^^^
CalculateBoundsZoomLevel([southWestLat,southWestLng],[northEastLat,northEastLng])
^^^^^^^^^^^^^^^^^^^^^^^^^^^
I assume you wanted it to be a 2D array
CalculateBoundsZoomLevel([[southWestLat,southWestLng],[northEastLat,northEastLng]])
You have the function defined as:
function CalculateBoundsZoomLevel(bounds) {
So inside the function, the variable bounds is the first argument from the call
CalculateBoundsZoomLevel([southWestLat,southWestLng],[northEastLat,northEastLng])
So bounds[0] == southWestLat and bounds[1] == southWestLng. This isn't the same as when you use console.log(bounds[0]) in the console. Then it's using the global variables that were defined with:
var bounds = new Array ();
bounds[0] = new Array (southWestLat,southWestLng);
bounds[1] = new Array (northEastLat,northEastLng)
The global bounds array is a 2-dimensional array, but inside the function it's just a 1-dimensional array.
You should use:
CalculateBoundsZoomLevel(bounds)
to use the same array inside the function as outside.
Related
What I am trying to achieve is send a list of zip codes from my JavaScript function that gets a range based on the distance and zip code that the user enters. Once I get my list of zip codes, send the list to my angular controller.
Originally, the scope below would grab the zip code that was entered by the user from the form (see below):
$scope.GetCurrentZip = function (){
try{
$http.get("../remote/ReturnZipCodes.cfm")
.then(function(response){
$scope.searchParam.Zip = response.data;
})
}
else{ console.log('No geolocation'); }
}
catch(err) { console.log(err.message); }
}
I would like to use the same scope that I have above. However, instead of grabbing the value that was entered by the user, I would like to grab the list that I obtain from the function instead.
The following is the JavaScript function that generates the list of zip codes:
var rad = function(x) {
return x * Math.PI / 180;
};
var getDistance = function(p1, p2) {
var R = 6378137; // Earth’s mean radius in meter
var dLat = rad(p2.lat - p1.lat);
var dLong = rad(p2.lon - p1.lon);
var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(rad(p1.lat)) * Math.cos(rad(p2.lat)) * Math.sin(dLong / 2) * Math.sin(dLong / 2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
var d = R * c;
return d; // returns the distance in meter
};
function getZipCodes() {
var miles = document.getElementById("miles").options[document.getElementById("miles").selectedIndex].innerHTML;
var zip = document.getElementById("zip").value;
if (typeof zip === 'undefined' || typeof miles === 'undefined' || !zip.length || !miles.length) return false;
var zips = getZips();
var zip_list = "";
if (zips.length) {
// var list_item = "";
// for (i=0;i<zips.length;i++) {
// console.log(zips[i]);
// }
zip_list = zips.join();
}
return zip_list;
}
function getZips() {
var zipcode1 = getZipInfo(zip);
var res = [];
if (typeof zipcode1 === "undefined") return false;
for (i=0; i<zipinfo.length; i++) {
var zipcode2 = zipinfo[i];
var distance = getDistance(zipcode1, zipcode2);
//Convert meters into miles
distance = distance/1609.344;
if (distance <= miles) {
res.push(zipcode2.zip);
}
}
return res;
}
function getZipInfo(zip) {
for (i=0; i<zipinfo.length; i++) {
if (zipinfo[i].zip == zip) return zipinfo[i];
}
}
Any help would be appreciated.
Update: As stated by #charlietfl, I was not clear with what I was asking in my question and I do apologize for any confusion.
What I was asking is I would like to retrieve the list of zip codes that was generated in my JavaScript function GetZips().
As suggested by #charlietfl (thanks for your help once more), all I needed to do is the following:
$scope.GetCurrentZip = function (){
try{
$scope.Zip = getZips();
}
catch(err) {}
}
Update: #LSD pointed out that it will not pass do to the values passing in are not in a array. Is it possible to change the scope to accept the list? The list is a string.
Below code of angular will give you the hiden value
var hidenctl = angular.element(document.querySelector('#hidenid'));
var hidenvalue = hidenctl.val();
I am struggling to understand how variables are referenced and stay alive in Javascript. In the following I have two types of object, a Note and an IntervalBuilder which takes a Note and creates
a second Note.
function Note() {
this.key = 1 + Math.floor( Math.random() * 13); // from 1 to 13 inclusive
this.setKey = function setKey(i) { key = i; };
this.getKey = function getKey() { return this.key; } ; // {return key} is a ReferenceError!!
}
function IntervalBuilder() {
this.setPerfectFifth = function setPerfectFifth(root) {
this.fifth = new Note();
console.log("this.fifth: " + this.fifth);
this.y = root.key;
console.log("root.key: " + root.key );
console.log("y: " + this.y );
this.fifth.setKey( this.y + 4 );
return this.fifth;
};
}
With the above I can now do this:
var x = new Note();
var ib = new IntervalBuilder();
ib.setPerfectFifth(x);
However, the instance ib now has a member named fifth! What I was hoping for was that I could assign the return value (a Note) from setPerfectFifth to a variable and let fifth vanish. How is that done?
Many thanks for any help, I find lots of this very confusing.
Gerard
Since you titled your quesion variable visibility in javascript what is basically going on is: In this.fifth = new Note(); the keyword this references the instance (the ib of var ib = new ...). So you attach your newly created Note to the instance. In JavaScript, as long as a variable can be reached starting with the global Object (window, when you think of a graph), it won't get garbage-collected away.
What you want is: var fith = new Note(), which will create a local variable which will get freed as soon as the function execution ends. Clearly, every usage of this.fifth then has to be replaced by just fith.
I do not know exactly what you want to achieve, but I think you want the following code structure:
// ==============================
// NOTE "CLASS"
// ==============================
var Note = (function () {
// Constructor
function Note() {
this._key = 1 + Math.floor( Math.random() * 13);
}
// Getter
Note.prototype.getKey = function () {
return this._key;
};
// Setter
Note.prototype.setKey = function (i) {
this._key = i;
};
return Note;
})();
// ==============================
// INTERVAL BUILDER "CLASS"
// ==============================
var IntervalBuilder = (function () {
// Constructor
function IntervalBuilder() {}
// Private members
var fifth = null,
y = 0;
// Setter
IntervalBuilder.prototype.setPerfectFifth = function (root) {
fifth = new Note();
y = root.getKey();
fifth.setKey(y + 4);
return fifth;
};
return IntervalBuilder;
})();
// ==============================
// CLIENT CODE
// ==============================
var x = new Note(),
ib = new IntervalBuilder();
ib.setPerfectFifth(x);
Sorry for the newb question here, but Im new to javascript. Ideally I would like to call for myLoop(latLong); but unless I make the variables outside of the function, I can't seem to have .setPosition() recognize the variable.
var x = 0;
var y = 0;
var z = 0;
var v = 0;
function xy(a,b,c,d) {
var longDistance = Math.abs(a-d);
var longTime = longDistance/0.1*0.5;
var latDistance = b-c;
var latRate = latDistance/longTime*0.5;
x = a; //origin long
y = b; //oringin lat
z = latRate;
w = d; //destination long
v = c; //destination lat
}
function myLoop () {
setTimeout(function () {
var latLong = new google.maps.LatLng(y,x);
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
myLoop();
} else {
alert('finished');
}
}, 0.5)
}
xy(-118,33,40,-73);
myLoop();
You simply need to pass the latLong variable into the myLoop() function recursively.
To do this, you can create your first latLong variable outside of the function, then call the function (passing in the first latLong variable), then within the latLong function, check for your conditions, and if you need to call the myLoop function again, update the latLong variable and then call the myLoop function again.
Here is what your recursive code would look like:
var x = 0;
var y = 0;
var z = 0;
var v = 0;
// Your first latLong
var latLong = new google.maps.LatLng(y,x);
function xy(a,b,c,d) {
// ...
}
// Pass in the latLong variable
function myLoop (latLong) {
setTimeout(function () {
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
// now create a new latLong, and pass it
// back into this function recursively
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
} else {
alert('finished');
}
}, 0.5)
}
xy(-118,33,40,-73);
// Now call the myLoop function to get the recursion started
myLoop(latLong);
Alternatively, you can wrap all the code up into one function
Using the revealing module pattern, you can wrap up all your loop functionality in one place (within a function object called latLongGenerator), allowing for a nice separation in your code logic, but still giving you a clean interface to use. The restructured "revealing module" code would look like this:
var latLongGenerator = (function () {
var x = 0;
var y = 0;
var z = 0;
var v = 0;
var latLong;
function setXY(a,b,c,d) {
var longDistance = Math.abs(a-d);
var longTime = longDistance/0.1*0.5;
var latDistance = b-c;
var latRate = latDistance/longTime*0.5;
x = a; //origin long
y = b; //oringin lat
z = latRate;
w = d; //destination long
v = c; //destination lat
// pass in the initial latLong to myLoop(latLong) from here
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
}
// This is the only function that will
// be exposed publicly on this function
// Example usage: latLongGenerator.startLoopWith(0,0,0,0);
function startLoopWith(a,b,c,d){
setXY(a,b,c,d);
}
function myLoop (latLong) {
setTimeout(function () {
marker.setPosition(latLong);
x = x + 0.1;
y = y - z;
if (x < w && y < v) {
// recursively call the loop from here
latLong = new google.maps.LatLng(y,x);
myLoop(latLong);
} else {
alert('finished');
}
}, 0.5);
}
return {
startLoopWith:startLoopWith
};
})();
// Finally, you can start your loop by passing in
// your initial values to latLongGenerator.startLoopWith(...)
latLongGenerator.startLoopWith(-118,33,40,-73);
This structure gives you a clean way of encapsulating all your calculation logic, while also giving you a nice, clean entry point. Using this new refactor, you can get your loop started with one line:
latLongGenerator.startLoopWith(-118,33,40,-73);
I haven't tested this code, but it should help you get on the right track.
Hope this helps!
Simple question which seems impossible for me because I'm just staring in the code.
Basicly I have this function, I call it X amount of times and it should put all the created divs in a array called world which I've declared outside of the function.
However, if I try to use one of these values they are "undefined".
var world = [];
function newTile(x, y, size, rotX, rotY, rotZ, tranX, tranY, tranZ, color) {
var tile = document.createElement('div');
tile.className = "tile";
tile.style.width = size+"px";
tile.style.height = size+"px";
tile.style.webkitTransform =
"rotateX("+rotX+"deg)"+
"rotateY("+rotY+"deg)"+
"rotateZ("+rotZ+"deg)"+
"translateX("+tranX+"px)"+
"translateY("+tranY+"px)"+
"translateZ("+tranZ+"px)";
tile.style.transform =
"rotateX("+rotX+"deg)"+
"rotateY("+rotY+"deg)"+
"rotateZ("+rotZ+"deg)"+
"translateX("+tranX+"px)"+
"translateY("+tranY+"px)"+
"translateZ("+tranZ+"px)";
if (x == 0 && y == 0) {
color="rgba(255,255,0,0.5)";
pathStart = tile;
pathCur = tile;
}
tile.style.backgroundColor = color;
tile.data = {
x:x,
y:y,
blacklist:0
}
tile.onclick = function() {
worldOri(null,null,null, -this.data.x*128 - 64, null, -this.data.y*128 - 64);
};
if (debug) tile.textContent = x+", "+y;
document.getElementById('world').appendChild(tile);
world[x] = [];
world[x][y] = tile;
}
Lets say I do something like:
newTile(2,6,128,90,0,0,2*128,0,6*128, "rgba(255,125,0,0.5)");
This works as intended and surely creates a div, placing it "in" another div with the id "world" and SHOULD add the div to the array "world" at [2][6]. If I now try to do something with the div, for example change color:
world[2][6].style.backgroundColor = "rgba(255,0,0,0.5)";
It returns as undefined, which I assume is that the actual adding to the "world" array didn't work, please help.
world[x] = []; will assign an empty array world[x] every time you make a call to newTile, thus "removing" all existing tiles from world[x]. Only initialize it if it doesn't exist yet:
world[x] = world[x] || [];
I am currently working on making a multiplayer Snake game in HTML5 Canvas with Javascript.
The code below is function that handles the random placement of food for the snake. The problem with the piece of code is that it give me the x and y in while(map[x][y]); back as something he can not read even though it does generate a random number.
This is the exact error:
"Uncaught TypeError: Cannot read property '20' of undefined"
The '20' is the random generated number (and will be the grid position of the food in a two dimensional array) and changes every time I restart the program or refresh the webpage. Can someone explain what I need the change in order to define x and y and place my food?
function rand_food(){
var x, y;
do {
x = MR() * this.rect_w|0;
y = MR() * this.rect_h|0;
}
while (map[x][y]); <-- Here is the error
map[x][y] = 1;
this.ctx.strokeRect(x * 10+1, y * 10+1, 8, 8);
}
Here is another code snippet which defines the map.
this.map = [];
// Map positions
//*
for (i = 0; i < this.rect_w; i++){
map[i] = [];
}//*/
After trying Sean's suggestion my code now looks like this: But it still gives me same error. Any other suggestion?
function SnakeGame(){
this.map = [];
for (i = 0; i < this.rect_w; i++){
this.map[i] = [];
}
function rand_food(){
var x, y;
console.log("Map length: " + this.map.length);
do {
x = MR() * this.rect_w|0;
y = MR() * this.rect_h|0;
console.log("x: " + x);
console.log("y: " + y);
}
while (this.map[x][y]);
this.map[x][y] = 1;
this.ctx.strokeRect(x * 10+1, y * 10+1, 8, 8);
}
this.map and map are not the same thing.
If you are inside an object then this.map is a public variable of the object, and map is a local variable.
Try something like this:
this.map = [];
// Map positions
for (var i = 0; i < 10; i++){
this.map[i] = [];
}
and in the rand_food function also use this.map.
Here are two possible ways you can go:
//using public variable
function SnakeGame() {
this.map = [];
// Map positions
for (var i = 0; i < 10; i++){
this.map[i] = [];
}
function rand_food() {
// refer to this.map here
this.map[0];
}
};
// using local variable
function SnakeGame() {
var map = [];
// Map positions
for (var i = 0; i < 10; i++){
map[i] = [];
}
function rand_food() {
// refer to map here
map[0];
}
};
If map was not defined you would normally get a ReferenceError, so map is defined but probably:
not assigned to anything
defined/assigned after beeing used
hoisted by beeing defined in a condition that do not execute
example
if (0) {
var foo = 1;
}
console.log(foo) //= undefined
console.log(foo[20]) // TypeError…
console.log(bar) // ReferenceError…