Detailing the issue

The core problem

It all boils down to one critical issue:

With the current SVG 1.1 (and draft 1.2) standard there is no way to statically find out the bounding box of an arbitrary text string for later usage in the SVG script.

This very surprising omission in the SVG standard makes it in principal impossible to even do such a simple thing as drawing a frame around a text programatically since there is no easy way to find out the size, in the given coordinate system, of the string.

Since the actual bounding box is dependent on both font, style, size, etc as well as the actual SVG viewer text-layout engine implementation this calculation cannot be done outside the viewer. It must be part of the SVG standard elements.

Note

Now, anyone who are familiar with SVG would jump in here and point out that this is not entirely correct. For the specific case of a frame around a text it would be possible to use a filter function as specified by the standard but that is a special case that just could be used to draw an effect that looks like a frame around a text (using the objectBoundingBox property). It is still not possible to find out the bounding box.

The second approach would be to to add some DOM Javascript code in the SVG script which upon execution of the script could in theory find out the bounding box and adjust suitable attributes in the script.

Why is this a problem ?

There are many places in the library where it is absolutely essential to find out the bounding box of a text string to adjust the position of other object in the graph. For example margins for titles, column width in gantt charts and legends and so on. Without this functionality it will be impossible to add SVG output without significantly reducing the functionality and in essence create a new version of the library suitable for this reduced functionality that is brought upon us by the use of SVG.

Possible workarounds

Looking at this from a more positive view instead of explaining why it cannot be done there are in principal only two workarounds (neither which is a 100% solution)

  1. Using a single fixed font. Restricting the library to one specific fixed font would make it possible to calculate the bounding box for the string. Due to differences in the existing viewers it would be necessary to have some safety margins built in when doing this calculation. However this would significantly impact the visual appearance of the graphs.

  2. Using heuristics By establishing some "good enough" heuristics for a plain font we can try to find a guesstimate of the size of the string. Unfortunately it is a big difference in length between "iiiii" and "wwwww" even though they have the same number of characters. So without fully implementing the same algorithm as some SVG viewer text-layout engine uses this method cannot guarantee that the text will always fit without making the box fit the worst case. In addition this method will have some difficulty in handling rotated text strings.

What would be required ?

What would be required in the standard to solve this is a new basis element which could be used to record the bounding box of a particular text string for later reference. To just give some idea on what is needed some "pseudo-SVG" that we would need is something along the lines of:

1
2
3
4
5
6
7
8
9
10
<def>
  <boundingbox id="bb1" 
               text="This is a text" style=" />
</def>
<rect x="50+#bb1.x1-10" y="50+#bb1.y1-10" 
      width="#bb1.width+20" 
      height="#bb1.height+20" />
<text x="50" y="50" >
  <tref xlink:href="#bb1" />
</text>

The basic idea is that in the def-section all text strings to later be used in the script is defined together with the font (and any other formatting applicable). These text strings are defined in the new SVG element "boundingbox" which will calculate the bounding box of the given text. These text string is later referenced in the actual text with a standard tref element. The bounding box attributes can then be used in the positioning of the text with a "#" reference based on the id of the new introduced element "boundingbox" The above script would then draw a text string positioned at (50,50) with a frame around it with a 10 units margin all around.

DOM scripting and GetBBox()

Since we make no claim to be experts in all aspects of the SVG standard (which is fairly big) it might be possible that there is some way to still solve this that has eluded us so we would be very interested in getting a second opinion of these findings. We are aware of the SVG method GetBBox() but this would not work in the library very well. The reason is that this is not a static function but requires the context of a DOM script. This would require a substantially rewrite of the library since there are graphs where every single coordinate would have to be back-patched in the end (possible in multiple passes - since the calculation of one bounding box would be needed to adjust another element).

This means that the script would no longer be static but would require the library to generate "self-modifying" DOM script at the end. The logic of the library assumes that the bounding box of text can be found out at the place of creation and then this bounding box can be used to adjust subsequent coordinates.

So to summarize this we do not feel that the potential back patching of every single element in the SVG image at the end in a DOM script is a solution.

A final comment

Since we still find it very hard to believe this giant oversight in the standard we would be happy to receive comments on these conclusions.