HTML Preparation code:
AخA
 
1
<canvas id="canvas" width="800" height="300"></canvas>
Script Preparation code:
x
 
// Create the canvas that the pixels will be drawn to:
$canvas = document.getElementById('canvas');
$context = $canvas.getContext('2d');
$context.clearRect(0, 0, 800, 300);
// Use that canvas to generate a 1px by 1px ImageData instance:
$onePixel = $context.createImageData(1, 1);
$onePixelData = $onePixel.data;
// Create 10,000 test pixels:
$pixels = [];
for (let i=0; i<10000; ++i) {
  const pixel = {
    x: Math.random() * 800 << 0,
    y: Math.random() * 300 << 0,
    r: Math.random() * 255 << 0,
    g: Math.random() * 255 << 0,
    b: Math.random() * 255 << 0,
    a: (Math.random() * 128 << 0) + 128,
  };
  pixel.aNormalized = pixel.a / 255;
  pixel.rgbaArray = [pixel.r, pixel.g, pixel.b, pixel.aNormalized];
  $pixels.push(pixel);
}
// For the drawImage() test, create a canvas that has all 10,000 pixels rendered to it:
$paletteCanvas = document.createElement('canvas');
$paletteCanvas.width = 10000;
$paletteCanvas.height = 1;
const paletteContext = $paletteCanvas.getContext('2d');
const imageData = paletteContext.getImageData(0, 0, 10000, 1);
$pixels.forEach((pixel, index) => imageData.data.set(pixel.rgbaArray, index));
paletteContext.putImageData(imageData, 0, 0);
$iterations = 500;
Tests:
  • fillRect using a concatenated color string

     
    for (let i=0; i<$iterations; ++i) {
      const px = $pixels[i % 10000];
      $context.fillStyle = 'rgba(' + px.r + ',' + px.g + ',' + px.b + ',' + px.aNormalized + ')';
      $context.fillRect(px.x, px.y, 1, 1);
    }
  • fillRect using a joined color string

     
    for (let i=0; i<$iterations; ++i) {
      const px = $pixels[i % 10000];
      $context.fillStyle = 'rgba(' + px.rgbaArray.join() + ')';
      $context.fillRect(px.x, px.y, 1, 1);
    }
  • fillRect with a template literal color string

     
    for (let i=0; i<$iterations; ++i) {
      const px = $pixels[i % 10000];
      $context.fillStyle = `rgba(${px.r},${px.g},${px.b},${px.aNormalized})`;
      $context.fillRect(px.x, px.y, 1, 1);
    }
  • fillRect with a constant color string

     
    for (let i=0; i<$iterations; ++i) {
      const px = $pixels[i % 10000];
      $context.fillStyle = 'rgba(100,150,200,0.9)';
      $context.fillRect(px.x, px.y, 1, 1);
    }
  • putImageData() using a 1px by 1px ImageData instance

     
    for (let i=0; i<$iterations; ++i) {
      const px = $pixels[i % 10000];
      $onePixelData[0] = px.r;
      $onePixelData[1] = px.g;
      $onePixelData[2] = px.b;
      $onePixelData[3] = px.a;
      $context.putImageData($onePixel, px.x, px.y);
    }
  • Using drawImage to copy a pixel from a palette canvas

     
    for (let i=0; i<$iterations; ++i) {
      const index = i % 10000;
      const px = $pixels[index];
      $context.drawImage($paletteCanvas, index, 0, 1, 1, px.x, px.y, 1, 1);
    }
Rendered benchmark preparation results:

Suite status: <idle, ready to run>

Previous results

Experimental features:

  • Test case name Result
    fillRect using a concatenated color string
    fillRect using a joined color string
    fillRect with a template literal color string
    fillRect with a constant color string
    putImageData() using a 1px by 1px ImageData instance
    Using drawImage to copy a pixel from a palette canvas

    Fastest: N/A

    Slowest: N/A

Latest run results:
Run details: (Test run date: one month ago)
Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Mobile Safari/537.36
Chrome Mobile 126 on Android
View result in a separate tab
Test name Executions per second
fillRect using a concatenated color string 625.9 Ops/sec
fillRect using a joined color string 590.0 Ops/sec
fillRect with a template literal color string 639.3 Ops/sec
fillRect with a constant color string 2385.0 Ops/sec
putImageData() using a 1px by 1px ImageData instance 16.1 Ops/sec
Using drawImage to copy a pixel from a palette canvas 355.9 Ops/sec