Published
Edited
Aug 19, 2019
16 stars
Insert cell
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = [startIndex];
yield context.canvas;
while (queue.length) {
await visibility();
const i = queue.shift();
const x = i % width;
const y = Math.floor(i / width);
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1);
context.fillRect(x - 1, y, 1, 1);
}
if (x < width && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1);
context.fillRect(x + 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width);
context.fillRect(x, y - 1, 1, 1);
}
if (y < height && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width);
context.fillRect(x, y + 1, 1, 1);
}
yield context.canvas;
}
}
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = [startIndex];
yield context.canvas;
while (queue.length) {
await visibility();
const i = queue.pop();
const x = i % width;
const y = Math.floor(i / width);
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1);
context.fillRect(x - 1, y, 1, 1);
}
if (x < width - 1 && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1);
context.fillRect(x + 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width);
context.fillRect(x, y - 1, 1, 1);
}
if (y < height - 1 && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width);
context.fillRect(x, y + 1, 1, 1);
}
yield context.canvas;
}
}
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = [startIndex];
yield context.canvas;
while (queue.length) {
await visibility();
const i = queue.pop();
const x = i % width;
const y = Math.floor(i / width);
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1);
context.fillRect(x - 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width);
context.fillRect(x, y - 1, 1, 1);
}
if (x < width - 1 && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1);
context.fillRect(x + 1, y, 1, 1);
}
if (y < height - 1 && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width);
context.fillRect(x, y + 1, 1, 1);
}
yield context.canvas;
}
}
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = [startIndex];
yield context.canvas;
while (queue.length) {
await visibility();
const i = queue.pop();
const x = i % width;
const y = Math.floor(i / width);
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
const i0 = queue.length;
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1);
context.fillRect(x - 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width);
context.fillRect(x, y - 1, 1, 1);
}
if (x < width - 1 && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1);
context.fillRect(x + 1, y, 1, 1);
}
if (y < height - 1 && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width);
context.fillRect(x, y + 1, 1, 1);
}
const i1 = queue.length;
d3.shuffle(queue, i0, i1);
yield context.canvas;
}
}
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = [startIndex];
yield context.canvas;
while (queue.length) {
await visibility();
const j = Math.floor(Math.random() * queue.length);
const i = queue[j];
const x = i % width;
const y = Math.floor(i / width);
queue[j] = queue[queue.length - 1];
queue.pop();
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1);
context.fillRect(x - 1, y, 1, 1);
}
if (x < width - 1 && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1);
context.fillRect(x + 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width);
context.fillRect(x, y - 1, 1, 1);
}
if (y < height - 1 && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width);
context.fillRect(x, y + 1, 1, 1);
}
yield context.canvas;
}
}
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = new Queue;
queue.push(startIndex, 0);
yield context.canvas;
while (queue.length) {
await visibility();
const i = queue.pop();
const x = i % width;
const y = Math.floor(i / width);
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1, (x - startX) ** 2 + (y - startY) ** 2);
context.fillRect(x - 1, y, 1, 1);
}
if (x < width - 1 && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1, (x - startX) ** 2 + (y - startY) ** 2);
context.fillRect(x + 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width, (x - startX) ** 2 + (y - startY) ** 2);
context.fillRect(x, y - 1, 1, 1);
}
if (y < height - 1 && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width, (x - startX) ** 2 + (y - startY) ** 2);
context.fillRect(x, y + 1, 1, 1);
}
yield context.canvas;
}
}
Insert cell
Insert cell
{
const context = createContext();
const pixels = new Uint32Array(context.getImageData(0, 0, width, height).data.buffer);
const startColor = pixels[startIndex];
const queue = new Queue;
queue.push(startIndex, 0);
yield context.canvas;
while (queue.length) {
await visibility();
const i = queue.pop();
const x = i % width;
const y = Math.floor(i / width);
context.fillStyle = "#f00";
context.fillRect(x, y, 1, 1);
context.fillStyle = "#ccc";
if (x > 0 && pixels[i - 1] === startColor) {
pixels[i - 1] = 0;
queue.push(i - 1, Math.random());
context.fillRect(x - 1, y, 1, 1);
}
if (x < width - 1 && pixels[i + 1] === startColor) {
pixels[i + 1] = 0;
queue.push(i + 1, Math.random());
context.fillRect(x + 1, y, 1, 1);
}
if (y > 0 && pixels[i - width] === startColor) {
pixels[i - width] = 0;
queue.push(i - width, Math.random());
context.fillRect(x, y - 1, 1, 1);
}
if (y < height - 1 && pixels[i + width] === startColor) {
pixels[i + width] = 0;
queue.push(i + width, Math.random());
context.fillRect(x, y + 1, 1, 1);
}
yield context.canvas;
}
}
Insert cell
Insert cell
function createContext() {
const context = DOM.context2d(width, height, 1);
context.canvas.style = `
display: block;
margin: auto;
width: ${canvasWidth}px;
image-rendering: pixelated;
`;
context.canvas.onclick = event => {
mutable startX = Math.round(event.layerX / canvasWidth * image.naturalWidth);
mutable startY = Math.round(event.layerY / canvasWidth * image.naturalWidth);
};
context.drawImage(image, 0, 0);
return context;
}
Insert cell
canvasWidth = Generators.observe(notify => {
let width;
function resized() {
let w = Math.floor(2 * document.body.clientWidth / image.naturalWidth) * (image.naturalWidth / 2);
if (w !== width) notify(width = w);
}
resized();
window.addEventListener("resize", resized);
return () => window.removeEventListener("resize", resized);
})
Insert cell
image = new Promise((resolve, reject) => {
const image = new Image;
image.crossOrigin = "anonymous";
image.src = "https://gist.githubusercontent.com/mbostock/25cc9214c334dfca1a10b1a37ccb3353/raw/bd8dab8127dd67c75dded8c689185e1cedd0b38f/floodfill.png";
image.onload = () => resolve(image);
image.onerror = reject;
})
Insert cell
mutable startX = width >> 1
Insert cell
mutable startY = (height >> 1) - 6
Insert cell
startIndex = startY * width + startX
Insert cell
width = image.naturalWidth
Insert cell
height = image.naturalHeight
Insert cell
Queue = require("flatqueue@1")
Insert cell
d3 = require("d3-array@2")
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