Painting with Pixels

Want to break into using JS creatively and don’t know where to start? Creating a painting program is a fun and easy way to ease yourself into it. With this tutorial I’ll step you through the process of writing a drawing program. Our drawing program will have multiple swatches to allow for pretty colors and a clear button. Best of all is that we’ll use the Data URIs to save the drawing as an image… all without ever needing any server side code!

To keep things nice and simple I’ll post all the examples on JSFiddle step by step. Play around, break them and make them your own!

Setting up

Take a look at my first fiddle here. I created a canvas element on the screen with an id of drawingPad and gave it a nice border around it so a user knows where the drawing area begins and ends. Lastly I added in this code:

1
2
var canvas = document.getElementById("drawingPad");
var context = document.getContext("2d");

Right now our code doesn’t do too much. This code basically says “Hey browser! When you’re good and ready, go ahead and keep track of our drawing pad in a variable aptly named canvas. Use variable context to store the canvas’ 2D context.” NBD, right?

Mouse Events

The next thing I’ll need to do is set up a way to tell when the user is on the canvas and drawing. After all, our program needs to know where to draw and when to draw right? To do that we’ll keep track of the position of the mouse in JS. When the user presses the mouse button down inside of the canvas tag drawing will begin. When they let go of the mouse drawing will end.

Take a look at the Fiddle here. There’s no change to the HTML or CSS but the JS got a little more complicated. So what’s going on here?

First, I set up a few more variables.

1
2
3
var isMouseDown = false;
var mouseX = 0;
var mouseY = 0;

These are pretty straightforward, right? I’ll change the isMouseDown to true when a user pushes the mouse button down and back to false when they let go. Along the way I’ll change the mouseX and mouseY variables to their mouse coordinates. As the user interacts with my program I update these variables so I know when and where to paint.

To update the variables I need to detect mouse movement and interaction. The code looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// when the user presses their mouse down on the canvas.
canvas.addEventListener("mousedown",function (evt) {
    isMouseDown = true;
 
    mouseX = evt.offsetX;
    mouseY = evt.offsetY;
});
 
// when the user lifts their mouse up anywhere on the screen.
window.addEventListener("mouseup",function (evt) {
    isMouseDown = false;
});
 
// as the user moves the mouse around.
canvas.addEventListener("mousemove",function (evt) {
    if (isMouseDown) {
        mouseX = evt.offsetX;
        mouseY = evt.offsetY;
    }
});

The one gotcha to this code is that we want to track when a user lifts up their mouse cursor anywhere in the window, not just inside of the canvas tag. This will make sure that users who draw right to the very border of the window don’t see a bug like the drawing continue to draw even after they’ve let go of the mouse button.

Clearing the canvas

Clearing the canvas requires way more HTML and CSS than it does JS, as the next Fiddle proves. The only JS required is

1
2
3
4
5
6
7
8
9
// when the clear button is clicked
var clearBtn = document.getElementById("clear");
clearBtn.addEventListener("click",function(evt) {
    canvas.width = canvas.width; // this is all it takes to clear!
 
    // make sure the canvas' background is actually white for saving.
    context.fillStyle = "#ffffff";
    context.fillRect(0,0,canvas.width,canvas.height);
});

Drawing at last!

So I need to actually draw to the canvas in order to see anything… but how do I do that? This new Fiddle lets you finally play around and see something! The best part is that we only needed a few lines of code to pull that off. Remember that 2D context thing we set up earlier? There’s only a few commands you need to know to draw on your canvas with it.

First there’s strokeStyle. This is all we need to say what color line we want to draw. It looks like this:

1
context.strokeStyle = "#000000";

Next, there’s beginPath and moveTo. This line of code is the equivalent of picking up a pen and moving it to a different place on a piece of paper. That “place” is defined as an x coordinate and y coordinate, like so:

1
2
context.beginPath();
context.moveTo(x,y);

When a user presses down on the mouse I’ll use the moveTo command to make sure I start their drawing from where their current mouse position is.

Finally when I want to actually draw the line I use lineTo to draw a line from the current pen position to a new X and Y and then stroke to see the line on the canvas.

1
2
context.lineTo(x,y);
context.stroke();

Adding in swatches

My painting program could be livened up a bit by allowing users to choose different swatch colors. With this next fiddle we do just that. For the first time since we started we added a bit of code to the HTML and CSS side of things.

The first thing I did was added in HTML with a list of swatches. Each swatch has their own background color listed in it. The CSS defines that each li element will be nice big squares that change the mouse cursor on rollover. I also added in a li.active selector which changes the border color of the swatch. Using JS I can change both the strokeStyle and add that class to the li when clicked. That code looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// swatch interactivity
var palette = document.getElementById("palette");
var swatches = palette.children;
var currentSwatch; // we'll keep track of what swatch is active in this.
 
for (var i = 0; i < swatches.length; i++) {
    var swatch = swatches[i];
    if (i == 0) {
        currentSwatch = swatch;
    }
 
    // when we click on a swatch...
    swatch.addEventListener("click",function (evt) {
 
        this.className = "active"; // give the swatch a class of "active", which will trigger the CSS border.
        currentSwatch.className = ""; // remove the "active" class from the previously selected swatch
        currentSwatch = this; // set this to the current swatch so next time we'll take "active" off of this.
 
        context.strokeStyle = this.style.backgroundColor; // set the background color for the canvas.
    });
}

Saving a drawing

Now that my drawing application is so great I want to make sure users can save images out. My final fiddle allows users to save the file straight to their hard drive.

To do this I added in my save button and then added this to the bottom of my script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// when the save button is clicked
var saveBtn = document.getElementById("save");
saveBtn.addEventListener("click",function (evt) {
    // we'll save using the new HTML5 download attribute to save the image. 
    // we'll give the image a name of draw-[timestamp].jpg
 
    var now = new Date().getTime(); // get today's date in milliseconds.
    var dataUri = canvas.toDataURL("image/jpeg");  // get the canvas data as a JPG.
 
    // change the a href and download attributes so it'll save.
    this.setAttribute("download","drawing-" + now + ".jpg");
    this.setAttribute("href",dataUri);
 
    // in older browsers you may need to substitute those last two lines of code with this:
    // window.open(dataUri,"_blank");
});

When the user clicks the save button I store the current date in milliseconds in variable now. Then I create another variable dataUri, which I use to create a JPG from the canvas tag. Finally I change the attributes of the a tag I just clicked to set the new download attribute to point to the JPG I just created and viola! The file saves to the users’ system. As I mention in the code comment, the download attribute is pretty new and you may need to substitute that with opening a window to see the result.

Making sure the JPG has a background color.

There’s one gotcha to our saving – something I took care of in the last Fiddle but need to highlight. While the web browser has a white background color that allows us to see what we’re doing, technically we’re drawing on a transparent background in our canvas right now! Wouldn’t make for much of a JPG, would it?

To fix this I this I added in these lines of code to our clear function:

1
2
context.fillStyle = "#ffffff";
context.fillRect(0,0,canvas.width,canvas.height);

These simply make sure the whole canvas has a white background. Our drawings save out and look beautiful like this:

Painting w/ Pixels

Wrapping up

Creating tools that let people draw and explore is a fun way to get to know HTML5 and Canvas a bit better. Why, with a little work you could even get pretty close to something approximating Photoshop!

The whole the Data URI thing is especially mind blowing: The idea that a file can be stored in a string is crazypants. You could take that in so many directions: Create a multifile form uploader, generate any kind of file you can think of entirely in JS, even connect canvas closer to other things outside of the browser (like openFrameworks) to do creative code stuff. I even know a guy who made an awesome super useful Data URI addon so you could play around with that.

Creative coding is as much about being playful and fun as it is artistic and expressive. Don’t be afraid to jump in and teach yourself something. Have fun!