I made a project called "pixel paint" by javascript with p5js library, but when I run it, that project ran too slow. I don't know why and how to make it run faster. And here is my code:
let h = 40, w = 64;
let checkbox;
let scl = 10;
let painting = new Array(h);
let brush = [0, 0, 0];
for(let i = 0; i < h; i++) {
painting[i] = new Array(w);
for(let j = 0; j < w; j++) {
painting[i][j] = [255, 255, 255];
}
}
function setup() {
createCanvas(w * scl, h * scl);
checkbox = createCheckbox('Show gird line', true);
checkbox.changed(onChange);
}
function draw() {
background(220);
for(let y = 0; y < h; y++) {
for(let x = 0; x < w; x++) {
fill(painting[y][x]);
rect(x * scl, y * scl, scl, scl);
}
}
if(mouseIsPressed) {
paint();
}
}
function onChange() {
if (checkbox.checked()) {
stroke(0);
} else {
noStroke();
}
}
function paint() {
if(mouseX < w * scl && mouseY < h * scl) {
let x = floor(mouseX / scl);
let y = floor(mouseY / scl);
painting[y][x] = brush;
}
}
<!--Include-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
Is there a solution to make my project run faster?
The code you have is easy to read.
It might not be worth optimising at this stage as it would make the code potentially needlessly more complex/harder to read and change in the future.
If you want to learn about different ways you could achieve the same thing I can provide a few ideas, though, for your particular use case int terms of performance might won't make a huge difference:
painting
as a nested [w][h]
array you could use a flat [w * h]
array and use a single for
loop instead of a nested for loop. This would be somewhat similar to using pixels[]
. (You can convert x,y to an index (index = x + (y * width)
) and the other way around(x = index % width, y = floor(index / width)
)p5.Image
, access pixels[]
to draw into it and render using image()
(ideally you'd get lower level access to the WebGL renderer to enable antialiasing if it's supported by the browser). The grid itself could be a texture()
for a quad where you'd use vertex()
to specify not only x,y geometry positions, but also u, v texture coordinates in tandem with textureWrap(REPEAT)
. (I posted an older repeat Processing example: the logic is the same and syntax is almost identical)p5.Image
idea, you can cache the drawing using createGraphics()
: e.g. only update the p5.Graphics
instance when the mouse is dragged, otherwise render the cached drawing. Additionally you can make use of noLoop()
/loop()
to control when p5's canvas gets updated (e.g. loop()
on mousePressed()
, updated graphics on mouseMoved()
, noLoop()
on mouseReleased()
)There are probably other methods too.
While it's good to be aware of techniques to optimise your code, I strongly recommend not optimising until you need to; and when you do use a profiler (DevTools has that) to focus only the bits are the slowest and not waste time and code readability on part of code where optimisation wouldn't really make an impact.