JavaScript library recommendation #1: two.js

in #javascript7 years ago (edited)

This is my first in the series of JavaScript library recommendation articles. I advocate for JavaScript because it is accessible and ubiquitous. In this article, I introduce a very atomic, renderer agnostic 2D drawing library that supports canvas, svg, and webgl. I use it mostly as an animation library, because its ability to integrate with so many other libraries, such as Tween.js.


Two.js

Getting started

According to their official website:

Two.js is a two-dimensional drawing api geared towards modern web browsers. It is renderer agnostic enabling the same api to draw in multiple contexts: svg, canvas, and webgl.

It's called two.js because of its tribute to the famous 3D rendering library three.js. Two.js has a very straightforward application programming interface (api), and it's the same for svg, canvas, and webgl rendering contexts. So it is fairly easy to get started.

First, download the JavaScript file and include it in your project through <script src="./path/to/two.js"></script>. Then, you are all set to go.

// get a container element to put your instance of two in it
var container = document.getElementById('two-container');
var two = new Two({
    width: 300,
    height: 300
}).appendTo(container);

// create some shapes with two's built-in methods
var circle = two.makeCircle(100,150,50);
var square = two.makeRectangle(200,150,50,50);

// you can then style your shapes in many ways
// two also accepts all valid css color attributes
circle.fill = '#abcdef';
circle.noStroke();
circle.opacity = 0.5;

square.noFill();
square.linewidth = 5;
square.stroke = 'orangered';

// then you need to tell two to render everything
two.update();

See this jsfiddle for live code.


Animate

To animate is not hard either. Two.js provides an animation loop. You will need to bind the function called each frame to the two.update() function every time it is called during the animation. It is fairly straightforward. Using the same code from above, we can add animation to it.

// you don't need to call update here because the animation loop will call it automatically
// two.update();

// and we add the following code

// bind a function to 'update'
two.bind('update',function(){
    // this function is called every time two.update() executes
  if (circle.translation.x >= 400){
    circle.translation.x = -100;
  }
  circle.translation.x += 2;
  square.rotation += 0.1;
}).play(); // don't forget to play the animation

See it live here.

We made the circle to move horizontally in a repeated manner by changing circle.translation.x. And we made the square spin by changing square.rotation. You can also animate shape.opacity, shape.scale, and even shape.fill or shape.stroke if you integrate other libraries to interpolate color values. I suggest using TinyColor for color interpolation.


Atomic

What I mean by atomic is that shapes in Two.js are manipulable to every single vertices. Vertices are essentially the atoms that make up the shapes. What this means is that it opens up doorways to a great many interesting animations that are not doable otherwise. Below, we add some animation to vertices on top of the code above.

// we need to prepare for vertices animation
// by storing original positions as their native property
square.vertices.forEach(function(vertice){
    vertice.ox = vertice.x; // ox = original x
  vertice.oy = vertice.y;
});

// bind a function to 'update'
two.bind('update',function(){
    // this function is called every time two.update() executes
  if (circle.translation.x >= 400){
    circle.translation.x = -100;
  }
  circle.translation.x += 2;
  //square.rotation += 0.1;
  square.vertices.forEach(function(vertice){
    // every vertice will animate from their original position
    // to a random direction with a random distance
    vertice.x = vertice.ox + (Math.random()-0.5)*4;
    vertice.y = vertice.oy + (Math.random()-0.5)*4;
  });
}).play(); // don't forget to play the animation

See it live here.

There are so many other things you can do with vertices. Your imagination is the limit.


Renderer agnostic

Two.js also has a magical function which interpret svg nodes and turn them into shapes in two. The other good news is, even though these are svg nodes, two.js can still renders these shapes in svg, canvas, or webgl.

To do this, we use the two.interpret function.

// get a container element to put your instance of two in it
var container = document.getElementById('two-container');
var two = new Two({
  width: 300,
  height: 300,
  type: Two.Types.canvas // render in canvas
}).appendTo(container);
var svg = document.getElementById('svggg');

// interpret svg node
// it returns a Two.Group, a group of Two.Paths
// that make up the shape we see
var graphic = two.interpret(svg);

// anchors all vertices to the center position of the group
graphic.center();
// set attributes
graphic.translation.set(two.width/2,two.height/2);
graphic.scale = 0;

// bind a function to 'update'
two.bind('update',function(){
    // this function is called every time two.update() executes
  if (graphic.scale >= 0.5){
    graphic.scale = 0;
  }
  graphic.scale += 0.001;
}).play(); // don't forget to play the animation

See it live here.

The only limitation right now is that this function is a little buggy. Sometimes vertices manipulation doesn't work, and sometimes the interpreted shape looks atrocious. But it is still a welcoming function that has a great potential. Considering two.js is in alpha right now, we can expect improvements on this function in the future.


Summing up

Two.js is a very interesting library to do animation with. It has a straightforward api, it is atomic, and it is renderer agnostic. It is also easily extensible. I have used this library with Tween.js, Howler.js and other libraries to create time-based motion graphics, and made this video entirely with web technologies. If you want to hear more about this, please comment below.

Please up and sub. Hope you enjoyed this article.


Side note

Here is the video I made with JavaScript.