You are here

SVG text vertical alignment

In a previous post I talked about my project with Dunbar Aitkens to create Glass Plate Game markers. I am using Python to directly generate SVG for this project. Mostly, this has worked exceptionally well. There is one place, however, where SVG has caused me grief… The structure of a labeled marker is a circle with some text centered in it. This is, I think, a pretty common design meme.

The "text-anchor" attribute of the "text" tag allows one to center the text horizontally: just say "text-anchor=middle" and put the anchor point at the center of the circle. Easy.

Vertically, however, is another problem. That anchor point I mentioned is glued to the font baseline of the text. Thus, the font won't be vertically centered (since for Western text the baseline is near the bottom) and the text definitely won't be vertically centered (since depending on what glyphs are in the text the center of the text may have nothing to do with the center of the font).

The first problem, vertically centering the font, turns out to be solvable in SVG 1.1. There's an "alignment-baseline=central" ("central"? Really?) attribute that effectively changes the baseline to the center of the font. However, reality soon sets in. No SVG renderer I can find actually honors "alignment-baseline". CairoSVG, my renderer of choice, does not; I'd be willing to change, though, if there were anything to change to.

OK, I can fix this. CairoSVG is open source. CairoSVG is written in Python, a language I'm teaching at PSU right now. CairoSVG uses, unsurprisingly, Cairo as its rendering API, an API with which I am fairly familiar. Two days later, I have patches to CairoSVG that do a half-assed job of implementing "alignment-baseline" for the "text" tag. Now I can center the font of my little marker labels on the circle vertically.

Two problems. First, I can't actually generate SVG anyone can use with this approach until upstream CairoSVG takes my patch. Second, and more importantly, this still isn't what I want. I don't want all the markers to have the same central baseline: I want the text of each marker label individually vertically centered. A fairly thorough scan of the various SVG specifications doesn't reveal anything I can use for that.

OK, let's make some stuff up. We'll add a "display-anchor" attribute for "text" elements, not part of any SVG standard, that can take values of "middle", "top" or "bottom" to specify the alignment of the actual text. We'll make the rule that if both "display-anchor" and "alignment-baseline" are present, the former takes precedence. We'll implement all this in CairoSVG. Now we can get what we want.

Now no one can render this stuff, now or in the future, unless one of two things happens. First, we could get "display-anchor" accepted as a W3C standard, which would hypothetically eventually get somebody to implement it. Or we could get CairoSVG to upstream these patches as well, so that at least folks with CairoSVG could render it.

That's where I am now. I have some lovely PDFs rendered from my non-standard SVG using my hacked up CairoSVG. I have some patches to CairoSVG that I am about to put in a pull request for.

Where I started was just hand-specifying a kludge in the Python code that would adjust the anchor-point of the text a bit lower to sort of center the text. I'm not sure I have an improvement here. Fob