Skip to content

Instantly share code, notes, and snippets.

@jonurry
Created March 30, 2018 11:28
Show Gist options
  • Save jonurry/03ba3627bd6d7b7e97d69fdec92d1e5a to your computer and use it in GitHub Desktop.
Save jonurry/03ba3627bd6d7b7e97d69fdec92d1e5a to your computer and use it in GitHub Desktop.
17.1 Shapes (Eloquent JavaScript Solutions)
<canvas width="600" height="200"></canvas>
<script>
let cx = document.querySelector("canvas").getContext("2d");
cx.clearRect(0, 0, 600, 200);
const drawTrapezoid = (cx, x, y, width, height, indent) => {
cx.beginPath();
cx.moveTo(x + indent, y);
cx.lineTo(x - indent + width, y);
cx.lineTo(x + width, y + height);
cx.lineTo(x, y + height);
cx.closePath();
cx.stroke();
}
const drawDiamond = (cx, x, y, side, fill) => {
cx.save();
cx.fillStyle = fill;
cx.translate(x + side / 2, y + side / 2);
cx.rotate(Math.PI / 4);
cx.translate(-x - side / 2, -y - side / 2);
cx.fillRect(x, y, side, side);
cx.restore();
}
const drawZigZag = (cx, x, y, width, height, num) => {
cx.beginPath();
cx.moveTo(x, y);
let inc = height / num;
for (let i = 0; i < num; i++) {
let offset = y + (i * inc);
cx.lineTo(x + width, offset + (inc / 2));
cx.lineTo(x, offset + inc);
}
cx.stroke();
}
const drawSpiral = (cx, x, y, width, segments) => {
cx.beginPath();
cx.moveTo(x + width / 2, y + width / 2);
let inc = Math.pow(Math.PI, 2) / segments;
let angle = 0;
for (let i = 0; i < segments; i++) {
let points = [];
angle += inc;
points[0] = Math.cos(angle);
points[1] = Math.sin(angle);
angle += inc;
points[2] = Math.cos(angle);
points[3] = Math.sin(angle);
points = points.map(x => ((x * i) + width) / 2);
cx.lineTo(x + points[0], y + points[1]);
cx.lineTo(x + points[2], y + points[3]);
}
cx.stroke();
}
const drawStar = (cx, x, y, width, points) => {
let halfWidth = width / 2;
let xCentre = x + halfWidth;
let yCentre = y + halfWidth;
let inc = 2 * Math.PI / points;
let angle = 0;
cx.beginPath();
cx.moveTo(x + width, y + width / 2);
for (let i = 0; i < points; i++) {
angle += inc;
cx.quadraticCurveTo(xCentre, yCentre, xCentre + Math.cos(angle) * halfWidth, yCentre + Math.sin(angle) * halfWidth);
}
cx.fillStyle = 'orange';
cx.fill();
}
drawTrapezoid(cx, 0, 30, 80, 40, 20);
drawDiamond(cx, 100, 25, 50, 'red');
drawZigZag(cx, 180, 0, 100, 100, 6);
drawSpiral(cx, 300, 0, 100, 100);
drawStar(cx, 420, 0, 100, 8);
</script>
@jonurry
Copy link
Author

jonurry commented Mar 30, 2018

Hints

The trapezoid (1) is easiest to draw using a path. Pick suitable centre coordinates and add each of the four corners around that.

The diamond (2) can be drawn the straightforward way, with a path, or the interesting way, with a rotate transformation. To use rotation, you will have to apply a trick similar to what we did in the flipHorizontally function. Because you want to rotate around the centre of your rectangle and not around the point (0,0), you must first translate to there, then rotate, and then translate back.

Make sure you reset the transformation after drawing any shape that creates one.

For the zigzag (3) it becomes impractical to write a new call to lineTo for each line segment. Instead, you should use a loop. You can have each iteration draw either two line segments (right and then left again) or one, in which case you must use the evenness (% 2) of the loop index to determine whether to go left or right.

You’ll also need a loop for the spiral (4). If you draw a series of points, with each point moving further along a circle around the spiral’s centre, you get a circle. If, during the loop, you vary the radius of the circle on which you are putting the current point and go around more than once, the result is a spiral.

The star (5) depicted is built out of quadraticCurveTo lines. You could also draw one with straight lines. Divide a circle into eight pieces for a star with eight points, or however many pieces you want. Draw lines between these points, making them curve toward the centre of the star. With quadraticCurveTo, you can use the centre as the control point.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment