makeTree = (a, orientation, scaleRatio, maxDepth = 5, isTopLayer = false) => {
const FULL_LENGTH = 300;
const traverse = (a, orientation, scaleRatio, currentDepth = 0) => {
const scale = scaleRatio * FULL_LENGTH;
const linearDepth = (maxDepth - currentDepth) / maxDepth;
const thickness = scaleRatio * linearDepth * 15;
const numBranches = Math.max(d3.randomNormal(1, 1.5)(), 1);
const length = Math.max(d3.randomNormal(scale, scale * 0.2)() + 30, 30);
const angle = d3.randomNormal(orientation, 0.25)();
const curvature = d3.randomNormal(0, .1)();
const b = {
x: Math.cos(angle) * length + a.x,
y: Math.sin(angle) * length + a.y
};
const cp = midOffset(a, b, curvature);
const bPrime = getQuadraticXY(0.99, a.x, a.y, cp.x, cp.y, b.x, b.y);
const endAngle = Math.atan2(b.y - bPrime.y, b.x - bPrime.x);
function getQuadraticXY(t, sx, sy, cp1x, cp1y, ex, ey) {
return {
x: (1 - t) * (1 - t) * sx + 2 * (1 - t) * t * cp1x + t * t * ex,
y: (1 - t) * (1 - t) * sy + 2 * (1 - t) * t * cp1y + t * t * ey
};
}
const tree = {
a,
b,
curvature,
linearDepth,
thickness,
color: '#333'
};
const isTwig = !(maxDepth !== currentDepth && numBranches);
if (!isTwig) {
tree.branches = [];
for (let i = 0; i < numBranches; i++) {
tree.branches.push(
traverse(b, endAngle, (length / FULL_LENGTH) * 0.6, currentDepth + 1)
);
}
if (Math.random() > 0.8 && isTopLayer) {
tree.blossoms = makeBlossomCluster(
tree.b,
Math.max(d3.randomNormal(20, 15)(), 10),
Math.max(d3.randomNormal(100, 100)(), 0),
Math.random() > 0.5 ? '#5c0204cc' : '#b6030b99',
'#469bd299'
);
}
} else {
if (Math.random() > 0.9) {
tree.blossoms = makeBlossomCluster(
tree.b,
Math.max(d3.randomNormal(30, 10)(), 1),
Math.max(d3.randomNormal(80, 10)(), 1),
'#f6b6accc',
'#bcafb2'
);
}
}
return tree;
};
return traverse(a, orientation, scaleRatio);
}