import { constants } from './utils';
const { Angles } = constants;
function drawConnector(canvas, connectingOffset) {
canvas.beginPath();
canvas.moveTo(0, 0);
canvas.lineTo(connectingOffset, 0);
canvas.stroke();
canvas.closePath();
}
function commitPath(canvas, { lineWidth, strokeStyle, fillStyle }) {
canvas.lineWidth = lineWidth;
canvas.strokeStyle = strokeStyle;
canvas.fillStyle = fillStyle;
canvas.fill();
if (lineWidth > 0 && strokeStyle !== fillStyle) {
canvas.stroke();
}
}
const lengthOfSquareSide = (radius) => radius * Math.sqrt(2);
/**
* @function nodeRenderer
* @description A pure function to render a leaf.
*
* @param {CanvasRenderingContext2D} canvas - See {@link Tree#canvas}
* @param {number} radius - See {@link Branch#radius}
* @param {Object} style - See {@link Branch#leafStyle}
*/
export default {
circle(canvas, radius, style) {
// circle takes same area as square inside given radius
const scaledArea = Math.pow(lengthOfSquareSide(radius), 2);
const scaledRadius = Math.sqrt(scaledArea / Math.PI);
drawConnector(canvas, radius - scaledRadius);
canvas.beginPath();
canvas.arc(radius, 0, scaledRadius, 0, Angles.FULL, false);
canvas.closePath();
commitPath(canvas, style);
},
square(canvas, radius, style) {
const lengthOfSide = lengthOfSquareSide(radius);
const startX = radius - lengthOfSide / 2;
drawConnector(canvas, startX);
canvas.beginPath();
canvas.moveTo(startX, 0);
canvas.lineTo(startX, lengthOfSide / 2);
canvas.lineTo(startX + lengthOfSide, lengthOfSide / 2);
canvas.lineTo(startX + lengthOfSide, -lengthOfSide / 2);
canvas.lineTo(startX, -lengthOfSide / 2);
canvas.lineTo(startX, 0);
canvas.closePath();
commitPath(canvas, style);
},
star(canvas, radius, style) {
const cx = radius;
const cy = 0;
const spikes = 5;
const outerRadius = radius;
const innerRadius = outerRadius * 0.5;
const step = Math.PI / spikes;
drawConnector(canvas, outerRadius - innerRadius);
let rot = Math.PI / 2 * 3;
canvas.beginPath();
canvas.moveTo(cx, cy - outerRadius);
for (let i = 0; i < spikes; i++) {
let x = cx + Math.cos(rot) * outerRadius;
let y = cy + Math.sin(rot) * outerRadius;
canvas.lineTo(x, y);
rot += step;
x = cx + Math.cos(rot) * innerRadius;
y = cy + Math.sin(rot) * innerRadius;
canvas.lineTo(x, y);
rot += step;
}
canvas.lineTo(cx, cy - outerRadius);
canvas.closePath();
commitPath(canvas, style);
},
triangle(canvas, radius, style) {
const lengthOfSide = (2 * radius) * Math.cos(30 * Math.PI / 180);
const height = (Math.sqrt(3) / 2) * lengthOfSide;
const midpoint = (1 / Math.sqrt(3)) * (lengthOfSide / 2);
drawConnector(canvas, radius - midpoint);
canvas.beginPath();
canvas.moveTo(radius, midpoint);
canvas.lineTo(radius + lengthOfSide / 2, midpoint);
canvas.lineTo(radius, -(height - midpoint));
canvas.lineTo(radius - lengthOfSide / 2, midpoint);
canvas.lineTo(radius, midpoint);
canvas.closePath();
commitPath(canvas, style);
},
};