A few years ago I made a Javascript script for APNGedit to draw the Laughing Man logo. It used the now defunct mozTextAlongPath
I recently rediscovered this script and redid it using translations, rotations and fillText(). However, this doesn’t respect character width nor is it kerned (it looks terrible).
Original circa 2009 (not perfect, but okay):

Current version:

How can I draw text in an arc on an HTML5 canvas and make it look good?
Solution Code based on Kolink’s answer:
ctx.fillStyle = primaryColor;
ctx.font = fontSize + 'px ' + fontFamily;
var textWidth = ctx.measureText(text).width,
charRotation = 0,
character, charWidth, nextChar, nextWidth, bothWidth, kern, extraRotation, charSegment;
for (var i=0, l=text.length; i<l; i++) {
character = nextChar || text[i];
charWidth = nextWidth || ctx.measureText(character).width;
// Rotate so the letter base makes a circle segment instead of a tangent
extraRotation = (Math.PI/2) - Math.acos((charWidth/2) / radius);
ctx.save();
ctx.translate(radius, h/2);
ctx.rotate(charRotation);
ctx.translate(0, -textRadius);
ctx.rotate(extraRotation);
ctx.fillText(character,0,0);
ctx.restore();
nextChar = text[i+1] || '';
nextWidth = ctx.measureText(nextChar).width;
bothWidth = ctx.measureText(character+nextChar).width;
kern = bothWidth - charWidth - nextWidth;
charSegment = (charWidth+kern) / textWidth; // percent of total text size this takes up
charRotation += charSegment * (Math.PI*2);
}

Obviously, it is no difficulty to place letters on the arc itself (just align center bottom to the circle). However, as you noted, the problem is kerning.
Luckily, we have
measureText(), which can tell us the width of the letters and therefore what kerning to use.The circumference of your circle is simply
2πr, and total width of the text isctx.measureText("Your text here");. Get the ratio of these two values and you will find out how much you need to space out or squash together your words.You probably want to apply the spacing modifier to the words as a whole, rather than the individual letters. To do this, use
measureText()on the sentence with spaces stripped to get the width of the letters (and by extension the total width of the spaces).Now you need to plot where each word will go. Use
measureText()again to find the width of each word and plot its center point on your circle, adding a portion of the total space value between each word. Now usemeasureText()on each individual letter and draw it in the right place to get perfect kerning.All being well, you should have a perfectly spaced circle of text.