67 lines
1.8 KiB
JavaScript
67 lines
1.8 KiB
JavaScript
import treemapDice from "./dice.js";
|
|
import treemapSlice from "./slice.js";
|
|
|
|
export var phi = (1 + Math.sqrt(5)) / 2;
|
|
|
|
export function squarifyRatio(ratio, parent, x0, y0, x1, y1) {
|
|
var rows = [],
|
|
nodes = parent.children,
|
|
row,
|
|
nodeValue,
|
|
i0 = 0,
|
|
i1 = 0,
|
|
n = nodes.length,
|
|
dx, dy,
|
|
value = parent.value,
|
|
sumValue,
|
|
minValue,
|
|
maxValue,
|
|
newRatio,
|
|
minRatio,
|
|
alpha,
|
|
beta;
|
|
|
|
while (i0 < n) {
|
|
dx = x1 - x0, dy = y1 - y0;
|
|
|
|
// Find the next non-empty node.
|
|
do sumValue = nodes[i1++].value; while (!sumValue && i1 < n);
|
|
minValue = maxValue = sumValue;
|
|
alpha = Math.max(dy / dx, dx / dy) / (value * ratio);
|
|
beta = sumValue * sumValue * alpha;
|
|
minRatio = Math.max(maxValue / beta, beta / minValue);
|
|
|
|
// Keep adding nodes while the aspect ratio maintains or improves.
|
|
for (; i1 < n; ++i1) {
|
|
sumValue += nodeValue = nodes[i1].value;
|
|
if (nodeValue < minValue) minValue = nodeValue;
|
|
if (nodeValue > maxValue) maxValue = nodeValue;
|
|
beta = sumValue * sumValue * alpha;
|
|
newRatio = Math.max(maxValue / beta, beta / minValue);
|
|
if (newRatio > minRatio) { sumValue -= nodeValue; break; }
|
|
minRatio = newRatio;
|
|
}
|
|
|
|
// Position and record the row orientation.
|
|
rows.push(row = {value: sumValue, dice: dx < dy, children: nodes.slice(i0, i1)});
|
|
if (row.dice) treemapDice(row, x0, y0, x1, value ? y0 += dy * sumValue / value : y1);
|
|
else treemapSlice(row, x0, y0, value ? x0 += dx * sumValue / value : x1, y1);
|
|
value -= sumValue, i0 = i1;
|
|
}
|
|
|
|
return rows;
|
|
}
|
|
|
|
export default (function custom(ratio) {
|
|
|
|
function squarify(parent, x0, y0, x1, y1) {
|
|
squarifyRatio(ratio, parent, x0, y0, x1, y1);
|
|
}
|
|
|
|
squarify.ratio = function(x) {
|
|
return custom((x = +x) > 1 ? x : 1);
|
|
};
|
|
|
|
return squarify;
|
|
})(phi);
|