source.fact.ngo a coherence.ngo project

assets/emergence-layout.js

raw ↗ · AGPL-3.0

// Squarified areas describe coverage, never a ranking of importance or confidence. function worst(row, side) { const sum = row.reduce((n, item) => n + item.value, 0); if (!sum || !side) return Infinity; return Math.max(side * side * Math.max(...row.map(i => i.value)) / (sum * sum), sum * sum / (side * side * Math.min(...row.map(i => i.value)))); } export function squarify(items) { const total = items.reduce((n, item) => n + item.value, 0); const rest = items.filter(i => i.value > 0).map(i => ({ ...i, value: i.value / total })); const tiles = []; let x = 0, y = 0, w = 1, h = 1; while (rest.length) { const side = Math.min(w, h), row = [rest.shift()]; while (rest.length && worst([...row, rest[0]], side) <= worst(row, side)) row.push(rest.shift()); const sum = row.reduce((n, i) => n + i.value, 0); if (w >= h) { const width = sum / h; let top = y; for (const item of row) { const height = item.value / width; tiles.push({ ...item, x, y: top, w: width, h: height }); top += height; } x += width; w = Math.max(0, w - width); } else { const height = sum / w; let left = x; for (const item of row) { const width = item.value / height; tiles.push({ ...item, x: left, y, w: width, h: height }); left += width; } y += height; h = Math.max(0, h - height); } } return tiles; }