In this post, we will dive right in and compare using e2d vs direct canvas.

Getting started with e2d

Install e2d or use e2d.js at requirebin to try it!

npm install --save e2d

How do we compare?

Let's take a look at a few side by side comparisons and the benefits/downsides to using e2d vs pure canvas.

A Hello World Example

The hello world example shouldn't exactly be a deciding factor, but consider the following example:

e2d requires a bit of setup too.

Getting the Mouse Position

In VanillaJS, set up an event listener and capture the mouse position using the getBoundingClientRect() function, e.clientX, and e.clientY properties.

  let canvas = document.querySelector('canvas');
let mousePosition = {x:0,y:0};
canvas.addEventListener('mousemove', function(e) {
   let rect = canvas.getBoundingClientRect();
   mousePosition.x = e.clientX - rect.left;
   mousePosition.y = e.clientY -;

To get the mouse position in e2d, use the renderer.mouseData.x and renderer.mouseData.y properties.

  let { x, y } = renderer.mouseData;

Comparing the two, we can see that VanillaJS ends up being less code over all. This is because e2d does many more things under the hood. For Example, e2d enables "custom transformed polygonal mouse regions." To see the code, take a look at this on line 937.

Hit regions are Path2d objects in pure canvas. See here.. addHitRegion has little support in today's browsers, but e2d tries to fix the problem in a big way. User interaction with the mouse on canvas is one of the main reasons to use it.

Event propagation is another thing to consider with mouse events. These problems are left as an exercise to the reader.

Following the Mouse

Now that we have mouse position, let's use these objects and make a circle follow the mouse.

This is a lot of code to get started, and most of it is boiler-plate, but it works.

Now we get the e2d comparison.

The biggest upside to this approach is default parameters. A full arc(0, 0, radius, 0, Math.PI * 2) is actually fillArc(radius) in e2d instead of the difficult-to-remember VanillaJS approach.

Another upside to this approach is ditching the save() and restore() function calls. These functions copy the entire CanvasRenderingContext2D object's properties and push them to a stack. Internally, e2d only does a setTransform vs a full context save() or restore(). When using VanillaJS, do not forget to use save/restore.

Move a Square with WASD

This is a bit more complicated. The code is messy, but each part is important.

Now we are responsible for each keycode value, each key state, event listeners, and doing some kind of action each frame based on the key state.

Instead, compare the code to the following e2d example.

Nesting transforms is FUN. rotate() is a child of translate(), and fillRect() is a child of both transforms. Visually, the indentation is html-like. We can certainly compare these function calls to React.createElement(type, props, ...children). The data flows to the component much like data flows to a React component.


Fine grain control over code is valuable because it can teach a deep understanding of Javascript.

Take a look at the following list and make a mental note of the things your canvas app needs:

  1. Transformable Polygonal Mouse Regions
  2. Immutable canvas instructions (Make a function with static canvas instructions)
  3. Touch support (e2d has touch support, and HammerJS is an alternative)
  4. Keyboard support (internally e2d uses keycode.js and it's only a few kb
  5. A virtual canvas stack (save and restore are still performant for batch operations)
  6. Implied setTransform (the transform, scale, and rotate functions work well enough without custom matrix math)
  7. Creating and mapping polygonal shapes to path instructions

If you need more than 3 of these, e2d may be the wiser choice for your team!

  let result = fillStyle('red',
  translate(200, 200,
    text("Thank you!")