Drawing Shapes with the JavaScript Canvas API

Published on August 5, 2019
Default avatar

By Joshua Hall

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.


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

<!DOCTYPE html>
<html lang="en">
    <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>


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

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.

// 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


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.
c.strokeStyle = 'white'
c.fillStyle = 'blue'
c.rect(100, 20, 150, 100)

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)


  • 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.moveTo(40, 250)
c.lineTo(200, 500)
c.strokeStyle = 'red'

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

// 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.moveTo(700, 500)
c.lineTo(1200, 500)
c.lineTo(950, 300)
c.lineTo(700, 500)


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))
c.lineWidth = 5
c.arc(400, 400, 50, 0, Math.PI * 2)

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:

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

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

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


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.
c.font = '60px Times-New-Roman'
c.fillText("Hello World", 600, 500)
c.strokeText('Hello World', 1200, 500)


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.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about us

About the authors
Default avatar
Joshua Hall


Still looking for an answer?

Ask a questionSearch for more help

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!

Try DigitalOcean for free

Click below to sign up and get $200 of credit to try our products over 60 days!

Sign up

Join the Tech Talk
Success! Thank you! Please check your email for further details.

Please complete your information!

Get our biweekly newsletter

Sign up for Infrastructure as a Newsletter.

Hollie's Hub for Good

Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

Become a contributor

Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

Welcome to the developer cloud

DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

Learn more
DigitalOcean Cloud Control Panel