You will need Javascript, but it is not as complicated as the previous examples.
All text elements have a set of corresponding interface functions for searching for each character:
http://www.w3.org/TR/SVG11/text.html#InterfaceSVGTextContentElement
The easiest way is to use getExtentOfChar(i) to find the rectangle rectangle for each character symbol. This is the approach used in the @Robert Longson example. Without all the extra event handling code, you can simplify it:
var texts = document.getElementsByClassName("backgroundRect"); var svgNS ="http://www.w3.org/2000/svg"; for (var i=0, max= texts.length; i<max; i++) { var t = texts[i]; var g = document.createElementNS(svgNS, "g"); for (var j=0, nchar=t.getNumberOfChars(); j<nchar; j++) { var r = t.getExtentOfChar(j); var re = document.createElementNS(svgNS, "rect"); re.setAttribute("width", r.width); re.setAttribute("height", r.height); re.setAttribute("x", rx); re.setAttribute("y", ry); g.insertBefore(re, null); } t.parentNode.insertBefore(g, t); }
http://fiddle.jshell.net/T5qWb/1/
The limitation is that the bounding rectangle is the narrowest rectangle that will contain the letter in the original horizontal and vertical coordinates, and not the rotating rectangle, and therefore the rectangles are larger than the letters and overlapping ones.
To define a bounded rectangle, you need to use .getStartPositionOfChar(i) , .getEndPositionOfChar(i) and some geometry:
var texts = document.getElementsByClassName("backgroundRect"); var svgNS ="http://www.w3.org/2000/svg"; for (var i=0, max= texts.length; i<max; i++) { var t = texts[i]; var g = document.createElementNS(svgNS, "g"); g.setAttribute("class", "textBackground"); for (var j=0, nchar=t.getNumberOfChars(); j<nchar; j++) { var p = document.createElementNS(svgNS, "path"); var start = t.getStartPositionOfChar(j), end = t.getEndPositionOfChar(j), height = parseFloat(getComputedStyle(t)["fontSize"]), vector = [(end.x - start.x), (end.y - start.y)], aspect = height / Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1]), normal = [vector[1]*aspect, -vector[0]*aspect]; var d = ["M", [start.x, start.y], "l", normal, vector, [-normal[0], -normal[1]], "z" ].join(" "); p.setAttribute("d", d); g.insertBefore(p, null); } t.parentNode.insertBefore(g, t); }
http://fiddle.jshell.net/T5qWb/2/
I use <path> instead of <rect> this time, using relative coordinates to draw straight lines along the baseline of the character, and then 1em up 90 degrees along that line. This positions each base of the rectangle in your text path, but does not cover the "descenders" of the letters.
To do this, I decided that it would be easier to go back to the <rect> elements and use transforms to place the rectangles. I translated the rectangle to the starting point, rotated it based on .getRotationOfChar(i) , and then translated it from the baseline. The only limitation is that I had to hard code in evaluating how much of the height of the character should be below the base, because I could not calculate any method to calculate this for a given font.
var texts = document.getElementsByClassName("backgroundRect"); var svgNS ="http://www.w3.org/2000/svg"; for (var i=0, max= texts.length; i<max; i++) { var t = texts[i]; var g = document.createElementNS(svgNS, "g"); g.setAttribute("class", "textBackground"); for (var j=0, nchar=t.getNumberOfChars(); j<nchar; j++) { var re = document.createElementNS(svgNS, "rect"); var start = t.getStartPositionOfChar(j), end = t.getEndPositionOfChar(j), angle = t.getRotationOfChar(j), height = parseFloat(getComputedStyle(t)["fontSize"]), vector = [(end.x - start.x), (end.y - start.y)], width = Math.sqrt(vector[0]*vector[0] + vector[1]*vector[1]), aspect = height / width, normal = [vector[1]*aspect, -vector[0]*aspect], baseline = 0.2; re.setAttribute("height", height); re.setAttribute("width", width); re.setAttribute("transform", ["translate(", [start.x, start.y], ")", "rotate(", angle, ")", "translate(0", -height*(1-baseline), ")" ].join(" ") ); g.insertBefore(re, null); } t.parentNode.insertBefore(g, t); }
http://fiddle.jshell.net/T5qWb/3/
It is tested and all interface methods are implemented and work as expected in the latest browsers Chrome and Firefox and IE11 / 10/9 (through the developer emulator).