Displacement
There are at least two ways you can achieve a curved text effect - both share the same principle of displacement of pixels (moving them out of position relative to their real position), it's just a matter of which method we use to do this.
In the following demo I will use simple slicing using the internal drawImage
method. Optional we could have iterated the pixel buffer and manually projected the pixels but for cases such as this it's simpler to use slicing IMO and we get anti-aliasing for free.
Example + demo
Here is a full example (see demo for sliders and custom text) on one way of doing this:
ONLINE DEMO HERE
The result will be:
var ctx = demo.getContext('2d'), /// get canvas
font = '64px impact', /// define font
w = demo.width, /// cache width and height
h = demo.height,
curve, /// curve for our text
offsetY, /// offset from top (see note)
bottom, /// bottom origin
textHeight, /// height of text
angleSteps = 180 / w, /// angle steps per pixel
i = w, /// counter (for x)
y,
os = document.createElement('canvas'), /// off-screen canvas
octx = os.getContext('2d');
/// set off-screen canvas same size as our demo canavs
os.width = w;
os.height = h;
/// prep text for off-screen canvas
octx.font = font;
octx.textBaseline = 'top';
octx.textAlign = 'center';
/// main render function
function renderBridgeText() {
/// snipped... get various data (see demo for detail)
/// clear canvases
octx.clearRect(0, 0, w, h);
ctx.clearRect(0, 0, w, h);
/// draw the text (see demo for details)
octx.fillText(iText.value, w * 0.5, 0);
/// slide and dice (MAIN)
i = w;
while (i--) {
/// calc distance based on curve (=radius) and x position
y = bottom - curve * Math.sin(i * angleSteps * Math.PI / 180);
/// draw the slice for this vertical line
ctx.drawImage(os, i, offsetY, 1, textHeight,
i, offsetY, 1, y);
}
}
Note on offset: offset can be many things - in this demo I let it be the top source of the text to "correct" the curving a little as texts aren't drawn at the very top (due to various glyph geometry which I'm not gonna into here) - you will see this clearly between Chrome and Firefox as the text is rendered differently.
The demo let you change text and adjust a few parameters so you can see what effect they have on the text.
How it works
The width is divided first on number of pixels we want to displace on the x axis. This gives us the delta angle we need to use for each pixel step.
Then we calculate a basic distance based on angle for y-axis using sinus using curve as radius. As the delta angle now corresponds to an angle from 0 to 180 based on x position this will gives us a nice curve matching the text width which is drawn in center.
This value we subtract from bottom to get the y position for the bottom of text.
Then we pick a normal sized slice from the source, one pixel thick, and we scale it to destination based on the y value. This does the trick.