I've been wanting to try out some JS for a while now, as it's an incredibly popular language that I've barely touched except for data-binding stuff with Angular. I decided I'd give Canvas a go, since I've always shied away from all things graphical, front-end and animated, and I'd heard good things about various Canvas animation frameworks.

But I didn't want to use a framework. Although if I ever want to get more seriously into animation on the front-end (which I highly doubt will happen) I'll be looking more carefully at the vast array of game-making and animation platforms for JavaScript, I wanted to get a feel for Canvas's native abilities.

Drawing paths wasn't a problem, and I quickly got a feel for the various 2d-context methods such as arc, lineTo and so on. My idea was to make a Mini Metro-style game for in the browser, or at least a neat little "browser toy" -- designing game challenges or time limits didn't seem like my cup of tea.

I got the basic path-drawing stuff down pretty quickly:

But... then I had to animate the cars. I realised I didn't have a handle on the actual Path(s) being used to draw the lines; I was generating it on-the-fly with the arcTo method on the 2D context.

I didn't really feel like doing all the work of curve-interpolation (for both position and rotation) if it was all there in a hidden Path object, so I looked around and found that without changing too much code, I could apply all the lineTo, arcTo etc. methods to a Path2D object, and "stroke" (draw the outline of) that to the 2D context instead.

Unfortunately, it didn't have what I needed for animation. At this point I started feeling like I'd made the wrong choice of tech: unlike SVG, whose paths have a handy getPointAtDistance methods, Path2D objects don't have an easy way to interpolate points. In fact, they don't expose anything about themselves: it's impossible to see the individual parts of a path unless you store them yourself.

At this point, I decided to stop using arcTo and do the calculations myself. The problem is that it opaquely draws lines to and from the arc itself, meaning that unlike lineTo and arc it can encompass up to three path "segments". This is a pain for interpolating points.

My current project is a wrapper for Path2D. It will store all information about the segments added so far, and expose an API with an SVG-like getPointAtDistance, along with a getRotationAtDistance for shapes which need to rotate along the path. Essentially this will compute the gradient of the tangent at this point on the line, and convert it to an angle of rotation between 0 and 2*pi.

It's intended to be a sort-of-dropin replacement for Path2D. Instead of creating a Path2D object (or using beginPath and writing one implicitly with a canvas's 2D context), make a Path object and use its arc, lineTo etc. methods. When it comes to drawing the path or hit-detection, you'll be able to get the real Path2D object from the wrapper with a call to getPath(). (Or maybe just grabbing the path2d attribute; I'm not sure which is best practice in JS but either would work).

I'm also writing a utility class called PathFollower. It essentially just stores the current distance, and allows for the following workflow:

path = new Path();
...
follower = new PathFollower(path);
follower.advance(10);
follower.position;  // {x: ..., y: ...}
follower.rotation;  // 0 <= rotation <= 2*PI

I've looked around, and it doesn't seem like there's anything like this currently available, which surprised me: maybe most people who need this functionality are happy to use SVG or one of the heavier visualisation/game-making frameworks out there.

But hopefully this will be useful to some! It'll be a great way to learn JavaScript for me, as well as a bit of a refresher course in basic trig.