Cant set origin for an element in JavaScript - javascript

I am making a simple game in js which consists of a grid and some cells
This is what it currently looks like and it works perfectly. The thing is that while making this I set the margin to 0 but I
would like to move the canvas to center. To do that, I got the margin from this function
var test = document.querySelector('.test');
var left_margin = window.getComputedStyle(test).getPropertyValue("margin-
left "); // returns margin e.g. '655px'
left_margin = left_margin.match(/\d+/);
Then I made some changes in the whole thing to account for this offset but for some reason when I try to add the offset to the x-axis, it returns NaN. To make sure there wasnt some problem I performed some basic mathematical operations on this value and they worked. Can someone tell me what is going on with this? and also, is there a simple way to just redefine the origin for an element(a canvas in my case), to avoid this hassle?
Edit:
I dont understand this. When i simply do var a = blockWidth + 0;The game doesnt start and then do console.log(a) this also return NaN. and i get**(Uncaught TypeError: Cannot set property 'strokeStyle' of undefined)**
function grid(){
var a = blockWidth + left_margin;
var b = blockHeight;
while (a != widthWin){
drawLine(a, 0, a, heightWin, 1, 'gray');
a += blockWidth;
}
while (b != heightWin){
drawLine(left_margin, b, widthWin+left_margin, b, 1, 'gray');
b += blockHeight;
}
}

What you get with
left_margin = left_margin.match(/\d+/);
is an array ["655"] not an int as you are assuming.
Therefore, you need to access its first element and parse it to a number before using it for doing any math:
left_margin = parseInt(left_margin.match(/\d+/)[0]);

Related

Identifying edge cases of a one-dimensional array in Javascript

I'm creating a 2-dimensional heat map which has functionality when you click on any pixel. It grabs data associated with the index of every pixel (including adjacent pixels) and plots it. It currently looks like this:
The problem that I'm encountering is when I click on a left or right edge pixel, since it grabs data from adjacent pixels, it can retrieve data from the opposite side of the graph since it is all within a one-dimensional array. I am trying to create a conditional which checks if the clicked pixel is an edge case, and then configures the magnified graph accordingly to not show points from the other side of the main graph. This is the code I have so far:
// pushes all dataMagnified arrays left and right of i to magMainStore
var dataGrabber = function(indexGrabbed, arrayPushed) {
// iterates through all 5 pixels being selected
for (var b = -2; b <= 2; b++) {
var divValue = toString(i / cropLength + b);
// checks if selected index exists, and if it is not in the prior row, or if it is equal to zero
if (dataMagnified[indexGrabbed + b] != undefined && (& divValue.indexOf(".")!=-1)) {
dataMagnified[indexGrabbed + b].forEach(function(z) {
arrayPushed.push(z);
})
}
}
};
I am trying to get the same result as if I had a two dimensional array, and finding when the adjacent values within a single array is undefined. This is the line where I'm creating a conditional for that
if (dataMagnified[indexGrabbed + b] != undefined && (& divValue.indexOf(".")!=-1)) {
The second condition after the and is my attempts so far trying to figure this out. I'm unsure if I can even do this within a for loop that iterates 5 times or if I have to create multiple conditions for this. In addition, here's an image displaying what I'm trying to do:
Thank you!
Your approach looks overly complex and will perform rather slowly. For example, converting numbers to strings to be able to use .indexOf() to find a decimal point just for the sake of checking for integer numbers doesn't seem right.
A much simpler and more elegant solution might be the following function which will return the selection range bounded by the limits of the row:
function getBoundedSelection(indexGrabbed, selectionWidth) {
return dataMagnified.slice(
Math.max(Math.floor(indexGrabbed/cropLength) * cropLength, indexGrabbed - selectionWidth),
Math.min(rowStartIndex + cropLength, indexGrabbed + selectionWidth)
);
}
Here, to keep it as flexible as possible, selectionWidth determines the width of the selected range to either side of indexGrabbed. This would be 2 in your case.
As an explanation of what this does, I have broken it down:
function getBoundedSelection(indexGrabbed, selectionWidth) {
// Calculate the row indexGrabbed is on.
var row = Math.floor(indexGrabbed/cropLength);
// Determine the first index on that row.
var rowStartIndex = row * cropLength;
// Get the start index of the selection range or the start of the row,
// whatever is larger.
var selStartIndex = Math.max(rowStartIndex, indexGrabbed - selectionWidth);
// Determine the last index on that row
var rowEndIndex = rowStartIndex + cropLength;
// Get the end index of the selection range or the end of the row,
//whatever is smaller.
var selEndIndex = Math.min(rowEndIndex, indexGrabbed + selectionWidth);
// Return the slice bounded by the row's limits.
return dataMagnified.slice(selStartIndex, selEndIndex);
}
So I discovered that since the results of the clicked position would create a variable start and end position in the for loop, the only way to do this was as follows:
I started the same; all the code is nested in one function:
var dataGrabber = function(indexGrabbed, arrayPushed) {
I then create a second function that takes a start and end point as arguments, then passes them as the for loop starting point and ending condition:
var magnifyCondition = function (start, end) {
for (var b = start; b <= end; b++) {
if (dataMagnified[indexGrabbed + b] != undefined) {
dataMagnified[indexGrabbed + b].forEach(function (z) {
arrayPushed.push(z);
})
}
}
};
After that, I created 5 independent conditional statements since the start and end points can't be easily iterated through:
if (((indexGrabbed - 1) / cropLength).toString().indexOf(".") == -1) {
magnifyCondition(-1, 2);
}
else if ((indexGrabbed / cropLength).toString().indexOf(".") == -1) {
magnifyCondition(0, 2);
}
else if (((indexGrabbed + 1) / cropLength).toString().indexOf(".") == -1) {
magnifyCondition(-2, 0);
}
else if (((indexGrabbed + 2) / cropLength).toString().indexOf(".") == -1) {
magnifyCondition(-2, 1);
}
else {
magnifyCondition(-2, 2);
}
};
Lastly, I pass the index grabbed (i of the on clicked function) and an arbitrary array where the values get stored.
dataGrabber(i, magMainStore);
If there's a better way instead of the if statements, please let me know and I'd be happy to organize it better in the future!

in gamequery; how would I move an object "slowly" from its "dropped" location to where it needs to go?

I am not trying to get it to follow a set path since the path is variable. but I am trying to set the object to fall in a noticable pattern from where Idrop it.
$(".gQ_sprite").mouseup(function() {
//test condition to see if collides with a box etc...
collision1 = $("#" + currentClickedDivId).collision(".gQ_group, .box");
if(collision1.length > 0)
{
//irrelevent
}
else
{
//figure out yarnball Id...
i = wordLength - 1
yarnBallIdNumber = currentClickedDivId.charAt(10);
yarnBallPositionFromStart = i - yarnBallIdNumber
initialMovedYarnBallXPosition = yarnBallPositionFromStart * yarnSpacing
initialMovedYarnBallXPosition = initialXYarnPosition - initialMovedYarnBallXPosition
$("#" + currentClickedDivId).xy(initialMovedYarnBallXPosition ,yarnYPosition);
}
right now my code simply flashes the object back to its location after the user releases it, and I am trying to move it back "slowly" if you will and can't think of the best way to do it.
so far my thoughts are to use a loop and subtract (or add) the location of the object with delay, but there may be a better way to move the object that I don't know about.
any ideas?
What you could do is to use jQuery to animate something else than a CSS property, like explained there: https://coderwall.com/p/fn2ysa
In your case to make your sprite move from currentX to destinationX in one second you code would look like:
var from = {x: currentX};
var to = {x: destinationX};
$(from).animate(to,{duration: 1000, step: function(step){
$(mySprite).x(step);
}});

Prevent touching corners (JS Game)

How can I prevent this map generator from creating touching corners like this:
-X
X-
Or
X-
-X
Here is a simplified example of the generator: http://jsfiddle.net/fDv9C/2/
Your question answers itself, almost.
Here's the fiddle: http://jsfiddle.net/qBJVY/
if (!!grid[y][x] && !!grid[y+1][x+1] && !grid[y+1][x] && !grid[y][x+1]) {
good=false;
grid[y+1][x]=2;
}
It simply checks for the combinations you do not want and patches them up. It always adds a grid point so as not to disconnect any parts of the map.
This in turn may lead to another situation where the issue may occur, but if it changed anything (that is, if it found a problem), it will simply check again. This can be optimized, for instance by recursively adjusting whatever was changed, but usually it only needs 1 or 2 passes. There's a limiter on there to not allow more than 100 passes, just in case there is some unforeseen circumstance in which it cannot fix it (I can't think of such a situation, though :) ).
Because of the way that you are creating board it's very difficulty to do this checking during generation. I create simple function that check board after. It's using flood algorithm. Here is the fiddle http://jsfiddle.net/jzTEX/8/ (blue background is original map, red background is map after checking)
Basically we create second array grid2. After filling grid we run recursively floodV function
function floodV(x,y) {
var shiftArray = [[0,1],[0,-1],[1,0],[-1,0]];
grid2[y][x]=1;
for(var k=0;k<4;k++) {
var x1=x+shiftArray[k][0];
var y1=y+shiftArray[k][1];
if(grid[y1][x1] == 1 && grid2[y1][x1] == 0 && checkV(x1,y1)) {
grid2[y1][x1] = 1;
floodV(x1,y1);
}
}
}
with the check function
function checkV(x,y) {
var checkVarr = [[-1,-1], [-1,1], [1,1], [1,-1]];
for(var k=0;k<4;k++) {
if(grid[y+checkVarr[k][0]][x+checkVarr[k][1]] == 1 && grid[y+checkVarr[k][0]][x] == 0 && grid[y][x+checkVarr[k][1]] == 0 && grid2[y+checkVarr[k][0]][x+checkVarr[k][1]] == 1)
return false;
}
return true;
}
This isn't perfect because we can sometimes throw away big parts of the map but if we try to start adding new elements we have to check whole map again (in worths case).
This is what I did: http://jsfiddle.net/fDv9C/13/
Where's the magic happening? Scroll down to lines 53 through 58:
var bottom = y_next + 1;
var left = x_next - 1;
var right = x_next + 1;
var top = y_next - 1;
if (grid[top][left] || grid[top][right] ||
grid[bottom][left] || grid[bottom][right]) continue;
In short your touching corner points can only occur at the computed next position. Hence if any one of the four corner neighbors of the next position exists, you must compute another next position.
You may even decrement the counter i when this happens to get as many paths as possible (although it doesn't really make a big difference):
var bottom = y_next + 1;
var left = x_next - 1;
var right = x_next + 1;
var top = y_next - 1;
if (grid[top][left] || grid[top][right] ||
grid[bottom][left] || grid[bottom][right]) {
i--;
continue;
}
See the demo here: http://jsfiddle.net/fDv9C/12/
Edit: I couldn't resist. I had to create an automatic map generator so that I needn't keep clicking run: http://jsfiddle.net/fDv9C/14/

Can I use a concatenated var+array_value as a selector in jquery i.e $("#var+array_value")

This might be really obvious, but I'll be honest, I'm not any kind of developer. Just someone trying to get something to work for customers of the company I work for.
I've got an array defined in JS, and I'd like to be able to use a for loop to run a section of code on each of the items in the array.
If I run the code individually (i.e. not in the loop), I know it works. As soon as try to put it in a loop, it fails. I'm hoping somebody here can tell me what I'm doing wrong, and why it is wrong, and how I can do it right. (I'd like to be able to understand what/why I'm doing things, as its always better to know these things, in my opinion).
The JS/JQuery code I've got (that works) is;
var a = document.getElementById('roomthumb_2236');
var d = $("#chosenrate_2236").offset();
if ($('#chosenrate_2236').length) {
a.style.visibility='visible';
$("#roomthumb_2236").css({
top: d.top -9 + "px",
left: d.left + 560 + "px",
})
};
This works fine (I know there is a mashup of JS and JQuery, I can standardise it later).
I've tried so many variations of the 'for' loop, but it just doesn't seem to want to work. Here is the most up-to-date version of my 'for' code;
var rooms_array = [2236, 2235]
var reposition = function (){
document.getElementById('hidden_stuff').style.display="none";
for (var i = 0; i < rooms_array.length; i++) {
var a = "roomthumb_"+rooms_array[i];
var b = "chosenrate_"+rooms_array[i];
var c = "chosenrate_"+rooms_array[i].offset()
if ($(b).length) {
$(a).css({
visibility:"visible",
top: c.top -9 + "px",
left: c.left + 560 + "px",
})
};
};
};
What the code should be doing (if its not clear) is;
set the array (this is a dynamically created list of id's from a database)
hide a div "hiddenstuff" (this works fine)
then for each id from the array;
create a variable 'roomthumb_xxxx' (where xxxx is the id from the array) called a
create a variable 'chosenrate_xxxx' (where xxxx is the id from the array) called b
check to see if an element exists with an ID that matches variable b, and if it does then edit the css properties of the element with the ID of variable a
The var c should get the position of var b (if I'm right), to allow me to position the element with the ID of var a relative to it...
I've no idea why the code fails inside of the loop. I always seem to get null errors or it thinks var b is undefined?
My guess is that I can't take a string (chosenrate_), add an array string to it and then use that result as an ID. If I use alert(a) or alert(b) I do get the ID's I need, but I can't work out how to use that in a $("#ID") for example...
I think I've explained everything. If I've missed anything I'll try to explain it better.
You can try
var a = "#roomthumb_"+rooms_array[i]; // put # sign for id selector
var b = "#chosenrate_"+rooms_array[i];
var c = $("#chosenrate_"+rooms_array[i]).offset();
you can also write var c as:
var c = $(b).offset(); // where var b = "#chosenrate_"+rooms_array[i];
instead of what you're currently trying.
As you're trying to point to id so you need # at begin.
I think something similar to this code will do the job for you:
// Your array with data.
var rooms_array = [2235, 2236, 2237, 2238];
var reposition = function (){
// Hide whatever you need to hide.
$('#hidden_stuff').attr('display', "none");
// This is a jQuery function to iterate over arrays.
$.each(rooms_array, function(key,value){
// Create your "a" variable
var a = '#roomthumb_'+value; // roomthumb_2235 ; roomthumb_2236 ...
var b = '#chosenrate_'+value; // chosenrate_2235 ; chosenrate_2236 ...
// If b exists...
if ($(b).length) {
var c = $(b).offset(); // get the offset of "b"
$(a).css({
visibility:"visible",
top: c.top -9 + "px",
left: c.left + 560 + "px"
})
}
// if "b" doesn't exist
else {
// edit the css properties of the element with the ID of variable "a"
}
});
};
You're right, you can concatenate strings to make jQuery selectors. After a quick look I can see that the problem is probably the value of c. Also, you're missing the hashes from the beginnings of the selectors. Replace this:
var c = $("chosenrate_" + rooms_array[i]).offset()
with:
var a = "#roomthumb_" + rooms_array[i];
var b = "#chosenrate_" + rooms_array[i];
var c = $("#chosenrate_" + rooms_array[i]).offset()
You are doing a wrong thing in writing your selector.
As per your question $(“#var+array_value”) This should be $(“#"+var+array_value)

JSON corrupted attributes

I'm having difficulties understanding behavior of Javascript.
Code:
function getPosition(element){
var position = {
x:$(".line div").has(element).index(),
y:$(".line").has(element).index()
};
console.log(position.y);
console.log(position)
return position;
}
Now while calling it from function I'm getting results like this:
0
Object
x: 8
y: 3
What I don't understand is how is it possible to change object attributes when trying to access it via object reference, but not directly.
But when I call same function from console I get this:
0
Object
x: 8
y: 0
This is the same element passed to function. And it seems that it fails always when X or Y is 0(zero), when it's another number it's ok.
Could anyone explain what I'm doing wrong? Or is it somekind of JS bug? O_o
EDIT:
So I finally found out what the problem was. I always thought that I was passing values but unfortunately I was wrong all the time. During some searches on stackoverflow, I found topic about JS values and references.
If anyone is interested and too lazy to read the topic, you can look at this example. It's pretty much self explanatory.
function test(){
var a = 5;
var b = a; //b now has value of 5
console.log("a:"+a+":b:"+b);
b = 4;//a still has value of 5 and b is assinged to 4
console.log("a:"+a+":b:"+b);
var c = {val:1};
var d = c; //d now has reference to c
d.val = 2; //c.val changes because it is a reference
console.log(c);
}
EDIT2:
oh and by the way, how can I mark my question as answered?
console.log delays converting values to string until the application slows down so that logging doesn't slow down the application unnecessarily.
If the console.log(position) is showing a value that is different from that at the time console.log was called its because the position has been modified between the call and the time the console widget decided to format the value for display.
You can see this by trying the following HTML:
<script>
// Emits the JSON form when converted to a string.
var obj = {
x: 1,
toString: function () {
return JSON.stringify(this);
}
};
console.log(obj); // Often {x:2}
console.log("" + obj); // Reliably {x:1}
obj.x = 2;
</script>
Look for code that does something like
obj = getPosition(...);
...
obj.y = <expression that evaluates to zero>
Alternatively, you can force eager formatting by changing
console.log(position)
to
console.log("" + position)
So I finally found out what the problem was. I always thought that I was passing values but unfortunately I was wrong all the time. During some searches on stackoverflow, I found topic about JS values and references.
If anyone is interested and too lazy to read the topic, you can look at this example. It's pretty much self explanatory.
function test(){
var a = 5;
var b = a; //b now has value of 5
console.log("a:"+a+":b:"+b);
b = 4;//a still has value of 5 and b is assinged to 4
console.log("a:"+a+":b:"+b);
var c = {val:1};
var d = c; //d now has reference to c
d.val = 2; //c.val changes because it is a reference
console.log(c);
}

Categories