Reputation: 14334
I am working on a project where I have to create design assets dynamically in the browser. For the past few months I have been using canvas to do this, but I am now being asked if I can create vector based assets directly from the client.
After investigating HTML5 SVG, it seems like I might be able to do this, and after playing around with raphael.js and svg.js, I decided I like svg.js better. Much more lightweight, and < IE9 support is not an issue for me.
My main concern with using SVG is that I have to render text to my svg's, and have the text vector based and available in the final asset. Not only this, I need to be able to perfectly measure the text's bounding area (to the nearest pixel). In this I see 2 problems:
Just using a standard draw.text()
call to create a <text>
element is no good as it means I must bundle the font with the asset, which is not possible due to licensing reasons.
Calling text.bbox()
to get the bounding area of a text element is inaccurate when it comes to height. I believe it simply returns the height for the tallest/lowest characters in the font rather than the characters actually being used, much like getClientRect()
does with standard html elements.
I see a solution which could solve these problems, and this is where I am looking for advice:
I believe I could manually render glyphs using draw.path()
with path information pulled from an SVG font. This way my final asset will have vector based glyphs in it which are not tied to any font, and hopefully a call to bbox()
after drawing a path is more accurate than with text.
Does anyone know if is it possible to pull any of this glyph information using svg.js? Or must I do that manually by parsing the xml and pulling the path information out of there? Also does anyone have any idea on how kerning could potentially work in this situation? Or even better do you know any other way of solving problems 1 & 2 above without doing this manual and complicated method?
Upvotes: 2
Views: 2554
Reputation: 457
Take a look at https://stackoverflow.com/a/19057523/2183503. Opentype.js can be used to parse OpenType and TrueType fonts.
Using opentype.js, one can get a path that can be used to draw using the HTML5 canvas:
var font = opentype.parseFont(arrayBuffer);
var path = font.getPath("Hello, World!", {x:0, y:150, fontSize:72});
path.draw(ctx);
As said in that answer, the demo website at http://nodebox.github.io/opentype.js/ has a live example.
Upvotes: 1
Reputation: 72465
I've taken a half hearted attempt at this before, it is indeed possible but not straightforward. To extract information font the SVG Font XML you need to...
document.querySelector("glyph[unicode=a]").getAttribute("d");
This will get you the path of letter a
. However, this path is in a different coordinate system, from w3c:
Unlike standard graphics in SVG, where the initial coordinate system has the y-axis pointing downward (see The initial coordinate system), the design grid for SVG fonts, along with the initial coordinate system for the glyphs, has the y-axis pointing upward for consistency with accepted industry practice for many popular font formats.
This means that you will have to transform the coordinates from one system into the other (this in itself shouldn't be too hard) and then scale it to the desired size
Then you must paint the next letter after the first one, there's horiz-adv-x
attribute of glyphs which you must also scale according to the text size. Even though SVG fonts account for kerning, in practice none of the browser engines that support SVG Text implement it, so spacing doesn't vary according to glyph pairs.
Depending on your specific requirements this process can go from easy to nightmarish. You can end up implementing a mini-text rendering engine if scope creeps up.
Upvotes: 4