JavaScript Array of arrays: not defined elemnts - javascript

I've been developing a canvas application in javascript in which I need to define a 9 cell grid (3x3) and in each grid have a canvas element.
The thing is, I have already an array called grid which has the data to represent the size of each cell.
var grid = new Array();
grid[0] = {x:[0, elemWidth], y:[0, elemHeight]};
grid[1] = {x:[elemWidth, elemWidth*2], y:[0, elemHeight]};
grid[2] = {x:[(elemWidth*2), sWidth], y:[0, elemHeight]};
grid[3] = {x:[0, elemWidth], y:[elemHeight+1,elemHeight*2]};
grid[4] = {x:[elemWidth, elemWidth*2], y:[elemHeight, elemHeight*2]};
grid[5] = {x:[(elemWidth*2), sWidth], y:[elemHeight, elemHeight*2]};
grid[6] = {x:[0, elemWidth], y:[(elemHeight*2), sHeight]};
grid[7] = {x:[elemWidth, elemWidth*2], y:[(elemHeight*2), sHeight]};
grid[8] = {x:[(elemWidth*2), sWidth], y:[(elemHeight*2), sHeight]};
This produces the following output on Chrome Inspector:
As far as I can tell, I should be able to obtain the x and y values by using the following code
canvas[i].fillRect(grid[i].x[0], grid[i].y[0], grid[i].x[1], grid[i].y[1]);
canvas[i].strokeRect(grid[i].x[0], grid[i].y[0], grid[i].x[1], grid[i].y[1]);
and each should give me the corresponding values.
I can't understand why I can get everything OK when on canvas[0] (everything renders on the browser) but when it comes to the subsequent canvas[i](with i>0) won't render and I get an undefined value although the HTML produces the tags for each canvas element.
Am I doing anything wrong declaring the arrays?
EDIT
Made a few changes to the code just for the sake of simplicity and readability:
function createCanvas() {
/* criar grelha aqui */
var sWidth = window.innerWidth; //- 50;
var sHeight = window.innerHeight; //- 50;
var elemWidth = sWidth / 3;
var elemHeight = sHeight / 3;
var grid = new Array();
var row1 = [0, elemHeight];
var row2 = [elemHeight, elemHeight*2];
var row3 = [elemHeight*2, sHeight];
var col1 = [0, elemWidth];
var col2 = [elemWidth, elemWidth*2];
var col3 = [elemWidth*2, sWidth];
grid[0] = [col1, row1];
grid[1] = [col2, row1];
grid[2] = [col3, row1];
grid[3] = [col1, row2];
grid[4] = [col2, row2];
grid[5] = [col3, row2];
grid[6] = [col1, row3];
grid[7] = [col2, row3];
grid[8] = [col3, row3];
for (var i = 0; i < grid.length; i++) {
var c = document.getElementById('content');
var newCanvas = document.createElement('canvas');
newCanvas.setAttribute('id', 'canvas'+i);
c.appendChild(newCanvas);
canvas[i] = new Canvas('canvas'+i, 0, function() {});
canvas[i].clear();
canvas[i].setAutoResize(true);
canvas[i].canvasElement.width = elemWidth - 2;
canvas[i].canvasElement.height = elemHeight - 2;
canvas[i].fillStyle('#000000');
canvas[i].strokeStyle('#FFFFFF');
canvas[i].fillRect(grid[i][0], grid[i][0], grid[i][2], grid[i][3]);
canvas[i].strokeRect(grid[i][0], grid[i][0], grid[i][4], grid[i][5]);
This code is much more complete than the previous version which only had a little bit of the function
Meanwhile I managed to get 3 cells to render (although the 3 cell, which should be 1x3 is actually a 2x1 because somehow the rendering isn't happening properly, which I think might be a CSS problem)
EDIT2
Again I've made some changes to the code above. And new screenshot of the grid array expanded view.

Related

Unable to loop over table rows to animate respective progress bars

Ok, for brevity's sake, I'm just including the javascript code itself. If the HTML or CSS is really needed, I'll update the post.
The objective: I've got a table with rows (displaying tasks), and I have a progress bar to the right of each task showing how much time has elapsed.
The problem: only the first progress bar works. All subsequent progress bars just show a completely filled-up bar. Upon looking at the console log, the program isn't looping at all. It performs no calculations for any rows other than the first. I've tried moving various variables inside and outside the loop, but no cigar.
Please forgive me if the code looks terrible and/or the answer is obvious. This is essentially my first real javascript 'program.'
var Table = document.getElementsByTagName("table");
var Row = document.getElementsByTagName("tr");
var rowDisplay = document.getElementsByTagName("td");
function fillBar(timeElapsedPercent) {
for (i = 0; i < rowDisplay.length; i++) {
var eachRow = rowDisplay.item(i);
const interval = setInterval(() => {
// Grabbing the needed info from the cells
var taskName = rowDisplay[0].innerText;
var rawDeadline = rowDisplay[1].innerText;
var rawStartTime = rowDisplay[2].innerText;
var bar = document.querySelector('.bar');
//calculations for the progress bar
var now = new Date();
var startTime = new Date(rawStartTime.replace(/(am|pm)/, ''));
var deadline = new Date(rawDeadline.replace(/(am|pm)/, ''));
var timeTotal = Math.abs(deadline - startTime);
var timeTotalPercent = Math.abs(timeTotal / 60000);
console.log('value for total time in minutes of', taskName, 'is', timeTotalPercent);
var nowTillDeadline = Math.abs(deadline - now);
var nowTillDeadlinePercent = Math.abs(nowTillDeadline / 60000);
var timeElapsed = Math.abs(timeTotalPercent - nowTillDeadlinePercent);
var timeElapsedPercent = Math.abs((timeElapsed / timeTotalPercent) * 100);
// moving the progress bar
bar.style.width = timeElapsedPercent + '%';
if (timeElapsedPercent >= 99) {
bar.style.width = '100%';
clearInterval(interval);
}
}, (1*1000))
}
}
fillBar();
All right then, time to answer my own question again.
I'll include the HTML for the row, then the Javascript to manipulate it:
<td class="col-sm-4">
<div id="progressBarBackground">
<div class="bar" id="progressBar"></div>
</div>
</td>
function fillBar() {
const interval = setInterval(() => {
var i;
for (i = 1; i < Table.rows.length; i++) {
// grabbing relevant info from DOM
var taskName = Table.rows[i].cells[0].innerText;
var rawDeadline = Table.rows[i].cells[1].innerText;
var rawStartTime = Table.rows[i].cells[2].innerText;
var bar = Table.rows[i].cells[6].getElementsByClassName("bar").item(0);
// calculations for progress bar
var now = new Date();
var startTime = new Date(rawStartTime.replace(/(am|pm)/, ''));
var deadline = new Date(rawDeadline.replace(/(am|pm)/, ''));
var timeTotal = Math.abs(deadline - startTime);
var timeTotalPercent = Math.abs(timeTotal / 60000);
var nowTillDeadline = Math.abs(deadline - now);
var nowTillDeadlinePercent = Math.abs(nowTillDeadline / 60000);
var timeElapsed = Math.abs(timeTotalPercent - nowTillDeadlinePercent);
var timeElapsedPercent = Math.abs((timeElapsed / timeTotalPercent) * 100);
// manipulating the necessary DOM element
bar.style.width = timeElapsedPercent + '%';
if (timeElapsedPercent >= 99) {
bar.style.width = '100%';
clearInterval(interval);
}
}
}, (1*1000))
}
So my problems were as follows:
1) The for-loop needs to be inside the interval, not the other way around. I read somewhere that an interval is basically just a timed for-loop. That was a light bulb moment for me.
2) Using .querySelector() to get the progress bar only gets the first one, even if it's in the for-loop; to get the progress bar for each row, the .getElementsByClassName() method was needed in addition to the .item() method with its index position, which you would never know from the error code you get if you leave it out. Since I only had one element within the cell to get, its index position is 0.
3) At the start of my for-loop, I changed from displayRows.length to Table.rows.length, but in order to do that, I had to change the way I defined var Table. Instead of .getElementsByTagName(), I used get .getElementById() -- for my fellow noobs, note it's just one Element, not Elements.
I think those were the three main issues. There were probably other minor issues, but I tried about 100 different things between now and when I first posted the problem, so it's hard to know.
I also made use of console.log at various points while I was troubleshooting everything. I deleted those lines here for the sake of code neatness, but they were immensely helpful.

javascript check if element rect hitting another with same class

I want to put like 30 of <img class="anger"> elements with random size and random position inside the <div> container, but none of the .anger hitting one another.
Is it possible?
This is my code so far:
function loadAngers() {
var wrp = '#angerContainer'; //the container
var rectAvatar = $('#picAvatar')[0].getBoundingClientRect(); //rect of user avatar
var rectWrapper = $(wrp)[0].getBoundingClientRect(); //rect of container
listCoorditaes = [[
rectAvatar.width,
(rectAvatar.left+rectAvatar.right)/2,
(rectAvatar.top+rectAvatar.bottom)/2
]];
$(wrp).find('.anger').remove();
for (var i=0; i<listAnger.length; i++) {
var verb = listAnger[i].replace('assets/img/verb/','').replace('.png','').replace('-',' ');
var anger = $('<img src="'+listAnger[i]+'" class="anger hvr-'+getRandom(listAnim)+'" data-verb="'+verb+'" style="position:absolute">');
var paddingX = 100;
var paddingY = 200;
var wideX = rectWrapper.width - paddingX;
var wideY = rectWrapper.height - paddingY - rectAvatar.top;
var width = Math.round(30 + Math.random() * 70);
var left;
var top;
var x;
var y;
var tubrukan;
var coba = 0;
do { //find the best coordinate
tubrukan = false;
coba++;
x = Math.round(Math.random() * wideX) + paddingX/2;
y = Math.round(Math.random() * wideY) + paddingY/2 + rectAvatar.top;
left = x - width/2;
top = y - width/2;
for (var j=0; j<=i; j++) {
var cekW = listCoorditaes[j][0];
var cekX = listCoorditaes[j][1];
var cekY = listCoorditaes[j][2];
var difX = Math.abs( x - cekX );
var difY = Math.abs( y - cekY );
if (difX < cekW && difY < cekW) {
tubrukan = true;
break;
}
}
}
while(tubrukan && coba<3); //as I give up for eternal loop, I limit the loop with 3 tries.
listCoorditaes.push([width,x,y]);
anger.css('width',width+'px');
anger.css('left',left);
anger.css('top',top);
anger.appendTo(wrp);
}
}
This is the current result:
As we can see, the elements still overlap the other because I limit the loop. If I remove the limit, browser will endure endless loop and become not responding.
Do you have another better way to achieve it?
UPDATE:
My bad, I set the container height only 800px, that's why it can't contain all those <img> without overlapping, thus eternal loop happen. I made it to 2000px to see if it works. But the problem is still takes uncertain number of loops to find the best coordinate, so I still put limit to the loop thus overlap still happen several times.

HTML Canvas putImageData causing frame overlap

I am trying to read pixels (frame by frame) from websocket and render it on to canvas (in grayscale). Data is being displayed properly, just that pixels of the current frame are displayed overlapped on previous frame. Thus picture gets smudged after few frames.
I am tying to clear out the previous frame before rendering current one. What would be the proper way to do it?
I am using putImageData() to render the frame. I have tried clearRect() before calling putImageData(). and have tried clearing Imgdata (Imgdata.data = [];) array before populating it again but none of these things worked.
` var canvas = document.querySelector("canvas");
var context = canvas.getContext("2d");
var Imgdata = context.createImageData(100,100);
var numPixel = Imgdata.data.length/4;
ws.onmessage = function (event) {
var bytes = new Uint8Array(event.data);
console.log("data: " + numPixel + " bytes: "+ bytes.length);
//Imgdata.data = [];
for (var i = 0; i < numPixel; i++) {
Imgdata.data[(i*4)+Math.round(bytes[i]/85)] = (bytes[i]%85)*3;
Imgdata.data[(i*4)+3] = 255;
Imgdata.data[(i*4)+0] = bytes[i];
Imgdata.data[(i*4)+1] = bytes[i];
Imgdata.data[(i*4)+2] = bytes[i];
Imgdata.data[(i*4)+3] = 255;
}
//context.clearRect(0, 0, canvas.width, canvas.height);
context.putImageData(Imgdata,0,0);
};
`
I would say the cause is most likely due to the first line inside the for loop, without knowing the data i dont know what it does but id does not look right.
// ???
Imgdata.data[(i*4)+Math.round(bytes[i]/85)] = (bytes[i]%85)*3;
If the data is random then this would randomly set one of the colour channels of each pixel.
Apart from that I can not see any errors that would cause what you describe.
I have rewritten the code only as a suggestion to improve the performance a little.
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
const imgdata = context.createImageData(100,100);
const pix = imgdata.data;
pix.fill(255); // set all to 255 To cover the alpha channel
const numPixel = pix.length; // best leave as byte count
ws.onmessage = function (event) {
const inData = event.data;
var inIndex = 0;
var i = 0;
while(i < numPixel){
pix[i ++] = pix[i ++] = pix[i ++] = inData[inIndex ++];
i++;
}
context.putImageData(imgdata,0,0);
};
That should work event if the incoming data is incomplete the function putImageData completely replaces the pixels. If any pixels are undefined from the socket data they will be set to zero and will show up as black.

How can I get EaselJS's MouseEvent to work properly? It SEEMS to work, but it keeps returning back a single bitmap ID, not the correct

I'm writing a mini-game in EaselJS that requires mouse clicks on a grid of tiles.
However, it appears that it's only partially working - or perhaps not assigning a unique Event to each bitmap. During creation, I assign a simple ID - a number counting up per iteration, and expect to get that back.... but no matter where I click, out of 49 objects on stage (hexagon tiles), it only reports back 48....every time. I have enabled stage.enableMouseOver(20), which I initially forgot, but it did not help.
function BuildGround()
{
var i = 0;
for (var x = 0; x < 7; x++)
{
for (var y = 0; y < 7; y++)
{
var h = 102;
var s = h/Math.cos(30*Math.PI/180)/2;
var tempTile = new createjs.Sprite(Tiles, 0);
WorldContainer.addChild(tempTile);
tempTile.regX = 64;
tempTile.regY = 64;
tempTile.id = i;
tempTile.x = x * s * 1.5;
tempTile.y = y * h + (x % 2) * h / 2;
tempTile.addEventListener("click", function(event) { alert(tempTile.id); })
TileArray.push(tempTile);
i++;
console.log(i);
}
}
WorldContainer.x = 155;
WorldContainer.y = 150;
}
My guess, you are experiencing context problem of JavaScript, try this:
tempTile.addEventListener("click", function(event) { alert(event.target.id); })
All events objects have a target element, usually the one which triggered it.

Programmatically determine the height of a div element

I'm trying to get the height of a div, then position it based on the height. I've read various articles on this, but I always seem to be getting NaN as a result. Yes the javascript is loaded at the end of the body, after the divs are drawn.
I'm using asp.net to create this javascript dynamically. What I have output so far is:
var resultsDiv = document.getElementById('resultsDiv');
var resultsInnerDiv = document.getElementById('resultsInnerDiv');
resultsInnerDiv.innerHTML = "test";
var h = parseInt(resultsInnerDiv.style.offsetHeight);
alert(parseInt(resultsInnerDiv.style.offsetHeight));
resultsInnerDiv.style.top = ((h / 2) -125) + 'px';
I need to get the actual height, instead of NaN. NaN pixels is obviously not valid.
I think this what you need:
var resultsDiv = document.getElementById('resultsDiv');
var resultsInnerDiv = document.getElementById('resultsInnerDiv');
resultsInnerDiv.innerHTML = "test";
var h = parseInt(resultsInnerDiv.offsetHeight);
alert(parseInt(resultsInnerDiv.offsetHeight));
resultsInnerDiv.style.top = ((h / 2) -125) + 'px';
offsetHeight is not a property of element.style, but the element itself (see here).
Try this:
var resultsDiv = document.getElementById('resultsDiv');
var resultsInnerDiv = document.getElementById('resultsInnerDiv');
resultsInnerDiv.innerHTML = "test";
var h = parseInt(resultsInnerDiv.offsetHeight);
alert(h);
resultsInnerDiv.style.top = ((h / 2) -125) + 'px';

Categories

Resources