Grid offset by one - javascript

Ok, so I've been trying to get a grid to work on my canvas. Here's what I've got:
codepen link
for (var j = 0; j < rows; j++) {
for (var i = 0; i < cols; i++) {
var pix = new Pixel(i, j);
grid.push(pix);
}
}
Now, the problem is that on the grid array, the pixel on index 0 is actually the 2nd one and the last is the 1st. I want to change that but I can't see what the problem in the code is.

Take a look at your Pixel#draw() function:
this.draw = function () {
rect(this.x, this.y, l, l);
fill(0);
stroke(20);
if (this.on)
fill(255);
}
Read this code line by line and really think about exactly what it's doing. Step through it with a piece of paper and a pencil to understand exactly what's going on.
Notice that you're calling the rect() function first, and then you're setting the fill and stroke.
This will cause each square to have the color of the previous cell. So it's not that your first Pixel is located in the second square, it's that the second Pixel is drawing itself based on the color of the first Pixel. The same is true for the first Pixel drawing itself based on the color of the last Pixel.
To fix your problem, just set the stroke and fill before you call the rect() function.
Side note: you also probably want to get into the habit of using { } curly brackets for every if statement, even one-liners like this:
if(this.one){
fill(255);
}
This isn't causing any problems in your code yet, but it's a good habit to get into.

Related

How do I change a variable while using a function?

I'm coding on the p5.js Website Editor
So I'm trying to make a lot of rectangles that move when I press a specific key.
To make that I thought of making a function where I would put everything related to the rectangles moving, so that I don't have to rewrite a code to make them move every time. I want all of them to move the same way.
This is what I tried
function wall(x, y, sx, sy){
rect(x, y, sx, sy);
if(keyIsDown(65)){
return x+1;
}
}
wall(300, 300, 20, 30);
and just got a rectangle in the right coordinates but not moving when I press the "a" key
When you want to move things in p5.js, you need to use the draw() function. The draw() function runs the code inside of it repeatedly multiple times a second. You can use that to create an illusion of movement by updating the location of your object by a small amount every frame and then re-rendering the object.
I don't see you using the draw() function, so I'm guessing this is the first part of your problem.
The second part I see is that you are referring to "a lot of rectangles", but you are only making one.
Consider the code below for a quick solution (copy-paste it into the p5.js editor to see it in action).
let wallX = 200;
let wallY = 100;
let wallSpeed = 2;
let wallWidth = 20;
let wallHeight = 30;
function setup() {
createCanvas(400, 400);
}
function draw() {
background(220);
if (keyIsDown(LEFT_ARROW)) {
wallX = wallX - wallSpeed;
} else if (keyIsDown(RIGHT_ARROW)) {
wallX = wallX + wallSpeed;
}
if (keyIsDown(UP_ARROW)) {
wallY = wallY - wallSpeed;
} else if (keyIsDown(DOWN_ARROW)) {
wallY = wallY + wallSpeed;
}
wall(wallX, wallY, wallWidth, wallHeight);
}
function wall(x, y, sx, sy) {
for (let i = 0; i < 5; i++){
rect(x, y + sy * i, sx, sy);
}
}
In this code snippet, I am defining some global variables (generally not a good practice, but for the purposes of a p5.js sketch this is fine). The important ones are the wallX and the wallY variables. These variables are defined outside of the draw() function, so they will not be reset every time the loop runs.
Inside the loop, there are key handlers defined (I used the arrow keys for clarity). If the arrow keys are pressed, the position of the wall will change by the wallSpeed value per frame.
Also, note the background(220) call - this redraws the grey background at the beginning of the loop. If you remove that, the results of the previous renders will be visible, chances are that you don't want that.
Finally, the wall() function. You can see that the key press handling is not done inside of it - it needs the state information to come from the outside. All this function does is use a loop to draw five rectangles in a stack, at the position it is given. When the position changes, it redraws the wall in a different place on the canvas. The rectangles all refer to the root x and y values, so they will all move together as a unit.
Another way would be to create the class to represent a Wall and make instances of that class and call methods on those instances, but that could be something to revisit once you gain more experience with p5.js.
Hope this helps!

P5.js object not leaving a trail

I have a project in which I'm trying to make a helix effect, where two ellipses rotate around each other, and they leave a trail which keeps going downwards and then disappearing. now the problem is, I cant get the trail to show up. I followed a tutorial by the coding train on making a trail, and while it works for him, it doesn't for me. one thing that I did differently from him is that he was using a classes for his ball, while I'm not.
My trail code's like this. It takes in a array I made called history, which contains a 2d vector containing the x and y positions, and it should be making a copy of the ellipse every frame, but instead it just makes a new ellipse and erases the last one.
function makeTrail(){
history.push(pos1);
for (var i = 0; i < history.length; i++){
let p = history[i];
ellipse(p.x, p.y, 8, 8);
}
}
and here's my draw function if it helps. Most of it's just code for where I want the balls to be drawn. The MoveBall functions just tell the program what to do with the balls.
function draw(){
pos1.y += -1;
pos2.y += -1;
let rs = 30/*random(10, 30)*/;
fill('#f42069');
ellipse(pos1.x, pos1.y, rs, rs);
moveBall();
fill('#b4da22');
ellipse(pos2.x, pos2.y, rs, rs);
moveBall2();
makeTrail();
}
The problem is that you're pushing pos1 into history, when you should be pushing pos1.copy(). When you push the vector itself, the value in the list changes with the value of pos1.

Canvas won't draw rectangle after for loop in function

I'm trying to create a news ticker that renders text in little square "pixels". I say "pixels" because they look like pixels but the actual squares being displayed are bigger than just 1px.
So far I can get all the letters rendered from an object that I built which contains the pixel coordinates for each rectangle. Code can be seen here:
https://jsfiddle.net/9u3ez6gu/2/
The letters render correctly, but after my for loop (see code sample below) I'm trying to create a lime colored space between each letter. This lime space never gets rendered no matter what I do. Here is the for loop and the code I'm using to render the space. Does anyone know why canvas will not let me draw the lime colored rectangle?
for (i = 0; i <= inv[letter].length; i++) {
var x = inv[letter][i][1] * full;
var y = inv[letter][i][0] * full;
context.beginPath();
context.rect(x, y, unit, unit);
context.fillStyle = 'black';
context.closePath();
context.fill();
}// End for loop
//Add a gap between letters
var gapx = full * 5;
context.beginPath();
context.rect(gapx, 0, full, full);
context.fillStyle = 'lime';
context.closePath();
context.fill();
}// End function
Your for loop goes one iteration too far:
for (i = 0; i <= inv[letter].length; i++) {
Should be <, not <=. Keep your developer console open!
Also, i should be declared with var, either at the top of the function or in the for loop header itself. In this case it (probably) doesn't matter, but it's good to get in the habit. If you don't declare the variable, it'll be global. If another of your functions also fails to declare another i, they'll be the same thing, and weird bugs can result.
If you put
"use strict";
at the top of your <script> blocks or the very top of each function, the parser (in modern browsers) will flag assignments to implicit global variables as errors.

Html5 canvas graph fill on hover

I'm drawing a graph on a html 5 canvas tag from a array with numbers like
arr = [6,3,16,6,53,1,3,54,67,6,3,21,6,49,7,8,31,66,51,32,56,49,4,78,9,65,43,1,3,54,67,6,3];
These numbers will be the height of the rectangle that is drawn on the canvas and it will be filled white with a transparent background;
for (var i = 0; i < arr.length; i += 1) {
ctx.fillStyle = "#ffffff";
// Fill rectangle with gradient
ctx.fillRect(
arr[i] * 10,
c_height - arr[i],
8,
arr[i]
);
}
Users can hover these rectangles and then see some more data.
I can make them change color but if there are to many rectangles the site laggs a little bit, so my question is if it is possible to make some kind of big horizontal rectangle that will mask(white rectangles) without filling the transparent background?
1) You can define the array as a typed array instead:
var arr = new Uint8Array([6,3,16,6,53,1,3,...,3]);
Just make sure the type (here unsigned 8-bit) fits the values. If you have higher values than 255 then use a 16-bit, or 32-bit, if floating point use Float32Array and so on.
2) If the color is the same don't set the fill style inside the loop. fillStyle is rather expensive as it has to parse the string and convert it to the color it defines.
3) use path to add the rectangle to, defining and filling each time is slower than to define all rects, then fill all at the same time outside the loop.
4) use a smarter for-loop by using the array entry as a conditional statement as well. Not only is this faster in itself but by storing the array entry to a value will be faster too as JS does not have to look up an array entry every time you use arr[i]:
ctx.fillStyle = "#ffffff"; // set fill style outside loop
ctx.beginPath(); // make sure we use a clean path
for (var i = 0, a; a = arr[i]; i++) { // fetch item and use as cond. for loop
ctx.rect(a * 10, c_height - a, 8, a); // add rect to path, but not fill yet
}
ctx.fill(); // fill all rects with fillstyle
Hope this helps!

loading very slowly all colors in htmll5 canvas

i am trying to make a color tools.so I i tried to show the colors in a canvas.But the problem is,it is loading very slowly.here is my code
var l=0
var ctx = document.getElementById('color').getContext('2d');
for (var i=0;i<125;i++){
for (var j=0;j<124;j++){
for(var k=0;k<125;k++){
ctx.fillStyle = 'rgb(' +i*2+ ',' +j*2 + ','+k*2+')';
l=i+k;
ctx.fillRect(l*1,j*1,1,1);
}
}
}
i have tested it firefox and crome.Both shows the same behaviour.Please help me.thanks in advance.
First of all, your algorithm is basically wrong. You are calculating the colors in a 3d space, (i j k) and maping that on a 2d space (l, j).
Every value for the l variable is calculated several times and only the last one is visible (i=0 k=100 -> l=100 ; 1=1 k=99 > l=100; i=2 k=98 > l=100 ...
You should decide beforehand what colors go where, and have only 2 loops and not 3 (Probably the most usual decision here is going to a hsl space, omitting l and doing the loops on h and s.
The other big improvement would be to set pixels directly and do not use fillrect. Something in the line of:
var imgData=ctx.createImageData (125,125);
accesing pixels
ctx.putImageData(imgData,0,0);
You should have picture already precalculated (as one of the comments suggest) and then only read the position from this picture. From that you could reverse engineer your color in RGB.

Categories

Resources