Search This Blog

A Barely Adequate Guide to JavaScript Canvas

Whenever I want to add a new feature to this blog, I write a post describing the process of researching and implementing that feature first. I've done two Barely Adequate Guides so far, one on syntax highlighting with JavaScript and one on JavaScript charts. The goal with these guides is twofold. First, I get to document what I'm learning about how to implement these features for future reference. Second, it shows at least one way of researching, choosing, and working with a new software library starting from square one.

Nearly everything we do as programmers has already been done before. Maybe not exactly in the same way as we're trying to do it this time, but pretty much every component that makes up any given project already exists in some form out on the Internet already, probably in more than one library. That means we have a choice as to how to spend our time. We can either write that component from scratch and know exactly how it works, or we can find a library and integrate it into our project. Each method has its benefits and costs, and I normally will spend at least a small amount of time looking for a ready-made solution. If I can find one quickly, it's robust, and it has a decent API, I can save a lot of time by programming at a higher level than I would otherwise.

An Initial Search


For this Barely Adequate Guide, I want to learn about the HTML5 canvas and start using a JavaScript library that makes using the canvas even easier. I'm planning some articles that will make good use of animated drawings, and it should prove useful for future posts as well. I start, as I always do, with a Google search:

Google Search: javascript canvas

I start with the basic "javascript canvas" search terms to see what comes up. (By the way, I just had a great experience getting this screen cap. I switched from Windows to Linux about half a year ago, and this is the first time I did a SHIFT-PrintScreen. The cursor turned into a cross-hairs and I selected an area to capture. Then a dialog box appeared where I could name the file and choose where to save it. This is a way better experience than having to muck around with Paint on Windows. Linux: 1, Windows: 0.) Here are the top ten results:
  1. Canvas tutorial - Web API Interfaces | MDN
  2. HTML5 Canvas - W3Schools
  3. HTML Canvas Reference - W3Schools
  4. HTML Canvas - W3Schools
  5. HTML Canvas Coordinates - W3Schools
  6. Canvas - Dive Into HTML5
  7. HTML5 Canvas Element Tutorial - HTML5 Canvas Tutorials
  8. Fabric.js Javascript Canvas Library
  9. Drawing on Canvas :: Eloquent JavaScript
  10. Canvas element - Wikipedia, the free encyclopedia 
This looks like a lot of HTML5 canvas stuff. I dive into the first link, but it looks like a lengthy tutorial so I back out. It's from the Mozilla folks and it's probably good, but I don't want to spend that much time right now. The next link leads me to a brief description of the HTML5 canvas with some code samples. After scanning through the samples, it's clear that most of the interaction with the canvas is already done through JavaScript, but I want something with higher-order functionality that will make drawing and animation even easier.

I skip past the other HTML5 links and take a look at the Fabric.js library. This looks promising. The Fabric.js library appears to have a lot of features, good documentation, and active support on Github. I take note and look at the next link. It's actually a chapter out of a free online book called Eloquent JavaScript. It looks quite good, but not what I need right now so I bookmark it and keep searching. With the tenth link, I've reached the end of the first page of search results, learned a bit about the canvas, and found one higher-level library.

Refining the Search


I could continue paging through the results, but I think I'll have better luck refining my search.

Google Search: best javascript canvas library

That's right. I want the best. I figure by using the 'best' search term, I'll get at least a few links that will rank or review different JavaScript libraries. I wasn't disappointed:
  1. My Favorite 5 JavaScript Canvas Libraries • Crunchify
  2. html5 - Current State of Javascript Canvas Libraries? - Stack Overflow 
  3. powerful javascript canvas libraries - Stack Overflow
  4. EaselJS | A JavaScript library that makes working with the ...
  5. What are the best JavaScript drawing libraries? - Slant
  6. 10 Cool JavaScript Drawing and Canvas Libraries - SitePoint
  7. Fabric.js Javascript Canvas Library
  8. Chart.js | Open source HTML5 Charts for your website
  9. Brief Overview of HTML5 Canvas Libraries - JSter Javascript ...
  10. Pixi.js - 2D webGL renderer with canvas fallback
It looks like six of the top ten results are rankings or reviews of JavaScript canvas libraries. Then there are three sites for popular canvas libraries (EaselJS, Fabric.js, and Pixi.js) and another site for a JavaScript chart library that happens to use the canvas but is not a general purpose drawing library. The second and third links catch my eye because they're from Stack Overflow, a reliable programmer's resource even if they tend to close these types of questions.

The second link leads me to a comparison table of JavaScript canvas libraries in a Google doc. It looks a little out of date and doesn't have too many different comparison points, but it's still useful to browse through. I find Pixi.js, EaselJS, and Fabric.js at the top of the list again, along with Paper.js. Both Paper.js and Fabric.js appear to be much larger than the other two libraries, although Fabric.js is more modular so it's potentially comparable to the smaller libraries if I only use the core of it.

I follow the links to each library's website, and I find that they all have demos, example code, and documentation ranging from good to great in quality. With the short time that I spend on each site, I feel that Paper.js and EaselJS have a bit more complicated API, while the Pixi.js and Fabric.js APIs look immediately familiar. Then I visit each of the GitHub repositories to get a sense of how active and popular the libraries were. They all seem to be well maintained with regular and recent checkins and good notes in the readme files for getting started. Pixi.js has by far the most watchers, stars, forks, and contributors, with the other three libraries having similar stats to each other for the most part.

Between its potential ease of use, small size, and popularity, I decide to go with Pixi.js. I wouldn't normally go with the crowd so quickly when choosing a library, but in this context it's a reasonable course of action. If this decision was for a more complex project that depended on a drawing library for its success, I would do a more in-depth analysis and probably experiment with all of the top contenders, but for using a library with this blog, any of these libraries would likely be more than adequate. I want something I can learn quickly, and I want to waste as little time as possible deciding which library to use so I can start learning the library sooner. Clear code examples and popularity are a decent first-order proxy for a detailed evaluation in this case.

Experimenting with Pixi.js


The first thing I need to do to start playing with Pixi.js in my blog is to load the JavaScript library. I can either load the source file from https://cdn.rawgit.com/GoodBoyDigital/pixi.js/dev/bin/pixi.min.js or clone the git repo from https://github.com/pixijs/pixi.js, host the pixi.min.js myself, and load it from that location.

One easy way to host JavaScript files is to set up GitHub Pages with this tutorial, make a javascript folder to dump in any JavaScript files you want, and push them up to GitHub. Then you can source the files from your own <username>.github.io URL. I chose to load the source from the main GitHub project, so I added this line within the <header> tag of my Blogger template:
<script src='https://cdn.rawgit.com/GoodBoyDigital/pixi.js/dev/bin/pixi.min.js' type='text/javascript'/>
With the library loaded, I can start experimenting with drawing shapes on a canvas. Let's start with drawing a simple line. On the examples page on GitHub there's a Graphics example with sample code. Pulling out the necessary setup code and the code to draw a single line gives me the following first attempt:
<div id="canvas-line" style="width: 550px; height: 400px">
</div>
<script type='text/javascript'>
 var canvas = $('#canvas-line');
 var renderer = PIXI.autoDetectRenderer(canvas.width(), 
                                        canvas.height(), 
                                        { antialias: true });
 canvas.append(renderer.view);

 var stage = new PIXI.Container();

 var graphics = new PIXI.Graphics();

 graphics.lineStyle(10, 0xffd900, 1);
 graphics.moveTo(50,50);
 graphics.lineTo(500, 300);

 stage.addChild(graphics);

 animate();

 function animate() {
  renderer.render(stage);
 }
</script>
The code starts out by defining a <div> with an id that I can refer to in the JavaScript code. Then the JavaScript finds the element with that id, creates a renderer and a canvas, creates a stage for adding graphics contexts, and creates the first graphics context. The graphics context is what's used to draw things, in this case a line. The line style is defined for the context and then the line is defined with a starting point and an end point. Finally, the context is added to the stage and the animate() function is called to render the drawing. The result looks like this:


Not too bad, but a bit rudimentary. Let's try something a bit more interesting. How about an oscillating sine wave. For this drawing, I'll have to add animation, but that shouldn't be too hard because animation support is already there by default in the animate function. The hardest part is constructing the sine wave from line segments. Here's the code:
 var canvas = $('#canvas-sinewave');
 var renderer = PIXI.autoDetectRenderer(canvas.width(),
                                        canvas.height(),
                                        { antialias: true });
 canvas.append(renderer.view);

 var stage = new PIXI.Container();

 var sinewave = new PIXI.Graphics();
 stage.addChild(sinewave);
 sinewave.position.x = 75;
 sinewave.position.y = 200;

 var count = 0;

 animate();

 function animate() {
  count += 0.1;

  sinewave.clear();
  sinewave.lineStyle(4, 0xff0000, 1);

  var amplitude = Math.sin(count) * 100;
  sinewave.moveTo(0, 0);
  for (var i = 0.1; i < 6.3; i+=0.1) {
    var x = i*63.5;
    var y = amplitude*Math.sin(i);
    sinewave.lineTo(x, y);
    sinewave.moveTo(x, y);
  }
  renderer.render(stage);
  requestAnimationFrame( animate );
 }
In this case I create a graphics context for the sine wave outside of the animate function and set its origin to where I want the sine wave to start. Then in the animate function, I increment a counter that determines what the amplitude of the sine wave is for the current frame and draw out the sine wave with line segments. Finally, I have to request an animation frame to advance the animation. The result looks like this:


Mesmerizing. That's not bad for a few hours of experimentation and a couple dozen lines of code. Now I can add animated graphics to my posts, and I learned a new trick to add to my repertoire. Pixi.js is a pretty deep library, and you can do a ton of different things with it. It would probably take months to become proficient with it, but getting a handle on it in a few hours was worth the time. If you're in need of graphics or animation for your website, it's a good place to start.

No comments:

Post a Comment