canvas-sketch cheatsheet
Ming Sun / May 06, 2023
8 min read • ––– views
Example 1: static
const canvasSketch = require("canvas-sketch");
const settings = {
// Output resolution, we can use 300PPI for print
pixelsPerInch: 600,
// Standard business card size
dimensions: [3.5, 2],
// all our dimensions and rendering units will use inches
units: "in",
};
const sketch = ({ context }) => {
console.log(context);
// Utility to draw a circle with or without a fill
const circle = (x, y, radius, fill = false) => {
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2, false);
if (fill) context.fill();
context.stroke();
};
return ({ context, width, height, frame }) => {
// Fill page with solid color
// The 'width' and 'height' will be in inches here
context.fillStyle = "#a00";
context.fillRect(0, 0, width, height);
context.strokeStyle = "#fff";
context.fillStyle = "#fff";
context.lineWidth = 0.01;
for (let i = 0; i < 5; i++) {
const x = (i / 4) * width;
const y = height / 2;
const radius = i % 2 === 0 ? 0.5 : 0.25;
const fill = i % 4 === 0;
circle(x, y, radius, fill);
}
};
};
canvasSketch(sketch, settings);
Example 2: animation
const canvasSketch = require("canvas-sketch");
const {
fract,
lerp,
clamp,
mapRange,
clamp01,
sign,
} = require("canvas-sketch-util/math");
const settings = {
// Enable an animation loop
animate: true,
// Set loop duration to 3 seconds
duration: 30,
// Use a small size for our GIF output
dimensions: [1920, 1080],
// Optionally specify an export frame rate, defaults to 30
fps: 36,
};
function drawLine(context, x1, y1, x2, y2) {
context.beginPath();
context.lineTo(x1, y1);
context.lineTo(x2, y2);
context.closePath();
context.stroke();
}
// Start the sketch
const sketch = ({ width, height }) => {
const render = ({ context, width, height, playhead }) => {
context.fillStyle = "#000";
context.fillRect(0, 0, width, height);
context.translate(width / 10 - 30, height / 2);
context.strokeStyle = "#fff";
context.lineCap = "round";
context.lineWidth = 3;
let xwidth = (width / 10) * 8;
let yheight = (height / 5) * 1.5;
drawLine(context, 0, 0, xwidth + 60, 0);
drawLine(context, 0, yheight, 0, -yheight);
let N = 10000;
let cycles = 3;
let step = xwidth / N;
context.lineWidth = 10;
context.strokeStyle = "cyan";
let amplitude = yheight * 0.8;
context.beginPath();
for (let i = 0; i < N * playhead; i++) {
let x = i * step;
let y = -amplitude * Math.sin((i / N) * 2 * Math.PI * cycles);
context.lineTo(x, y);
}
context.stroke();
let x = xwidth * playhead;
let y = -amplitude * Math.sin(playhead * 2 * Math.PI * cycles);
context.fillStyle = "red";
context.beginPath();
context.arc(x, y, 20, 0, 2 * Math.PI);
context.closePath();
context.fill();
context.fillStyle = "#fff";
context.font = "40px Arial";
context.fillText("y=sin(x) animation", xwidth / 2 - 150, -height / 2 + 100);
context.strokeStyle = "#fff";
context.lineWidth = 2;
context.setLineDash([2, 5]);
drawLine(context, 0, y, x, y);
drawLine(context, x, yheight - 20, x, y);
context.textAlign = "center";
context.fillText("0", -20, 40);
context.fillText(
Math.round(Math.sin(playhead * 2 * Math.PI * cycles) * 100) / 100,
-60,
y + 10
);
context.fillText(
Math.round(playhead * 2 * Math.PI * cycles * 100) / 100,
x,
yheight + 20
);
context.textAlign = "center";
context.fillText("π", xwidth / 6, 40);
context.fillText("2π", xwidth / 3, 40);
context.fillText("3π", xwidth / 2, 40);
context.fillText("4π", (xwidth / 6) * 4, 40);
context.fillText("5π", (xwidth / 6) * 5, 40);
context.fillText("6π", xwidth, 40);
context.restore();
};
return render;
};
canvasSketch(sketch, settings);