danvk/dygraphs — pull request #469 by danvk (2014-11-15 21:43:05+00:00)
Title: Smooth plotter using bezier curves

Fixes #370, one of our more popular issues.

Here's what it looks like:
![screen recording 2014-11-15 at 04 08 pm](https://cloud.githubusercontent.com/assets/98301/5059302/8fe08960-6ce4-11e4-91eb-d39f4c1fd2bc.gif)

This uses cubic splines (aka bezier curves) to smooth out the lines between points. To draw a bezier curve between two points, you must also specify two control points which specify how it bends:

![300px-bezier_curve svg](https://cloud.githubusercontent.com/assets/98301/5059318/e9902fb0-6ce4-11e4-9f67-f4d7dcf5196f.png)

The problem is to determine those control points.

When you connect a bunch of bezier curves, each original point in the series has both a left control point and a right control point. To avoid forming a kink in the chart, the left control point, the series point and the right control point all need to fall on a line.

The algorithm I wound up using follows the HighCharts implementation of this. Here's how it works...

The setup is that you have a point whose left & right controls you're trying to determine. You also know the previous and next point:
![setup](https://cloud.githubusercontent.com/assets/98301/5059343/c2372b52-6ce5-11e4-9bfa-cc29469d786a.png)

Start by placing the control points α of the way along each line segment. This is the only parameter we'll need to control the amount of smoothing:
![controls on line](https://cloud.githubusercontent.com/assets/98301/5059347/caeef586-6ce5-11e4-82e1-f057ef7c754a.png)

But now we've broken the rule that the original point has to be on the line between the control points! To fix that, we shift the control points up by ∆y, which can be determined with some simple algebra:
![controls shifted](https://cloud.githubusercontent.com/assets/98301/5059351/e8266ca6-6ce5-11e4-96b1-187039feca19.png)

But this introduces a new problem: the right control point is above the data points, and so it will create an impression of a false maximum to the right of the data point. To fix this, we cap the y-value of the control points:
![controls capped](https://cloud.githubusercontent.com/assets/98301/5059354/16edd9ca-6ce6-11e4-8110-6512ba5de766.png)

But now we've re-broken that rule about being on a line. So we have to do the mirror-image adjustment to the left control point:
![controls capped and adjusted](https://cloud.githubusercontent.com/assets/98301/5059359/26939216-6ce6-11e4-9dce-66d574928a14.png)

and now we have our control points!

Hopefully the algorithm makes good sense now. I implemented this as a separate plotter in `/extras` for now, but it might make more sense to move this into core dygraphs. That would make it easier to have the smooth plots play nicely with other options like `connectSeparatedPoints`, `strokePattern` and `drawPoints`.