Arbor web solutions

Contact

Comprehensive Guide to Using Cufón Text with Raphaël

How to add some TTF to your SVG.

Comprehensive Guide to Using Cufón Text with Raphaël

[Note: I'm starting this post with a look at a specific problem and why I chose to use Raphaël in the first place. If you want to get straight to the point, scroll down to "Using Text in Raphaël".]

I recently had the opportunity to re-create a Flash component in JavaScript. The component in question was a horizontal accordion that opened slides based on mouse hover. It looked really cool, and it de-saturated the color slide backgrounds for non-active slides. Here is the actual component I was re-building.

So, my first step was to pull out jQuery. I quickly ran across a problem, though: each slide has a title that runs vertically up the slide. I couldn't use text burned into the image, because the slide titles had to be editable by the client. I couldn't use CSS3 rotation, because the site had to support Internet Explorer, which as of version 8, doesn't know what to do with anything in CSS3.

What to do? The answer was more JavaScript. I decided to use Raphaël, a library that lets you easily make SVG canvases on a page and interact with them through standard JavaScript events. Best of all, Raphaël integrates nicely with Cufón, so you can make a Cufón font file, draw shapes from that font, and then work with them in a Raphaël canvas.

Rotation Differences

I set up a prototype that featured the vertical titles, which animated into a horizontal position at the top of the slide when that slide is active. This worked great, aside from my left-aligned text becoming center-aligned after rotation. I figured it was just a quirk of SVG, and I left it at that.

Until, that is, I switched my default text to Cufón text. Now, the .rotate('-90') command that made my default text vertical had a very different effect - the text string stayed horizontal, but each character rotated -90 degrees within that horizontal text string!

I spent hours reading everything I could find about text handling in Raphaël, SVG, and Microsoft's VML, and noticed many other people having similar problems, particularly with text alignment after rotation. Here, then, is the collected wisdom of all that searching.

Using Text in Raphaël

Ok, first set up your Cufón files. You may already be using Cufón on your site. Whether you are or not, you need Raphaël-specific Cufón files. To do this, go to the Cufón generator page and set it up like normal, but near the very bottom, look for the section titled "Customization (for 3rd party scripts only)". See the two icons to the right of the text input? The first one is for Cufón; the second is for Raphaël. Click the second icon, and the text in the input box should change to "Raphael.registerfont()". Generate the font file and save it with your other JavaScript files. I like to prefix Raphaël font files with "Raphael-" to keep them separate from my standard Cufón files. Make sure that your site is actually loading these new font files with <script> tags.

Next up, set up your Raphaël canvas. When you want to place text on the canvas, use .print() instead of .text() (check the Raphaël documentation page for syntax). You can use the same .attr() function to set attributes like fill, stroke, font-size, and more. There is one attribute that you will definitely want to use, and which the Raphaël documentation does not discuss - text-anchor. Set text-anchor to "start" to make your text left-aligned, since the default is centered. You can also set text-anchor to "end" to get right-aligned text.

Keep in mind that your custom text from .print() is not a single string - it's a "set" of paths, one for each letter. That means that setting "x" or "y" through .attr() isn't going to do anything, because .attr() on a set applies the attribute to every element of the set - the set itself doesn't have "x" or "y". Instead, use .translate() or .animate({translation: "dx,dy"}) if you want to animate the movement.

If you want to rotate text, you must include coordinates around which the text will be rotated. The rotation attribute (or the .rotate() function) assume that each object will be rotated about its center point. That's why you get the spinning letters effect when you call .rotate() on Cufón text - each path is rotating around its own center. That's also why my prototype with .text() lost left-alignment after rotation - it was rotating from the center of the text string. Specifying a rotation point moves each item being rotated the specified number of degrees around an imaginary circle, with the rotation point as its center and the distance between that point and the rotating item as the circle's radius.

So how do you figure out what to use as the point of rotation? Thankfully, with text, it's pretty simple - just use whatever you specified as the position for the .text() or .print() function. In my case, the text was positioned at 20,180, so I used that as the rotation point in my .rotate() call. When I translated the text to 60,20 on slide hover, I used those new coordinates as the rotation point to make the text vertical again before translating it back to 20,180.

Fun with Raphaël

Making the horizontal accordion took a lot of trial and error, but now that I understand what's going on behind the scenes it wasn't all that complicated. I'm looking forward to creating some animated graphs and charts with Raphaël, and I'll be sure to post any other insights I happen upon here.