Public
Edited
Mar 21
Paused
8 stars
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
Insert cell
Insert cell
function placeTiles(w, h, {tileVariants, rng, nLargest}) {
const grid = new Uint32Array(w * h);
const slots = new Set(d3.shuffler(rng)(Array.from({length: w * h}, (_, i) => i)));
const placedTiles = [];
const wMax = tileVariants.reduce((max, t) => Math.max(max, t.w), 0);
const hMax = tileVariants.reduce((max, t) => Math.max(max, t.h), 0);
const iOf = (x, y) => x + y * w;

// Finds the largest free area, with a bias towards landscape orientation.
const extentOf = (x1, y1) => {
let x2 = Math.min(x1 + wMax, w);
let y2 = Math.min(y1 + hMax, h);
for(let x = x1; x < x2; x++) {
if(grid[iOf(x, y1)]) x2 = x;
else for(let y = y1; y < y2; y++) {
if(grid[iOf(x, y)]) y2 = y;
}
}
return [x2 - x1, y2 - y1];
};

const placeTile = (x1, y1, tile) => {
const {w, h} = tile;
const n = placedTiles.push({x: x1, y: y1, tile});
for(let y = y1; y < y1 + h; y++) {
for(let x = x1; x < x1 + w; x++) {
const i = iOf(x, y);
slots.delete(i);
grid[i] = n;
}
};
};

for(const i of slots) {
const x = i % w;
const y = i / w | 0;
const [mw, mh] = extentOf(x, y);
const candidates = tileVariants.filter(t => t.w <= mw && t.h <= mh);
if(candidates.length) placeTile(x, y, weighted(rng(), candidates, d => d.r));
}

return placedTiles;
}
Insert cell
function weighted(n, arr, weightOf) {
let max = 0;
const weights = arr.map(v => (max += weightOf(v)));
const offset = n * max;
if(isNaN(offset)) throw new Error("Invalid offset");
return arr[weights.findIndex(w => offset <= w)];
}
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