Published
Edited
Sep 11, 2021
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{
ctx.fillStyle = "black";
ctx.fillRect(0, 0, width, height);

// Here we compute the color values for each pixel
const pixelColors = [];
let c = 0;
// Use the canvas width and height so we get the real/scaled size of our canvas
for (let y = 0; y < ctx.canvas.height; y++) {
for (let x = 0; x < ctx.canvas.width; x++) {
pixelColors.push(d3.hsl(c, 0.4, 0.5, 1));
}
c += 1;
if (c > 255) c = 0;
}
// Now we tell the browser to render those pixels in the canvas
// That function will associated the correct rgb/opacity values to each pixel in the canvas 🔥
drawPixels(ctx, pixelColors);

// And now we use the more "common" canvas api to continue drawing the rest of the elements of our project
ctx.fillStyle = "pink";
ctx.fillRect(20, 20, 15, 30);

return ctx.canvas;
}
Insert cell
/**
* ctx: canvas context
* pixelColors: Array of d3 colors for each pixel
**/
function drawPixels(ctx, pixelColors) {
const dpi = devicePixelRatio;
// access the canvas at pixel level
const { width, height } = ctx.canvas;
const id = ctx.getImageData(0, 0, width, height);
const pixels = id.data;

for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
// We have two indexes, offData for the pixelColors (each entry has a d3 color)
// and offPixel to address the canvas pixels
const offData = y * id.width + x;
const offPixel = (y * id.width + x) * 4;
if (!pixelColors[offData]) continue;
const { r, g, b, opacity } = pixelColors[offData].rgb();
pixels[offPixel] = r;
pixels[offPixel + 1] = g;
pixels[offPixel + 2] = b;
pixels[offPixel + 3] = opacity * 255;
}
}
ctx.putImageData(id, 0, 0);
}
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more