Public
Edited
Jan 8, 2023
Insert cell
Insert cell
viewof canvas = {
const
height = 200,
dpi = devicePixelRatio,
context = DOM.context2d(width, height, dpi),
w = context.canvas.width,
h = context.canvas.height,
time = new Date(),
text = `${time.getHours().toString().padStart(2, "0")}:${time.getMinutes().toString().padStart(2, "0")}`;

context.canvas.value = context; // Allows use of `viewof`.

// Draw text.
context.font = "bold 60px sans-serif";
context.fillText(text, 10, 60);

// Figure out where text is.
const
imageData = context.getImageData(0, 0, w, h).data,
textPixels = [];

for (let x = 0; x < w; x++) {
for (let y = 0; y < h; y++) {
// See:
// https://developer.mozilla.org/docs/Web/API/ImageData
// https://developer.mozilla.org/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas
const
startOffset = (4 * y * w) + (4 * x),
endOffset = startOffset + 4,
pixelData = imageData.slice(startOffset, endOffset),
[r, g, b, a] = pixelData;

if (a > 0) {
textPixels.push((x << 16) | y);
}
}
}

// Clear text.
// context.clearRect(0, 0, w, h);

// Draw dots.
const
dotsOffsetX = 50,
dotsOffsetY = 50,
dots = Array.from({ length: 20 }, (_, i) => {
const
r = 20 + Math.random() * 100,
t = Math.random() * Math.PI * 2,
x = (dotsOffsetX + r * Math.cos(t)) | 0,
y = (dotsOffsetY + r * Math.sin(t)) | 0,
v = (dpi * x << 16) | (dpi * y);
return { x, y, v };
});

context.fillStyle = "red";

for (const { x, y, v } of dots) {
const
dotWidth = textPixels.includes(v) ? 10 : 6,
dotWidthHalf = dotWidth / 2;

context.beginPath();
context.roundRect(x - dotWidthHalf, y - dotWidthHalf, dotWidth, dotWidth, dotWidthHalf);
context.fill();
}

return context.canvas;
}
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