Passing arguments down to nested functions Google Maps v3 - javascript

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!

Related

JavaScript how to transform String into a function

I am doing a calculator for definite integrals, where I can add the function to integrate by using this interface.Calculator interface
The point is that once I call the function to integrate it recognizes it as a String and i cannot calculate over it. But if I add the function hardcoding it, it works perfectly fine.
prueba() {
//**** this.cadena is the function I add by using the interface
var sal = this.cadena;
console.log(sal);
var f = function (x) {
//**** The comented return works perfecly fine
//return 1/x;
return parseFloat(sal);
};
var integrada = this.integ(sal, 1, 2);
this.cadena = integrada;
this.imprime();
}
integ(f, a, b) {
var area = 0;
var dx = 0.001;
for (let x = a; x < b; x += dx) {
area += dx * f(x);
}
return area;
}
Can you try below line
var integrada = this.integ(parseFloat(sal), 1, 2);

I couldnt call a value from other function

The js code has 3 functions. I want to call values from the 2 functions and execute them in the 3rd function.
function first() {
var x = 2
var y = 3
var z = x * y
}
first()
function second() {
first();
var z;
var a = z - 1
}
second()
function third() {
first();
second();
var a
var z
var ans = a * z
console.log(ans);
document.getElementById("ans_html").innerHTML = precision(ans);
}
third()
<div id="ans_html"></div>
The expected outcome was 30.
But the output was "NaN".
In most languages, including JS, variables have "scope" (mdn). If you want to share data between function's, you can either
1) return values (mdn),
function first() {
var x = 2
var y = 3
return x * y;
}
function second() {
let z = first();
return z - 1
}
function third() {
let z = first();
let a = second();
var ans = a * z
console.log(ans);
}
third();
2), less conventionally, modify a param obj since they're are passed by ref.
let func = param => {
param.x = 3;
param.y = 4;
};
let a = {};
func(a);
console.log(a);
You will need to either create global variables which is considered a bad practice, or pass values around as parameters.
Global variables:
var a
var x
var y
var z
function first() {
x = 2
y = 3
z = x * y
}
function second() {
a = z - 1
}
function third() {
first()
second()
let ans = a * z
console.log(ans);
}
Passing Parameters:
function first(x, y) {
return x * y
}
function second(z) {
return z - 1
}
function third() {
let x = 2
let y = 3
let z = first(x, y)
let a = second(z)
let ans = a * z
console.log(ans);
}
Judging based on your code, you likely should take a look into how JavaScript scopes variables based on using the keyword var vs let. I hope this helps!
You have two major issues:
Your variables a and z are not global variables. They are defined within the function itself so you cannot access those variables outside of that scope (see this)
I would not fix your code to adhere to the first issue. You don't need global variables here, you just need to return the result so you can call your functions later. In the long run, I would assume you want to add arguments to your functions, but the below is an example of how to do what you're trying to accomplish by simply returning the result in your functions.
NOTE I don't know if you have a custom precision function or what. So, I added an empty function that just returns the input. You can probably remove this.
function precision(num) {
// Insert whatever is in your precision function here...
return num;
}
function first() {
var x = 2
var y = 3
var z = x * y
return z;
}
function second() {
var z = first();
var a = z - 1
return a;
}
function third() {
var a = second();
var z = first();
var ans = a * z
console.log(ans);
document.getElementById("ans_html").innerHTML = precision(ans);
}
third()
<div id="ans_html"></div>
This is not the best design pattern, but if you want to achieve this in this way, the code is going to look like the one below. You need to return the result of the function in order to get it in another function and use it.
function first() {
var x = 2
var y = 3
return x * y
}
function second() {
var z = first()
return z - 1
}
function third() {
var a = first()
var z = second()
var ans = a * z
console.log(ans);
// document.getElementById("ans_html").innerHTML = precision(ans);
}
third()
<div id="ans_html"></div>

JS Console Variable Output Issue

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.

Javascript requiring a dummy call to "this" to work

I have a mighty strange JavaScript problem. I have made an object oriented maze generator, which works well, but only if I call "this" (or the alias "self") right before the generator.
See code below:
// Constructor for a maze
function Maze(mazeWidth, mazeHeight) {
// Always working reference to this
var self = this;
// Has the maze been generated?
var generated = false;
// Default dimensions
var width = 20;
var height = 20;
// Check if dimensions are given
if (!isNaN(mazeWidth) && mazeWidth >= 1) {
width = parseInt(mazeWidth);
}
if (!isNaN(mazeHeight) && mazeHeight >= 1) {
height = parseInt(mazeHeight);
}
// The maze itself
var maze = {};
// Populate the maze
for (var y = 0; y < height; y++) {
maze[y] = {};
for (var x = 0; x < width; x++) {
maze[y][x] = new MazeCell(x, y);
}
}
// Function to get a cell
this.getCell = function(x, y) {
return maze[y][x];
}
// For some mighty strange reason "self" (or "this") needs to be called here for the code below to work
self;
// Generate the maze
(function generateMaze() {
// Map directions to its reverse
var directionMap = {};
directionMap[Maze.prototype.N] = Maze.prototype.S;
directionMap[Maze.prototype.E] = Maze.prototype.W;
directionMap[Maze.prototype.S] = Maze.prototype.N;
directionMap[Maze.prototype.W] = Maze.prototype.E;
// Depth-first search to generate the maze
(function DFS(cell, entryDirection) {
// Set the cell as discovered and open the entry direction
cell._setDiscovered();
cell._open(entryDirection);
// Find the neighbour cells
var neighbours = {};
neighbours[Maze.prototype.N] = cell.getNeighbourCell(Maze.prototype.N);
neighbours[Maze.prototype.E] = cell.getNeighbourCell(Maze.prototype.E);
neighbours[Maze.prototype.S] = cell.getNeighbourCell(Maze.prototype.S);
neighbours[Maze.prototype.W] = cell.getNeighbourCell(Maze.prototype.W);
// Check the neighbour cells in random order
for (var i = 0; i < 4; i++) {
var direction = (function() {
var result;
var count = 0;
for (var direction in neighbours) {
if (Math.random() < 1/++count)
result = direction;
}
return result;
})();
var nextCell = neighbours[direction];
delete neighbours[direction];
if (nextCell == false)
continue;
if (nextCell._isDiscovered())
continue;
// Set exit opening of this cell
cell._open(direction);
// Process next cell
DFS(nextCell, directionMap[direction]);
}
})(self.getCell(Math.floor(Math.random()*width), Math.floor(Math.random()*height)), null); // This line is the problem
})();
// ......
If I don't call "self" above the generation code, this.getCell will be called, but the first parameter will be a reference to the generateMaze-function itself. The second parameter will be unset.
It also work if I change the dummy line from "self" to "this".
Just writing "self" (or "this") on an otherwise empty line doesn't really do anything, does it? Why is it needed?
You should add semicolons after assigning a value to an attribute or variable, even if the value is a function, like here:
// Function to get a cell
this.getCell = function(x, y) {
return maze[y][x];
}
It should look like this:
// Function to get a cell
this.getCell = function(x, y) {
return maze[y][x];
};
I think that might be the cause of your problem.

Uncaught TypeError while generating a random position for the food in a HTML5 snake game

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…

Categories