Creating Art with HTML Canvas and JavaScript

Varun Maliwal
Nov 3 · 6 min read
First attempt at creative coding

Motivation

In last few months, apart from creating Koonchi, I’ve developed a strong affection for Generative Art.

“Generative Art often refers to algorithmic art (algorithmically determined computer generated artwork)” — Wikipedia

Also known as Creative Coding, it is a mix of creativity and everything a modern world computers has to offer. I’ve been working professionally as a Software Engineer for 8+ years now, but it is still hard for me to fathom why I did not think writing code to create art. But as they say better late than never, so let’s begin our adventure.

I plan to write a series of articles about my journey through creative coding, and the first step in this process is to explore HML5 <canvas> element.

Why is <canvas> element so special you may ask, and the simple answer is: it can be used to draw graphics using JavaScript. It provides APIs to manipulate photos, tools to create games and animations, and it makes it very easy to create Generative Art.

Does that mean we are restricted to using only JavaScript on the web for Generative Art? Absolutely not! There are tons of libraries, resources and frameworks available in all languages. You may need to do a little bit of research but here’s an awesome list I found on github to begin.

How to Get Started with HTML5 Canvas?

It is a two step process.

Step 1: Add <canvas> element to your HTML document, like —

<canvas id="myCanvas"></canvas>

Step 2: Use canvas’ context API in JavaScript to draw

const canvas = document.querySelector("#myCanvas")
const ctx = canvas.getContext("2d")

If you want to skip implementation details, and instead look at a full working example checkout codepen & codepen.

What is a Context?

Canvas allows drawing and pixel manipulation using JavaScript API. This drawing has to be performed on canvas’ context. Think of context as a page to paint and API as available tools (or brushes). The context can either be “2d” or “webgl”(3d). For the purpose of this introduction we will always assume “2d” context.

How to set Width and Height of Canvas?

Dimensions of canvas element can either be set statically in HTML, or dynamically using JavaScript, or a combination of both.

Using HTML:

<canvas id="myCanvas" width="200" height="300"></canvas>

Using JavaScript:

const canvas = document.querySelector("#myCanvas")canvas.width  = 200
canvas.height = 300
// To set width and height of current viewport do// canvas.width = window.innerWidth
// canvas.height = window.innerHeight

The Grid or Coordinate Space

1: A rectangle on canvas at position 0, 0

It is important to understand the coordinate space of canvas, if you want elements to be positioned as desired. Top left of canvas represents (0,0) or origin coordinate. All the elements on canvas are placed with reference to this origin. 1 point on grid is roughly equivalent to 1px.
Pic 1 further elaborates: we have red border around our canvas and we have drawn a rectangle of 100px width and height with a stroke of blue.

2: A rectangle on canvas at position 20, 20

Providing x and y coordinates would translate the element relative to the canvas’ origin coordinates. As shown in Image 2, our rectangle has moved 20 pixels to the right and bottom as we have provided the values of x and y as 20.

How to Draw Basic Shapes?

It is easy to draw basic shapes like rectangle, triangle, square, circle, polygon or a just a simple line between two points. But by default Canvas provides a method only to draw rectangle. However, rest of shapes can be created by joining points using path API, and a combination of line and arc APIs. Let’s look at some code examples to further elaborate.

Rectangle: Rectangles can be drawn using fillRect(x, y, width, height) and strokeRect(x, y, width, height) method on context. fill and stroke are ink methods and each case it means to draw a rectangle with a filled color, or to draw a rectangular outline of a color. The default color is black.

const ctx = canvas.getContext("2d")// fill color of rectangle
ctx.fillStyle = "tomato"
// draw rectangle, and fill it with "tomato" color
// x = 10
// y = 20
// width = 200
// height = 300
ctx.fillRect(10, 20, 200, 300)
// now change style to stroke
ctx.strokeStyle = "green"
// draw rectangle with "green" color stroke (no fill)
ctx.strokeRect(100, 100, 200, 100)

Circle: As we mentioned earlier there is no straight forward method to create a circle, but we can use a combination of path APIs and arc method to draw our circle. Let’s understand a little more about path:

“A path is list of points connected to form different shapes”.

This means a path can be formed between two given points on screen. It can be a straight line or curved arc or can be any shape or color. There are three steps to follow to create a shape using path:

  1. Invoke beingPath() method on context a create a new path. Once a path is created all future commands to draw are applied on this path.
  2. Next create a path using drawing methods, like lineTo, moveTo, arc, rect, etc. Refer MDN for list of all available methods that used with path.
  3. Once path has been created it needs to actually be rendered on canvas; we can do that using ink methods fill and stroke.

Let’s get back drawing our circle. We have to use arc(x, y, radius, startAngle, endAngle) method on context to draw our circle. If we try to recollect basic geometry, to draw a circle using a protractor we need a radius, and a start & end angle. A semi-circle starts at angle 0 and ends at 180 degree or PI radians. So a full-circle extends further and just ends at 2*PI or 360 degrees. This exact concept can be used to draw a circle using arc method.

  // Step 1. Invoke path method
ctx.beginPath()

// Step 2. Creating a circular path
// x = 300
// y = 320
// start angle = 0
// end angle = 360 or 2*PI
ctx.arc(300, 320, 75, 0, 2*Math.PI)

// Fill with Lavender color
ctx.fillStyle = "Lavender"

//Step 3. Now ink on canvas
ctx.fill()

Line: To draw a line between two points we use moveTo(x, y)and lineTo(x, y)methods. If we consider two points A & B with x and y coordinates respectively, then moveTo acts as a position of A on canvas, while lineTo as position of point B.

  ctx.beginPath();  // Point A
ctx.moveTo(350, 50);
// Point B
ctx.lineTo(400, 100);

ctx.strokeStyle = "DeepPink"
ctx.stroke();

Triangle: Triangle is simply three lines connected together. We are going to use a special path method called as closePath() to complete our triangle. closePath basically adds a straight line from end coordinate to the start coordinate inside a path. If we assume a triangle is made of three points A, B & C, then we can draw our triangle like:

  ctx.beginPath();

// Point A
ctx.moveTo(250, 250);

// Point B
ctx.lineTo(500, 400);

// Point C
ctx.lineTo(100, 25);

// Join C & A
ctx.closePath()
ctx.strokeStyle = "Navy"
ctx.stroke();

So that’s it! Creative Coding is a lot more involved and we are just scratching the surface. In next few articles we will look at adding randomness, noise, vectors, and many more concepts, to generate an artwork. So stay tuned!

CodePen below provides complete sample of all the code mentioned in this post:

A bonus pen with all the basic elements placed with pleasing colors:


Since I have started exploring my understanding of basic maths have flourished. I’ve always wondered where am I going to apply concepts of physics, geometry and complex algorithms that I have learnt in school. Now I guess I have an answer!

Resources

  1. Canvas API on MDN
  2. Apple’s Documentation on Canvas
  3. Coding Train channel on Youtube

Let your creative spirits go wild and generate something awesome!

Namaskar 🙏🏾

JavaScript in Plain English

Learn the web's most important programming language.

Varun Maliwal

Written by

Building Koonchi | Software Engineer | Entrepreneur

JavaScript in Plain English

Learn the web's most important programming language.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade