// Tutorial //

Drawing Shapes with the JavaScript Canvas API

Published on August 5, 2019
Default avatar
By Joshua Hall
Developer and author at DigitalOcean.
Drawing Shapes with the JavaScript Canvas API

While we believe that this content benefits our community, we have not yet thoroughly reviewed it. If you have any suggestions for improvements, please let us know by clicking the “report an issue“ button at the bottom of the tutorial.

In this article we’ll be looking at the HTML canvas element and the JavaScript canvas API to render complex shapes onto our web pages.

Setup

All we need to start is an HTML page with a canvas tag and a JavaScript file to manipulate it with.

index.html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <meta http-equiv="X-UA-Compatible" content="ie=edge"/>
    <title>HTML Canvas</title>
  </head>
  <body>

    <canvas></canvas>

  </body>
  <script src="./canvas.js"></script>
</html>

With our canvas element in place, we now need to create a new variable with it and a canvas context, which adds a bunch of functionality onto our canvas. To keep things simple we’ll stick with 2D shapes, but with the webgl context, 3D is also possible.

For our example we’ll need our canvas to be fullscreen but setting the size using CSS creates a strange blurry effect, which we obviously don’t want, so we’ll have to set it here.

canvas.js
// getting a reference to our HTML element
const canvas = document.querySelector('canvas')

// initiating 2D context on it
const c = canvas.getContext('2d')

addEventListener('resize', () => {
  canvas.width = innerWidth
  canvas.height = innerHeight
})

Rectangles

To draw rectangles, on our context variable (c), we can start adding what we want, measured in pixels:

  • rect(x-axis, y-axis, width, height): Sets the location and dimensions of our rectangle, and needs to be called before stroke or fill.
  • stroke: Renders an outline of everything before it.
  • fill: Renders the whole shape as a solid color.
  • strokeStyle and fillStyle: Sets the outline and shape color. They are not functions like the others and need to be assigned a string.
  • strokeRect and fillRect: Same as stroke and fill but only for that item, works the same as rect.
  • clearRect(x-axis, y-axis, width, height): Clears everything inside of a certain area. Very useful when we get into animations where we’re constantly rendering new elements and don’t want the old ones to stick around.
canvas.js
c.strokeStyle = 'white'
c.fillStyle = 'blue'
c.rect(100, 20, 150, 100)
c.stroke()
c.fill()

c.fillStyle = 'red'
c.fillRect(400, 500, 300, 250)

// Uncomment to remove the first two blocks
// c.clearRect(0, 0, canvas.width, canvas.height)
c.fillStyle = 'green'
c.fillRect(1500, 500, 300, 250)

Lines

  • beginPath: Starts a new Line
  • stroke: Renders the line
  • moveTo(x-axis, y-axis): Sets the starting point
  • lineTo(x-axis, y-axis): Renders a line from the previous endpoint
  • lineWidth: Set the line’s thickness

And here are a few examples where we draw some lines:

// Just a basic line
c.beginPath()
c.moveTo(40, 250)
c.lineTo(200, 500)
c.strokeStyle = 'red'
c.stroke()

// Draw the letter M
c.beginPath()
c.moveTo(1500, 700)
c.lineTo(1600, 450)
c.lineTo(1700, 700)
c.lineTo(1800, 450)
c.lineTo(1900, 700)
c.strokeStyle = 'blue'
c.stroke()

// Let's now draw a house
c.lineWidth = 10
c.strokeStyle = 'red'
c.fillStyle = 'red'

// Walls 
c.strokeRect(800, 500, 300, 200)

// Door
c.fillRect(925, 600, 50, 100)

// Roof 
c.beginPath()
c.moveTo(700, 500)
c.lineTo(1200, 500)
c.lineTo(950, 300)
c.lineTo(700, 500)
c.stroke()

Circles

The only method we really need for drawing circles is arc. The angles are taken in radians and not degrees so for our end-angle we can just use Math.PI * 2, since that’s equal to 360 degrees, and the starting angle can be left at 0. We’re not going to need to specify a value for counterclockwise, so we can just leave it off since it defaults to false.

  • arc(x, y, radius, starting-angle, end-angle, counterclockwise (boolean))
canvas.js
c.lineWidth = 5
c.beginPath()
c.arc(400, 400, 50, 0, Math.PI * 2)
c.stroke()

Quadratic and Bezier Curves

If you’ve ever used graphic design tools like Photoshop or Affinity Designer, these will seem very similar to some of their line tools.

Essentially, quadratic and bezier curves are just free form lines with different methods of control. Quadratic curves are simpler in that they just have a start, endpoint, and what’s known as the control point, which acts as a handle for curving the line. You can see a wonderful interactive example here. Bezier curves, on the other hand, have two control points, at each end of the curve for more complex shapes. Another great example here.

  • quadraticCurveTo(controlPoint-x, controlPoint-y, endpoint-x, endpoint-y)
  • bezierCurveTo(startControlPoint-x, startControlPoint-y, endControlPoint-x, endControlPoint-y, endpoint-x, endpoint-y)

And some examples:

canvas.js
c.lineWidth = 5
c.strokeStyle = 'white'

c.beginPath()
c.moveTo(400, 400)
c.lineTo(400, 300)
c.quadraticCurveTo(450, 250, 500, 300)
c.lineTo(500, 400)
c.stroke()

c.beginPath()
c.moveTo(800, 400);
c.bezierCurveTo(800, 150, 1200, 700, 1200, 400);
c.stroke()

Text

Text works very similarly to rectangles with a few CSS-like options for styling:

  • fillText(text, x, y)
  • strokeText(text, x, y)
  • font: Takes a string with the size in pixels and font family; like ‘60px Times-New-Roman’.
  • textAlign: Takes a string with the same options as its CSS counterpart; start, end, left, right, and center.
canvas.js
c.font = '60px Times-New-Roman'
c.fillText("Hello World", 600, 500)
c.strokeText('Hello World', 1200, 500)

Conclusion

While there is still an enormous amount that can be done with HTML canvas like animations and interactivity, hopefully this was a good first introduction to some of its possibilities.


Want to learn more? Join the DigitalOcean Community!

Join our DigitalOcean community of over a million developers for free! Get help and share knowledge in our Questions & Answers section, find tutorials and tools that will help you grow as a developer and scale your project or business, and subscribe to topics of interest.

Sign up
About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
Leave a comment

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!