Published
Edited
Jul 15, 2021
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
imagetracer = require("imagetracerjs")
Insert cell
function getVoronoiCells(points, { width = 100, height = 100 } = {}) {
const voronoi = d3.Delaunay.from(points).voronoi([0, 0, width, height]);
const cells = points.map((point, i) => {
const pathDefinition = voronoi.renderCell(i);
return { pathDefinition, point };
});
return cells;
}
Insert cell
function getPixels({ context, x, y, width, height, sample = 0.5 }) {
const imageData = context.getImageData(x, y, width, height);
const pixels = imageData.data;
const out = [];
const keys = ["r", "g", "b", "a"];
let current = {};
pixels.forEach((d, i) => {
const mod = i % 4;
const key = keys[mod];
current[key] = d;
if (mod === 3) {
if (Math.random() > sample) {
current = {};
return;
}
const pixelIndex = Math.floor(i / 4);
const column = pixelIndex % width;
const row = Math.floor(pixelIndex / width);
Object.assign(current, {
index: pixelIndex,
column,
row,
x: x + column,
y: y + row
});
const { r, g, b } = current;
const lightness = Math.floor((r + g + b) / 3);
const grayscale = `rgb(${lightness}, ${lightness}, ${lightness})`;
out.push({ ...current, lightness, grayscale });
current = {};
}
});
return out;
}
Insert cell
function getCells(columns = 50) {
const aspectRatio = imageWidth / imageHeight;
const rows = Math.ceil(columns / aspectRatio);
const cellWidth = Math.ceil(imageWidth / columns);
const cellHeight = Math.ceil(imageHeight / rows);
const numCells = columns * rows;
const cells = Array.from({ length: numCells }).map((d, i) => {
const column = i % columns;
const row = Math.floor(i / columns);
return {
x: column * cellWidth,
y: row * cellHeight,
column,
row,
width: cellWidth,
height: cellHeight
};
});
return cells;
}
Insert cell
function renderWithTransform({ func, columns, sample }) {
const context = DOM.context2d(imageWidth, imageHeight, 1);
context.canvas.style.width = "400px";
context.canvas.style.border = "1px solid black";
context.drawImage(image, 0, 0, imageWidth, imageHeight);

const outContext = DOM.context2d(imageWidth, imageHeight, 1);
outContext.canvas.style.width = context.canvas.style.width;

const withPixels = getCells(columns).map((cell, index) => {
const pixels = getPixels({
...cell,
context,
sample
});
return {
...cell,
pixels: pixels
};
});

const transformed = func({ cells: withPixels });

transformed.forEach((cell, index) => {
const { x, y, width, height, fillStyle } = cell;
outContext.beginPath();
outContext.fillStyle = fillStyle;
outContext.fillRect(x, y, width, height);
});

outContext.canvas.cells = transformed;

return outContext.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