Code Visualizer
by wio_dude
HTML
<canvas
id="canvas"
width="720"
height="480"
/>
CSS
#canvas {
background-color: lightgrey;
}
JavaScript
class CodeMachine {
constructor(statement) {
this.statement = statement;
}
size(ctx, opts) {
const size = this.statement.size(ctx, opts);
return [size[0], size[1] + 2 * opts.pointSize];
}
draw(ctx, opts, start) {
ctx.beginPath();
ctx.arc(start[0], start[1] + opts.pointSize / 2, opts.pointSize / 2, Math.PI, 2 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.beginPath();
ctx.moveTo(start[0], start[1] + opts.pointSize / 2);
ctx.lineTo(start[0], start[1] + opts.pointSize);
ctx.stroke()
let end = this.statement.draw(ctx, opts, [start[0], start[1] + opts.pointSize]);
ctx.beginPath()
ctx.moveTo(end[0], end[1]);
ctx.lineTo(end[0], end[1] + opts.pointSize / 2);
ctx.stroke();
ctx.beginPath();
ctx.arc(end[0], end[1] + opts.pointSize / 2, opts.pointSize / 2, 0, Math.PI);
ctx.closePath();
ctx.fill();
}
}
class CodeBranch {
constructor(branches = []) {
this.branches = branches;
}
doesBranch() {
return true;
}
size(ctx, opts) {
let height = 0;
let width = 0;
for (const branch of this.branches) {
const child_size = branch.size(ctx, opts);
height = Math.max(height, child_size[1]);
width += child_size[0];
}
return [width, height + 2 * opts.gutterSize];
}
draw(ctx, opts, start) {
const sizes = this.branches.map(x => x.size(ctx, opts));
const width = sizes.map(x => x[0]).reduce((x, y) => x + y);
const height = sizes.map(x => x[1]).reduce((x, y) => Math.max(x, y));
const end = [start[0], start[1] + height + 2 * opts.gutterSize];
let offset = start[0] - width / 2;
for (const [index, branch] of this.branches.entries()) {
const railOffset = !branch.doesBranch() ? opts.gutterSize / 2 : sizes[index][0] / 2;
const branchStart = [offset + railOffset, start[1] + opts.gutterSize];
ctx.beginPath();
ctx.moveTo(start[0], start[1]);
ctx.bezierCurveTo(start[0], branchStart[1], branchStart[0],...