You can use a cardinal spline to smooth out lines like this:

The cause is as @Pointy already explained due to how fast the browser is able to respond to the events (mousemove
). There is an API called Pointer Lock API which might help solve this in the future as it is more low-level, but for now we need to use algorithms to smooth out lines appearing segmented due to this.
In addition to smoothing there is detail-smoothing, point reduction, taper and other things that can be applied to improve the result.
But in this particular case you can use the following function which I made as an extension to the canvas. Just call it:
ctx.curve(myPointArray, tension, segments);
ctx.stroke();
The array contains your x and y points ordered like [x1, y1, x2, y2, ... xn, yn
.
A typical value for tension
is 0.5. segments
(default 16) is optional.
The more tension the more round the curve will appear. Segments are the resolution between each point in the array. For drawing application a value of 5 might work fine (less resulting points).
To make it work better you could register your points on a separate canvas where you draw the original line. At mouse up process the line with this function and draw it to the main canvas and then clear the drawing canvas.
This function is highly optimized - it also returns the processed points so you can store the result instead of re-processing every time.
/**
* curve() by Ken Fyrstenberg (c) 2013 Epistemex
* See Code Project for full source:
* http://www.codeproject.com/Tips/562175/Draw-Smooth-Lines-on-HTML5-Canvas
*/
CanvasRenderingContext2D.prototype.curve = function(pts, ts, nos) {
nos = (typeof numOfSegments === 'undefined') ? 16 : nos;
var _pts = [], res = [], // clone array
x, y, // our x,y coords
t1x, t2x, t1y, t2y, // tension vectors
c1, c2, c3, c4, // cardinal points
st, st2, st3, st23, st32, // steps
t, i, l = pts.length,
pt1, pt2, pt3, pt4;
_pts.push(pts[0]); //copy 1. point and insert at beginning
_pts.push(pts[1]);
_pts = _pts.concat(pts);
_pts.push(pts[l - 2]); //copy last point and append
_pts.push(pts[l - 1]);
this.moveTo(pts[0], pts[1])
for (i = 2; i < l; i+=2) {
pt1 = _pts[i];
pt2 = _pts[i+1];
pt3 = _pts[i+2];
pt4 = _pts[i+3];
// calc tension vectors
t1x = (pt3 - _pts[i-2]) * ts;
t2x = (_pts[i+4] - pt1) * ts;
t1y = (pt4 - _pts[i-1]) * ts;
t2y = (_pts[i+5] - pt2) * ts;
for (t = 0; t <= nos; t++) {
// pre-calc steps
st = t / nos;
st2 = st * st;
st3 = st2 * st;
st23 = st3 * 2;
st32 = st2 * 3;
// calc cardinals
c1 = st23 - st32 + 1;
c2 = st32 - st23;
c3 = st3 - 2 * st2 + st;
c4 = st3 - st2;
res.push(c1 * pt1 + c2 * pt3 + c3 * t1x + c4 * t2x);
res.push(c1 * pt2 + c2 * pt4 + c3 * t1y + c4 * t2y);
} //for t
} //for i
l = res.length;
for(i=0;i<l;i+=2) this.lineTo(res[i], res[i+1]);
return res;
} //func ext
See this answer for an implementation of a cardinal spline.