Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

110
Views
Marking pixel on a canvas

I'm building an application around a 1000x1000 canvas, where you can select areas of the canvas by dragging the mouse around. In order to remember the area selected from the user I save the coordinates in an array and I draw them with imageData:

    const applySelectedPixelLayer = useCallback(() => {
        const canvas = canvasRef.current;
        if (!canvas) return;
        const ctx = canvas.getContext("2d");
        const imageData = ctx.createImageData(1, 1);

        imageData.data[0] = 0; // R value
        imageData.data[1] = 0; // G value
        imageData.data[2] = 0; // B value
        imageData.data[3] = 255; // A value

        for (let i = 0; i < selectedCoordinates.length; i++) {
            ctx.putImageData(
                imageData,
                selectedCoordinates[i][0],
                selectedCoordinates[i][1]
            );
        }
    }, [selectedCoordinates]);

Basically the user can click pixel on the canvas or drag the mouse to select a rectangle of pixels. When the user releases the mouse pointer, I add the coordinates selected to selectedCoordinates and then I call the applySelectedPixelLayer function to update the canvas.

The problem is that it's incredibly slow, it takes 20/30 seconds to see the result if a lot of pixels are selected.

Is there a more effective way to mark the selected pixel on a canvas?

about 4 years ago · Juan Pablo Isaza
1 answers
Answer question

0

Like mentioned in the comments, you should try to work with larger areas of image data in one go.

Here's an example that lets you cut out a part of some random image.

  • Store drag start
  • Store drag end
  • Use getImageData to get the selected pixels from the canvas,
  • or (see section after return statement in snippet below), use coordinates to modify existing pixel data

const cvs = document.createElement("canvas");
cvs.width = cvs.height = 512;
const ctx = cvs.getContext("2d");

let imageData = null;
let offset = [];
let dragStart = null;
let dragPos = null;
let copied = null;

// Generate some image
const init = () => {
  const size = cvs.width / 8;
  
  for (let i = 0; i < 64; i += 1) {
    const y = Math.floor(i / 8);
    const x = i % 8;
    
    ctx.fillStyle = `hsl(${Math.random() * 255} 100% 50%)`;
    ctx.fillRect(x * size, y * size, size, size);
  }
  
  imageData = ctx.getImageData(0, 0, cvs.width, cvs.height);
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  
  draw();
}

const draw = () => {
  ctx.clearRect(0, 0, cvs.width, cvs.height);
  ctx.putImageData(imageData, 0, 0);
  
  if (dragStart && dragPos) {
    const [ x1, y1 ] = dragStart;
    const [ x2, y2 ] = dragPos;
  
    ctx.fillStyle = "rgba(255,255,255,0.9)";
    ctx.strokeStyle = "rgba(255, 255, 255)";
    ctx.lineWieght = 2;
    ctx.fillRect(x1, y1, x2 - x1, y2 - y1);
    ctx.strokeRect(x1, y1, x2 - x1, y2 - y1);
  }
}

const onMove = e => {
  const [ dx, dy ] = offset;
  
  dragPos = [
    e.clientX - dx,
    e.clientY - dy
  ];
  
  draw();
}

const onSelectionEnd = e => {
  const [ x1, y1 ] = dragStart;
  const [ x2, y2 ] = dragPos;
  
  dragStart = null;
  dragPos = null;
  
  
  // A) To get the image you selected, you can do:
  draw();
  const selection = ctx.getImageData(
    Math.min(x1, x2),
    Math.min(y1, y2),
    Math.abs(x1 - x2),
    Math.abs(y1 - y2)
  );

  imageData = selection;
  return;
  
  // B) To clear the pixels from the original image, you could do something like:  
  for (let y = Math.min(y1, y2); y < Math.max(y1, y2); y += 1) {
    for (let x = Math.min(x1, x2); x < Math.max(x1, x2); x += 1) {
      const pi = y * cvs.width * 4 + x * 4;
      
      imageData.data[pi + 0] = 255;
      imageData.data[pi + 1] = 255;
      imageData.data[pi + 2] = 255;
      imageData.data[pi + 3] = 255;
    }
  }
  

}

cvs.addEventListener("mousedown", e => {
  const { top, left } = cvs.getBoundingClientRect();
  offset = [ top, left ];

  onMove(e);
  dragStart = dragPos;
  
  cvs.addEventListener("mousemove", onMove);
  window.addEventListener("mouseup", onSelectionEnd, { once: true });
});


init();
document.body.appendChild(cvs);

about 4 years ago · Juan Pablo Isaza Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!