Let’s look again at this example
We start with a red canvas element in our HTML document.
<canvas width="300" height="100" id="myCanvas" style="background: red;"></canvas>
The 2d canvas context provides us with access to the drawing API.
// get a reference to the 2d canvas context object
const ctx = myCanvas.getContext('2d');
// fill a big square (default to black)
ctx.fillRect(100, 0, 100, 100);
// fill two smaller squares
ctx.fillRect(30, 30, 40, 40);
ctx.fillRect(230, 30, 40, 40);
// change the fill style to red and draw another square
ctx.fillStyle = "red";
ctx.fillRect(130, 30, 40, 40);
Coordinates
Canvas coordinates are pretty simple but be aware that the origin is in the top left corner.
Paths, stroke()
and fill()
<canvas width="300" height="100" id="myCanvas2" style="background: red;"></canvas>
Again, starting with a red canvas, this time we draw a path with individual lines.
The path is closed (to join the end back with the beginning) and then filled in blue.
We call stroke
to draw a line on the path.
Notice the thickness of the yellow line is spread equally over either side of the path.
const ctx2 = myCanvas2.getContext('2d');
ctx2.strokeStyle = "yellow";
ctx2.lineWidth = 5;
ctx2.fillStyle = "blue";
ctx2.moveTo(10, 10);
ctx2.lineTo(160, 40);
ctx2.lineTo(290, 10);
ctx2.lineTo(290, 90);
ctx2.lineTo(120, 60);
ctx2.lineTo(10, 90);
ctx2.closePath();
ctx2.fill();
ctx2.stroke();
Event listeners
Event Listeners allow us to execute code when certain events occur on an element.
The classic example is the click
event which triggers when the mouse clicks an element.
<canvas width="300" height="150" id="myCanvas3" style="background: #eee; border: 4px solid black;"></canvas>
When we click on the canvas, we generate random coordinates x
and y
based on random numbers (0 to 1) multiplied by the width (for x) and the height (for y) of the canvas.
We also generate a random radius value, r
.
We use these coordinates to as the location of a circle which we draw on the canvas.
const ctx3 = myCanvas3.getContext('2d');
ctx3.strokeStyle = "hsla(30, 50%, 40%, 0.15)";
ctx3.lineWidth = 20;
function draw_random_circle() {
const x = Math.random() * myCanvas3.width;
const y = Math.random() * myCanvas3.height;
const r = (0.1 + Math.random()) * myCanvas3.height / 4;
ctx3.beginPath();
ctx3.arc(x, y, r, 0, Math.PI * 2);
ctx3.stroke();
}
myCanvas3.addEventListener('click', draw_random_circle);
Mouse events
Here we turn drawing on when the mousedown event fires and turn it off when the mouseup event fires.
We also call lineTo
on the mousemove event, but only when drawing is turned on.
const ctx = canvas.getContext('2d');
let on = false;
canvas.addEventListener('mousedown', ev => {
on = true;
ctx.moveTo(ev.offsetX, ev.offsetY);
ctx.beginPath();
});
canvas.addEventListener('mouseup', ev => {
on = false;
});
canvas.addEventListener('mousemove', ev => {
if(on) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.lineTo(ev.offsetX, ev.offsetY);
ctx.stroke();
}
});
Lines and curves
A path is a series of points connected by lines or curves.
We can use moveTo
, lineTo
, bezierCurveTo
, quadraticCurveTo
and arcTo
to join paths in different ways.
Use quadraticCurveTo
to add a quadratic bezier curve to the current sub-path.
The curve begins at the latest point in the current path.
The function requires coordinates for a control point plus the end point.
Use bezierCurveTo
to add a cubic bezier curve to the current sub-path.
The curve begins at the latest point in the current path.
The function requires coordinates for two control points plus the end point.
Use arcTo
to add a circular arc between two points.
The function requires coordinates for two control points plus the radius of the arc.
The examples here use the same control point but different radii.
Animation
To animate a canvas, we just need to draw one frame at a time. The frame function clears the canvas and draws a square at the given coordinates. We just move the x-coordinate a little bit every frame.
const animatedCtx = animatedCanvas.getContext("2d");
animatedCtx.fillStyle = "red";
let animx = 200;
let animy = 75;
function animateFrame() {
animatedCtx.clearRect(0, 0, animatedCanvas.width, animatedCanvas.height)
animatedCtx.fillRect(animx - 10, animy - 10, 20, 20);
animx += 25;
animx %= animatedCanvas.width;
}
animateFrame();
animatedCanvas.addEventListener('click', ev => {
animateFrame();
});
What’s next?
Now we are working with the HTML <canvas>
element, your job is to experiment.
Next week, we will be covering how to use JavaScript classes to represent objects in a scene. And you will be asked to produce another assignment in which you will produce an animation of your choice.