Content – SVG Structure
Accessibility and SVG
The images in the Hawkes Web Platform are primarily SVG images. From a content perspective there are several aspects of SVG that lend SVG to the creation of accessible images that are mathematically accurate, more so than traditional image formats, such as JPEG or PNG.
- The first aspect is the ability to create templates of visual objects using the
defs
element. - The second aspect is being able to group together related portions of an image and use standard SVG markup to describe those groups.
- Third, text that is placed within an SVG image through use of the
text
element is readable, selectable, and able to be copied. - Finally, SVGs are scalable and do not lose quality when enlarged, unlike other images like PNGs.
This provides enhanced accessibility for sight-impaired users and users in general. The W3C website provides a great example of the differences between PNG and SVGs here: SVG vs PNG Magnification. Each of these aspects is looked at in further detail in the rest of this document.
SVG Basics
There are several elements that make up an SVG. It is important to note that variations of this structure will occur based on the type of SVG being created. However, the basic structure of an SVG should appear in the following order:
<figure>
<div>
<svg>
<title> </title>
<desc> </desc>
<defs> </defs>
<g aria-hidden="true">
<g (as needed)>
<paths>
<text> </text>
</g>
</g>
</svg>
</div>
<figcaption> </figcaption>
</figure>
For consistency we need to ensure that all of these pieces are present in the correct order and they also are used correctly in the context of specific SVGs. Starting at the top of the SVG structure we will look at each element and discuss its function beginning with the figure element.
Figure Element
The figure
tag is included around SVG’s that have figure captions above or below. The tag goes around the div
tag and also around the entire SVG. Depending on where the figcaption
occurs in the text, it should be placed above or below the SVG but ALWAYS outside the div
(if applicable) and svg
tags but inside the figure
tag.
DIV Element
The div
tag applies appropriate CSS styles for our SVGs and should wrap EVERY SVG. The only exception is when SVGs occur in a table. In this circumstance adding a div
around SVG’s within a table will cause display issues. For this reason all SVG’s that are placed in tables should not have div
tags. Additionally, because they don't have div
tags they should be given a defined height and width to prevent display issues due to excessive scaling.
ieSVG Class
Used when SVG’s have no defined height and width. Not defining a height and width allows SVGs to scale in Internet Explorer in a similar manner natively supported by other browsers. This occurs mainly with cartesian graphs, pie charts and bar graphs/histograms. Although number lines fall into this category as well, we don't want to apply the ieSVG class to them because there will be an excessive amount of whitespace above and below the numberline. When using the class ieSVG it should be included in the div
tag. If there is no defined height and width Internet Explorer will set arbitrary values of 150 pixels for each which results in tiny images. Using the ieSVG class will prevent this.
SVG Element
The svg
tag is the beginning of the actual SVG. There are a number of different parameters you can add to the svg
tag but the absolute minimum must include the namespaces and a viewbox
.
Namespaces From W3C: XML namespaces provide a simple method for qualifying element and attribute names used in Extensible Markup Language documents by associating them with namespaces identified by URI references. The namespaces we will be using are:
xmlns=http://www.w3.org/2000/svg
xmlns:xlink=http://www.w3.org/1999/xlink
Viewbox
All SVG’s should have a viewbox
regardless of type. The viewbox
allows for more specification on how the SVG will be displayed on screen. By changing the values you can display all or part of an SVG. Altering the viewbox
can also shrink or enlarge the SVG display. The viewbox
has four parameters that are separated by spaces.
viewbox="minimum-x minimum-y width height"
In general, the minimum values should be set to 0 and the width and height should be set to the height and width values of the SVG.
Height and Width
The height and width attributes determine the actual size of the SVG. All SVG’s should have a defined height and width with the exception of Cartesian graphs and number lines. Using height and width in conjunction with viewbox
provides a lot of display utility. In general, both the height and width should be no smaller than 250px and no bigger than 520px. However in some fringe cases it is acceptable for one of the dimensions to be below this threshold as long as the other is within the desired parameters.
The barebones SVG tag will be:
<svg viewBox="0 0 520 520" xmlns=http://www.w3.org/2000/svg xmlns:xlink="http://www.w3.org/1999/xlink">
</svg>
SVG Canvas
The SVG canvas is slightly different from the cartesian canvas. The minimum (0, 0) values begin in the top left corner for both x and y values. The farther right on the canvas, the larger the x-value and the farther down, the higher the y-value. When creating SVGs it is important to include a slight margin around the edges of the SVG. The actual SVG should not touch the edges of the viewbox because this can cause display issues.
Title(title
) and Description(desc
)
The title
element represents the title of the object and will appear as a tooltip. The title
should only contain plain text (NO MathML). This includes mathematical equations. If math needs to be included it should be done using plaintext with the "^" character representing exponents like this:
7x^3 + 5x + 3
The desc
element represents an extended description of the SVG. title
and desc
elements can be thought of as the alt
and longdesc
attributes in HTML. Using titles and descriptions combined with the semantic grouping of elements assists in the development of mental models by users of assistive technologies. Below is an example of our coordinate system with title
and desc
elements added. We should note that we have left out the contents of the defs
element since it is defined later. In addition, note that the contents of the title
and desc
elements are not rendered on the page. However they will be read by
SR technologies.
<div class="ieSVG">
<svg viewBox="0 0 520 520" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Cartesian coordinate plane</title>
<desc>This is a standard Cartesian coordinate system with axes of equivalent lengths.</desc>
</svg>
</div>
Another benefit of SVGs is that MathML elements can be inserted into desc
elements. Below is an example using MathML in the desc
element to represent the equation of the line. In this way we can use the actual equation as a description of the shapes or lines that make up the visual representation of the equation.
<title>Cartesian Graph and Equation Example</title>
<desc>The equation of the line is
<math>
<mi>y</mi>
<mo>=</mo>
<mrow>
<mrow>
<mn>2</mn>
<mo>⁢</mo>
<mi>x</mi>
</mrow>
<mo>+</mo>
<mn>2</mn>
</mrow>
</math>. Two of the points it passes through are
<math>
<mo>(</mo>
<mrow>
<mn>0</mn>
<mo>,</mo>
<mn>3</mn>
</mrow>
<mo>)</mo>
</math> and
<math>
<mo>(</mo>
<mrow>
<mrow>
<mo>−</mo>
<mn>2</mn>
</mrow>
<mo>,</mo>
<mrow>
<mo>−</mo>
<mn>1</mn>
</mrow>
</mrow>
<mo>)</mo>
</math>.
</desc>
defs
and use
Elements
The defs
Element
The defs
element is used to define elements to be reused later in an SVG. Some elements, such as marker
, can only exist within a defs
element. Other SVG elements can exist within a defs
and can be called with the use
element. Below we define the different arrowhead markers that are used throughout the document. Since none of the elements within the defs
are actually rendered on the page, there is nothing to show here but the code.
<svg width="250" height="250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Def Element Example</title>
<desc>Brief introduction to definitions utilizing axis arrowhead markers. These markers are used in every cartesian graph and numberline SVG.</desc>
<defs>
<marker id="axisArrowheadStart" orient="auto" viewBox="0 0 10 10" refX="10" refY="5" markerWidth="7.5" markerHeight="7.5">
<path class="fill" d="M10,0 L0,5 L10,10z" />
</marker>
<marker id="axisArrowheadEnd" orient="auto" viewBox="0 0 10 10" refX="0" refY="5" markerWidth="7.5" markerHeight="7.5">
<path class="fill" d="M0,0 L10,5 L0,10z" />
</marker>
</defs>
</svg>
Elements that exist within a defs
element can be replicated in other SVG images using a simple ID reference. This allows for the creation of image templates to ensure that SVG images are consistent without the need for scripting. This reduces page load times, while helping students to focus on learning.
An important note about defs
is that they are not limited to a single SVG on the screen. Once definitions are included on the page they can be referenced by any SVG on that page. For learn screens with multiple SVGs we do not want to repeat the same definitions for each SVG. For these instances, include all of the defs
in first SVG. If a subsequent SVG needs a more specific definition, it should be included within that SVG. This will reduce the amount of redundant code while clarifying which definitions each SVG uses.
The use
Element
The use
element allows you to duplicate and reuse previously created elements. Using the xlink:href
attribute, the use
element can reference a previously implemented grouping ID or definition. This is a great way to reduce the amount of code and save time. Height, width, and x / y attributes can be added to the use
element for proper placement and sizing.
The examples below show multiple ways of combining the use
and defs
elements with other elements (like path
) to create new images.
<defs>
<marker id="arrowheadEnd1" orient="auto" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="7.5" markerHeight="7.5">
<path class="primaryFill" d="M0,0 L10,5 L0,10z" />
</marker>
<marker id="arrowheadEnd2" orient="auto" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="7.5" markerHeight="7.5">
<path class="secondaryFill1" d="M0,0 L10,5 L0,10z" />
</marker>
<marker id="arrowheadEnd3" orient="auto" viewBox="0 0 10 10" refX="5" refY="5" markerWidth="7.5" markerHeight="7.5">
<path class="secondaryFill2" d="M0,0 L10,5 L0,10z" />
</marker>
<path id="blueLine" class="line stroke2 primaryStroke" d="M0 0 h100" />
<path id="redLine" class="line stroke2 secondaryStroke1" d="M0 0 h100" />
</defs>
<use xlink:href="#redLine" x="90" y="50" marker-end="url(#arrowheadEnd2)" />
<use xlink:href="#blueLine" x="70" y="80" marker-end="url(#arrowheadEnd1)" />
<path class="line stroke2 secondaryStroke2" d="M 50 110 h100" marker-end="url(#arrowheadEnd3)" />
The red and blue arrows were made exclusively by referencing the defs
"blueLine" and "redLine" and the colored arrrowhead markers. The green line was created from scratch using the path
element but also references the green arrowhead marker. Either option can create an accessible image but having a strong understanding of the use
element will make the code more succint.
Grouping (g
) Element
SVGs support the grouping of multiple SVG elements through the use of the g
element. The g
element can be used to group visual elements together that are semantically linked. It can also be used to group together elements that make up a distinct object but themselves are only pieces. The grouping of related elements can create a hierarchy within the SVG document that will allow users to create a mental model of the image.
Grouping semantic elements together helps organize the code within the SVG. For a Cartesian graph, we would group the Cartesian dot and its coordinates (x, y) together because they are semantically linked. We don’t want all the points in one group and all the coordinates in another.
There are two different ways to assign unique identifiers to grouping elements. If the grouping element is included in a defs
tag we can assign it an ID attribute. This is done like so:
<g id="Insert_ID_Here">
Adding an ID attribute to the group provides an easy way to reference the group later on and, with proper naming, makes it easy to know what the group consists of. ID’s should not contain spaces, if they do it will throw an error in the W3C validator tool during the finalization process. If the grouping element is not contained within the defs
then we can add a comment to the group for readability. This is done like so:
<g data-comment="Insert Comment Here">
Not all groups will require ID’s or comments but in situations with complicated SVG’s they are very beneficial. Each ID and comment should be a unique identifier. If they are not unique the page will not validate so avoid duplicates at all costs!
The example below provides a clear method of how to semantically group elements together in an effective way.
<g data-comment="Points and Coordinates">
<g data-comment="point(1, 3)">
<use xlink:href="#cartesianDot1" x="284" y="188" />
<text class="svgMath" x="310" y="190">(1, 3)</text>
</g>
<g data-comment="point(4, 6)">
<use xlink:href="#cartesianDot1" x="356" y="116" />
<text text-anchor="end" class="svgMath" x="340" y="110">(4, 6)</text>
</g>
<g data-comment="point(-2, 0)">
<use xlink:href="#cartesianDot1" x="212" y="260" />
<text text-anchor="end" class="svgMath" x="220" y="240">(−2, 0)</text>
</g>
<g data-comment="point(-4, -2)">
<circle class="secondaryFill1" cx="164" cy="308" r="8" />
<text text-anchor="end" class="svgMath" x="150" y="310">(−4, −2)</text>
</g>
</g>
Each of the points on the graph and their respective coordinates are grouped together. This reinforces the idea that each point and its coordinates are linked. If we were to group all of the coordinates together in one group and all of the points in another group, this information would be lost.
Aria-hidden Grouping
Another important use for the grouping element is to apply the aria-hidden
attribute to elements or groups of elements which contain text. If best practices are followed, the title
and desc
will provide all the relevant information about the SVG. If this holds, then all of the subsequent text in the SVG will be redundant. aria-hidden
will prevent SR technologies from repeating information to students.
NOTE: The aria-hidden
grouping should be included after the title
, desc
and defs
tags and not at the beginning of the SVG. If the aria-hidden
grouping wraps the title
and desc
then they will not be visible to SR technologies.
The example below shows how to properly implement the aria-hidden
attribute.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 250 250" height="250" width="250">
<title>Aria-Hidden Example</title>
<g aria-hidden="true">
<g data-comment="Long Division">
<text text-anchor="middle" class="svgMath" x="60" y="40" dy="0 0 0 0 -2">6.2 )</text>
<path class="line stroke1" d="M 77.25 19 h77" />
<text text-anchor="middle" class="svgMath" x="120" y="40">63.86</text>
</g>
</g>
</svg>
The path
Element
The path
element is used to draw lines and outline shapes within SVGs. There are a number of different attributes that a path can have. The data for the path is contained in the d attribute. The specifics for the d attribute can include moveto
(M/m), lineto
(L/l), horizontal line
(H/h), vertical line
(V/v), closepath
(Z/z), and curve commands (for curve commands please refer to the SVG Pocket Guide). All of these path specific attributes may be used repeatedly (if necessary) within the path data.
Moveto (M/m)
The path data must begin with a moveto
command. The moveto
command creates a new point in the same way we lift a pen to a new point to begin drawing on a sheet of paper.
Closepath (Z/z)
Closepath
ends the current subpath and draws a straight line from the initial point of the path to the current point being closed. For this attribute, "Z" and "z" are interchangeable. It is important to note that you can have additional subpaths in the path data after using closepath
.
Line Commands
Lineto (L/l)
The lineto
command has the most utility and draws a line from any one point to any other point. When chaining lineto
commands together, the end point of the current line becomes the starting point of the next unless a moveto
command is used.
Horizontal Line (H/h)
The horizontal line
command draws a horizontal line from the current point to a specified point "x" pixels to the left or right
Vertical Line (V/v)
The vertical line
command draws a vertical line from the current point to a specified point "y" pixels up or down.
Chaining Multiple Line Commands
Chaining multiple lines or curves into path
data is how complex shapes are created. The two examples below highlight how to chain multiple lines together within the same path
. The triangle image was created with only one moveTo
command and each line was drawn from the end point of the previous line. The three diagonal lines were created within the same path
but made use of the moveTo
command to draw the next line at a new point.
<svg viewBox="0 0 250 250" height="250" width="250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
</defs>
<g aria-hidden="true">
<path class="line stroke2 noFill" d="M50 60 l 30 50 h-60 l 30 -50" />
<path class="line stroke2 noFill" d="M150 60 l 30 50 M160 60 l 30 50 M170 60 l 30 50" />
</g>
</svg>
Capital letters signify absolute positioning while lower case letters signify relative positioning. In most cases using relative positioning will be more beneficial than using absolute. Using relative positioning makes the code easier to refactor later if necessary.
This idea is expressed in the example below. The top triangles are the originals, with the left triangle created using relative positioning and the right with absolute. When the first triangle was shifted down, the only change required was to change the original moveTo
y-value from 60 to 120. For the absolutely positioned triangle, every y-value in the path
needed to be altered to keep the image intact. When working on complicated SVGs with large amounts of pathing data, altering an absolutely positioned SVG will get very complicated very fast.
<svg viewBox="0 0 250 250" height="250" width="250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
</defs>
<g aria-hidden="true">
<g data-comment="Original Triangles">
<path data-comment="Relatively Positioned Triangle (Top Left)" class="line stroke2 noFill" d="M50 60 l 30 50 h -60 l 30 -50" />
<path data-comment="Absolutely Positioned Triangle (Top Right)" class="line stroke2 noFill" d="M150 60 L 180 110 H 180 120 L150 60 " />
</g>
<g data-comment="Position Altered Triangles">
<path data-comment="Relatively Positioned Triangle (Bottom Left)" class="line stroke2 noFill" d="M50 120 l 30 50 h -60 l 30 -50" />
<path data-comment="Absolutely Positioned Triangle (Bottom Right)" class="line stroke2 noFill" d="M150 120 L 180 170 H 180 120 L150 120 " />
</g>
</g>
</svg>
Text in SVG
An important part of SVG accessibility (and useful information in general) is that actual text can be used within SVG images, whereas text would be converted to a number of pixels in more standard image formats. Text can be placed within text
elements and given x and y coordinates on the SVG canvas to be placed. Characters placed within text
elements will be displayed on the screen as well as being read by assistive technology. If you have a title and description of a grouping of elements any characters within text elements will also be read unless they are specifically given the aria-hidden
attribute set to "true". This should ALWAYS be done when an SVG contains text. The tspan
element can be used within a text
element to place the text in different places on the SVG canvas. The article Authoring Accessible SVGs gives an excellent explanation of how to use text
and tspan
elements to arrange text in an SVG but still provide the same information to users of assistive technologies.
Text-anchor element
The text-anchor
attribute will determine the location of the x and y coordinates in relation to the text being placed on the SVG. This attribute should always be used, regardless of the text. One of three identifiers can be used: start, middle, and end. When placing text to the right of another element, start should be used. When placing text to the left of another element, end should be used. Only use middle if the text will be directly above or below the element you wish to label. These specific instances allow the font size of the text to grow while ensuring the element it is labeling will not be overlapped. The text-anchor
attributes are listed below.
text-anchor="start"
text-anchor="middle"
text-anchor="end"
The example below outlines each different use case for the text-anchor
attribute. The coordinates (−2, 1) and (2, −2) make use of the text-anchor="middle"
attribute because they are directly above and below their respective points. The "Text1" text uses the text-anchor="end"
attribute because it lies to the left of the line. The "Text2" text uses text-anchor="start"
because it lies to the right of the line.
T-span Element
The tspan
element can be used in a number of instances regarding text in SVGs. It is similar to the span
tag in HTML. If you wish to style or move only a single character (or set of characters) within a text tag, tspan
should be used with the appropriate classes and attributes. The attributes dx
and dy
can be used to move the value(s) in any direction, relative to the previous text. This can be useful when using exponents and degree symbols.
T-span Gotchas:
tspan
preserves all white space within it. When using tspan
ensure that the only spaces included are the ones needed. Otherwise it will cause display issues like the extra spaces in the whitespace error example below.
When using tspan
to change the position of elements within a text element, it is important to remember that the position change of the tspan
will apply to EVERYTHING after it within the same text
element, not just what is included in the tspan
. After using the tspan
for a power or subscript you will need to readjust the dx
and dy
values to use the original baseline using an additional tspan
. The examples below outline the correct tspan display and display issues associated with improper tspan use.
<g data-comment="Correct tspan">
<text x="150" y="30" text-anchor="end">Correct tspan:</text>
<text class="svgMath primaryFill" text-anchor="start" x="170" y="30">2<tspan class="italic">x</tspan><tspan class="fontSmall" dy="-14">2</tspan><tspan dy="14"> + 4<tspan class="italic">x</tspan> + 5</tspan>
</text>
</g>
<g data-comment="tspan excessive white space">
<text x="150" y="90" text-anchor="end">Whitespace Error:</text>
<text class="svgMath primaryFill" text-anchor="start" x="190" y="90">2<tspan class="italic"> x </tspan><tspan class="fontSmall" dy="-14"> 2 </tspan><tspan dy="14"> + 4 <tspan class="italic"> x </tspan> + 5</tspan>
</text>
</g>
<g data-comment="tspan baseline error">
<text x="150" y="150" text-anchor="end">Baseline Error:</text>
<text class="svgMath primaryFill" text-anchor="start" x="190" y="150">2<tspan class="italic">x</tspan><tspan class="fontSmall" dy="-14">2</tspan>+ 4<tspan class="italic">x</tspan> + 5</text>
</g>
Transformations
Elements occuring within an SVG can be transformed to be used in different situations then what might have been previously envisioned. When transforming an element the element will shift its position on the SVG canvas dependening on whether the x or y values are being transformed and by what factor they are being transformed by. Since placement of elements will be of the utmost importance in the WebProduct, understanding how to deal with transformed elements moving around on the canvas is important.
To use a transform on an object in an SVG, use the attribute transform="type of transform"
. The transformation can be translate
, scale
, rotate
or skew
. You can also use the transform matrix
, but this requires understanding of the matrix system. There are examples of the basic transforms below, and you can learn more on the MDN Transform Page. For more guidance on the subject of view boxes, transformations and many other things SVG check out this article Soueidan's Blog: SVG Tranformations. Any transformation that is applied to an element in effect changes the coordinate system for that element. If you translate
something, you are setting up a new coordinate system for the element, with the starting coordinates however far in the x and y directions that your transform
specified.
Translate
The first transform
to discuss is translate
. In effect, translating an element means moving it. The code for this is: transform="translate(x [y])"
.
This definition specifies a translation by x and y. If y is not provided, it is assumed to be zero. If you have a rect
element that is drawn at x="10" and y="10", and transform
it 100px to the right and 35px down, then you are in effect drawing the rect at x="110" and y="45". You can also translate groups of multiple elements so that the entire group is shifted rather than translating each individual element. This is particularly helpful when shifting fractions or large equations.
The example below outlines a basic transformation of a square.
<g aria-hidden="true">
<g data-comment="Original Rectangle">
<rect x="10" y="10" width="50" height="50" class="line noFill stroke1" />
<text class="svgMath fontSmall" text-anchor="start" x="75" y="35">The rectangle before the translation</text>
</g>
<g data-comment="Translated Rectangle">
<rect transform="translate(100,35)" x="10" y="10" width="50" height="50" class="secondaryStroke1 noFill stroke1" />
<text class="svgMath fontSmall secondaryFill1" text-anchor="start" x="175" y="70">The rectangle after the translation</text>
</g>
</g>
Scale
The second transformation is scale
. The code for this is: transform="scale(x [y])"
This definition specifies a translation by x and y. If y is not provided, it is assumed to be equivalent to x.
Keep in mind that when you use transform
to scale
an element, the scaling factors are applied to all of the positional numbers in the element. So if you have a rect
element that you want to scale
by 2, the x and y coordinates of the upper left hand corner of the rectangle will be multiplied by 2 and the height will be multiplied by 2. If your starting x and y coordinate values are 20, then your new coordinates after the transformation would be 40. Notice as well that the stroke width changes with the scaling.
If you want to keep the upper left hand corner of the rect
element in the same spot you will need to move it up the difference between the old and new coordinate using translate
. This translate
can be placed in the same transform
statement as the scale
. See the examples below.
<svg width="520" height="250" viewBox="0 0 520 250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g aria-hidden="true">
<g data-comment="Original Rectangle">
<rect x="20" y="20" width="50" height="50" class="line noFill stroke1" />
<text class="svgMath fontSmall" text-anchor="start" x="85" y="35">The rectangle before scaling</text>
</g>
<g data-comment="Scaled Rectangle">
<rect x="20" y="20" width="50" height="50" transform="scale(2)" class="secondaryStroke1 noFill stroke1" />
<text class="svgMath fontSmall secondaryFill1" text-anchor="start" x="155" y="95">The rectangle after scaling</text>
</g>
</g>
</svg>
<svg width="520" height="250" viewBox="0 0 520 250" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g aria-hidden="true">
<g data-comment="Original Rectangle">
<rect x="20" y="20" width="50" height="50" class="gridline noFill stroke1" />
</g>
<g data-comment="Scaled Rectangle">
<rect x="20" y="20" width="50" height="50" transform="scale(2)" class="secondaryStroke1 noFill stroke1" />
<text class="svgMath fontSmall secondaryFill1" text-anchor="start" x="155" y="95">The rectangle after scaling, before translation.</text>
</g>
<g data-comment="Scaled and Translated Rectangle">
<rect x="20" y="20" width="50" height="50" transform="scale(2) translate(-10,-10)" class="primaryStroke noFill stroke1" />
<text class="svgMath fontSmall primaryFill" text-anchor="start" x="130" y="30">The rectangle after scaling and after translation.</text>
</g>
</g>
</svg>
Mirror Imaging
One really useful thing you can do with a combination of scale
and translate
is to mirror an object across the canvas of the SVG. This is particularly useful when drawing curves that are mirrored across an axis. To do this, you scale
the element by −1 in the direction you want to mirror, then translate
by the width of the canvas. See the example below.
<g data-comment="Mirror Line (Dashed)">
<path d="M250 0 v100" class="gridline stroke1 dashed" />
<text class="svgMath fontSmall" x="250" y="115" text-anchor="middle">Mirror Line</text>
</g>
<g data-comment="Original Path">
<path d="M10 60 C15 150 35 50 240 70" class="primaryStroke stroke2 noFill" />
</g>
<g data-comment="Mirrored Path">
<path d="M10 60 C15 150 35 50 240 70" class="primaryStroke stroke2 noFill" transform="scale(-1,1) translate(-500 0)" />
</g>
Rotation
The next transformation is rotate
. The code for this is:
transform="rotate(a [x y])"
This specifies a rotation by "a" degrees about a given point, which is defined by x and y. The "a" represents the degree of rotation and can be positive (clockwise) or negative (counter-clockwise). If x and y are not supplied, the rotation is about the origin of the current user coordinate system (default is the top left corner).
For an example, take a rect
element and apply a rotate
of 25 degrees without specifying the x and y coordinates. Notice that while the rect
is rotated, it doesn't just rotate around itself. Instead, a copy of the canvas, the user coordinate system, is created and rotated by 25 degrees.
<g data-comment="Original Rectangle">
<rect x="250" y="10" width="50" height="50" class="line noFill stroke1" />
<text class="svgMath fontSmall" x="240" y="40" text-anchor="end">The rectangle before rotation</text>
</g>
<g data-comment="Rotated Rectangle">
<rect x="250" y="10" width="50" height="50" transform="rotate(25)" class="secondaryStroke1 noFill stroke1" />
<text class="svgMath fontSmall secondaryFill1" x="275" y="155" text-anchor="start">The rectangle after rotation</text>
</g>
However, if we specify the x and y coordinates as the center of our rect
, we get a very different result like the blue rectangle below.
<g data-comment="Rotated Rectangle with x and y specified">
<rect x="250" y="10" width="50" height="50" transform="rotate(25,275,35)" class="primaryStroke noFill stroke1" />
<text class="svgMath fontSmall primaryFill" text-anchor="start" x="290" y="85">The rectangle after x/y rotation</text>
</g>
Skew
The final transformation is skew
, but it is not particularly useful in creating SVGs for the WebProduct. The code for it is:
transform="skewX(a)"
or transform="skewY(a)"
.
This defines a skew
across the x or y axis by "a" degrees. Visual examples are provided below.
<g data-comment="Rectangle without skew">
<rect x="10" y="10" height="50" width="75" class="stroke1 line noFill" />
<text class="svgMath fontSmall" x="90" y="40" text-anchor="start">The rectangle before skewX</text>
</g>
<g data-comment="Rectangle with skew on X axis" transform="translate(-30, 0)">
<rect transform="skewX(20)" x="10" y="90" height="50" width="75" class="stroke1 line secondaryStroke1 noFill" />
<text x="135" y="120" text-anchor="start" class="svgMath fontSmall secondaryFill1">The rectangle after skewX</text>
</g>
<g data-comment="Rectangle without skew">
<rect x="10" y="10" height="50" width="75" class="stroke1 line noFill" />
<text class="svgMath fontSmall" x="90" y="40" text-anchor="start">The rectangle before skewY</text>
</g>
<g data-comment="Rectangle with skew on X axis">
<rect transform="skewY(20)" x="10" y="90" height="50" width="75" class="stroke1 line secondaryStroke1 noFill" />
<text x=90 y="150" text-anchor="start" class="secondaryFill1 svgMath fontSmall">The rectangle after skewY</text>
</g>