This is MathTools' SVG implementation. The classes here exactly mirror SVG tags and provide methods for setting attributes and content properly. Where possible values are constrained to prevent invalid values, whether by accident or design. Each tag has its own class (with a few limited, special-case exceptions) and the classes themselves are organized logically so that the range of attributes and options available increases 'down' the subclassing chain.
Presentation styling is done via CSS. The StylePen
, a StyleInfo
subclass, provides the basic styling options available to all tags.
It has two specialized subclasses: MarkerPen and TextPen
. The former is optimized for placing markers along paths and the latter has text-specific
methods and options. The tag classes are written specifically to separate structure from presentation: no individual attributes are used for style information.
The 'style=' attribute is an option, but the preferred way is to establish a CSS rule and use and re-use it throughout the document.
MathTools SVG, much as does the graphing.*
package, uses the metaphor of pen and paper to model its behavior. To wit, the structure elements
represent the paper with the CSS styling as the pen. There are four __Pen
classes: Style, Marker, Text, and Transform. StylePen
is
the base styling class. It has methods for setting stroke color, fill color, URLs, and other such things dealing with making the graphic look good.
A StylePen
, once configured, can be used one of two ways. The structure tags ('paper') have setStyle(StylePen)
methods that convert
the StylePen directly to a 'style=' attribute on the tag to which it is applied. This allows individual tags requiring only one or two different things to have
them without defining a CSS rule that only one or two tags might use.
For defining broad CSS rules that multiple tags will use, each pen has a setPen(int)
method for assigning a pen number. StyleTag
also specifies a setPen(int)
method, but this one is used to assign the CSS rule defined by the pen to that tag. When output as a document, the
result is something like this:
<!-- CSS Stylesheet --> .Pen_0 { stroke:blue; fill:none; stroke-width: 3; } .Pen_1 { stroke: black; fill: #888; }When added to the document,
. . .
<!-- Document Content --> <circle cx='25' cy='40' r='10' class='Pen_1' />
StylePen
assigned the pen number '1' becomes the CSS rule 'Pen_1'. Any StyleTag
assigned pen #1 has its
'class=' attribute set to 'Pen_1'. CSS made simple!
When using the various StylePen
s it is important to understand how they are actually set. The setStyle()
method and its defaults
instantly convert the pen to an immutable String, thus 'freezing' it as soon as it is added. The pen can be changed subsequently and the already-set tags
will not change! This is handy when using 'style=' attributes since it allows one pen to be re-used for all tags. On the other hand, using the pen
numbers does not freeze things, it only sets the 'class=' CSS attribute to the given 'Pen_' value and that can be changed. Under this model the pen
remains mutable until it is added to the document itself: SVGTag add(StylePen)
does this. Up until that point any changes in the pen will be
reflected in all the tags using it because setting a pen number in fact sets a reference to that pen!
The TransformPen
deserves special attention. It does not extend StylePen
and it is used for one purpose only: holding transforms. It
has methods to add each kind of transform available and it retains them, in order. Although technically transformation is more structure than presentation,
the model fit nicely so it was used. As with other pens, once added to a tag TransformPen
is 'frozen' into String form. That means the pen can be
altered later and re-used without affecting the tag(s) to which it has already been applied.
StyleTag
, in addition to setter methods for each tag class, also specifies default setters: a default style, pen number, or both can be
assigned to any subclass! So, if you are preparing to draw a lot of similar lines (or circles!), simply deside how each is to be styled, assign a pen number
and make that the default pen number for that particular class. Then, when it's no longer needed, clear the default or replace it with another. Simple!
Speaking of drawing, the DrawableContainerTag
is optimized for just such a thing. The 'container' part means that this class (tag) is used to hold
other classes (tags). For example the <svg> tag serves as the document root so of course it is a container! These classes all have 'add__()' methods for
putting graphic content where it is needed.
The 'drawable' part means that each of these classes has a set of draw__()
methods designed to take the minimum necessary information about a
tag, create an instance from it, and add it to the container's content. drawLine(X1, Y1, X2, Y2)
creates a <LineTag> with the given
points and adds it to the container in one fell swoop.
When combined, the default style setters and 'draw' methods equal one powerful and fast way to add tags to a document. Set the default pen (style declarations)
for the needed tags and go to town with it. The draw__()
methods take the minimum amount of required structural information, but they do
require sufficiency! The tag added to the container will have enough information (modulo style information, handled with default pens) to add a proper tag!
It is also worth noting that there is no reason whatsoever that both models cannot be combined. Graphics requiring large numbers of basically similar tags with
a few specials should use both creation methods: draw__()
the similar tags, which are added automatically, and create and add the special tags
individually.
The MathDrawSVG
class exists to provide tag class instances and to set defaults. It is somewhat analogous to a GraphEngine
in that
it provides what is necessary to create graphics. It is different in that it can also set default values in the form of styling and transformation pens for
each type of tag it creates. As with draw__()
methods, MathDrawSVG
also ensures that sufficient information is available to create
a tag. ClipTag
, for instance, must have a valid 'id=' attribute. This is because the <clipPath> tag lives inside the <defs>
block and cannot be referenced without a valid ID. Whenever this is the case, both the class constructors or factory methods and MathDrawSVG
make
certain the mandatory information is supplied.
For those using MathTools in a Java application it is possible to instantiate the SVG classes directly. This works, and will create tags properly, but it is
still a better idea to use MathDrawSVG
. It collects all the tag classes, pens, and default-setting methods in one class. It also performs certain
housekeeping tasks 'under the hood' on a per-tag as-needed basis. Direct instantiation works, but MathDrawSVG
is designed for the purpose.
One glaring omission in the SVG package concerns units of measurement. The W3C SVG specification allows individual units to be attached to numbers in almost all SVG tags with numeric attributes. MathTools does not allow this! This exclusion is deliberate. Not allowing units on individual tags prevents massive careless errors caused by using incorrect units or simply misspelling them. Casting numerical values as double, or Double when they might be null, is one of MathTools' strongest goof-proofing features.
Individual unit omission is also good error-protection in another way: structural. While many tags do allow units, some do not. Some tags omit units by the
specification and automatically adopt the units of their parent tag, or user units which may be radically different from what is desired. Leaving units off
the individual tags requires that the document itself (SVGTag
) establish a uniform and consistent coordiante system for all of its elements. Since
creating an <svg> tag absolutely requires a non-null, non-empty width and height this is guaranteed.
For best results (and fewest headaches) first establish the overall size of the graphic. Set the width and height accordingly. Next set the viewport to a
convenient number of user units per established unit (setViewBox()
). The MathDrawSVG getLetter()
method does this: the width and
height are '8.5in' and '11in' respectively and the viewport is set to '0 0 850 1100'. This gives 100 user units per inch in both dimensions and all contained
tags use this consistently.