23
SVG Definitions help to create condensed and terse SVG by utilizing definition markers, symbols, patterns and CSS to reduce code and styling repitition. They also add significant clarity to hand-created/modified SVG. Modified: 20 December 2015
SVG has the <defs>...</defs> element to contain repetitive components that are not displayed until called by the <use>...</use> element from the body of any SVG image.
Do you want to learn how to make great handcrafted SVG?
Visit our new Interactive SVG Tutorial Site here ►.
These can be very useful, but they only really work when something can be globally pre-defined. They can also create annoying problems with scaling of drawings.
<defs> are at the top of the <svg>...</svg> file and are placed like this:
<svg width="400" height="400 viewBox="0, 0, 400, 400"> <title>...</title> <desc>...</desc> <defs> ... definition components go here... </defs> <use>...defs can be inserted anywhere, any number of times...</use> ...any other viewable components go here.... <svg>
So anything in <defs> is loaded and processed by the rendering system but not make visible until it is <use>ed.
There are a number of standard supporting styles and defined structures that can be used in <defs>....</defs>.
These can make it easier to hand-craft high-quality illustration outcomes without totally mastering SVG programming and syntax. SVG Primitives has a set of <defs> components available for instant use.
The definitions components consist of:
In addition to the above, project defined SVG-CSS can be included in the <defs>. This is incredibly powerful and a major contributor to the quick and productive assembly of custom drawings and significant file-size reduction. SVG Primitives have predefined styles for all common attributed that can be simply injected as class="" statements in the SVG shapes.
Very few high-level SVG tools use the <defs> or the <styles>. They generate nearly all shapes using complicated path statements with very complex inserted SVG attributes. Application generated SVG normally writes the style and attribute information inline, over and over again within the shape definitions. This results in impossible to read SVG and massively enlarged file sizes. To make matters worse, SVG generation applications also write a lot of their own maintenance data into the file.
The value of SVG Primitives is they can be inserted directly into the HTML5 content. The content need to be as small and efficiently written as possible without any loss of sophistication.
The use of definitions is a significant part of file-size reduction and simplification and enrichment of SVG Primitives.
You will notice in the code examples that the SVG is enclosed between simple <html>...</html> elements with no other structures. This is valid html5 and fine for editing and developing.
Just save the text as UTF-8 with an *.html extension and it will immediately open in Chrome and Safari, and for better standards support Firefox and Internet Explorer10.
There is a default set of CSS styles for major stroke, fill and text properties. These are applied to objects using the CSS class statement.
The colours and sizes choosen here are quite mechanical and designed to show how the styles can be used. For any specific book or series of books you should of course design your own colour and layout scheme by modifying the colours, or adding and deleting anything.
There is a default set of colors defined to inspire, not constrain the designer. All colors are defined as RGBA colours for mechanical reasons. Backgrounds are set at 0.5, lines at 1.0 transparency. It is better from a rendering performance perspective to use RGB colours and opacity if you want transparency on an object.
A strong advantage using CSS is that SVG-CSS follows the cascade rules. This means default properties can be set and modified as required further down in the cascade.
For any specific book it would be expected the designer would set the color design parameters before shape production begins.
View the SVG to see the default styles that have been defined for stroke, stroke-width, fill, and other miscellaneous properties.
View the SVG
You should be careful with the CSS and always reduce it to just the selectors being used in any particular SVG illustration. There is a tutorial that shows how to use the grouping element <g>...</g> to reduce the effort in creating styled elements.
Do not use the style=" " inline statements. There is no value in this. SVG attributes are more reliable. However using the class attribute is reliable, powerful and can considerably reduce the size of any SVG file.
Note there are properties that cannot be manipulated with the CSS definitions so by not using the style=" " inline property you will get more predictable behaviour.
An alternative is to use one external CSS with the full book design and reference that from the SVG illustrations. This becomes very power and improves production speed enormously if the styles are not extended in an uncontrolled manner.
The CSS can be included in the HTML CSS. It does not have to be applied within the SVG element. This means books that use a large number of SVG illustrations can all share the same CSS. These APEX@IGP articles do just that.
Markers attach to the start and end of lines and polygons. SVG Primitives provide a small set of useful markers for general maths and science. Here they are.
1. Arrows. There are six markers for arrows
2. Dots. Dots join the line in the (XY) center. Therefore only one Dot marker is required for start and end. There are three sizes available.
3. Crosses, like Dots join the marker shape in the exact center so only one is required for start, middle and end. There are three sizes available.
4. Lines Lines are the same for both ends and only one marker is required for the start, middle and end. There is one size available.
5. Squares These join the line in the XY center so only one marker is required for the start, middle and end.
See the comments in Marker Sizing Issues to understand the different sizing of markers in this illustration.
View the SVG
Webkit does not support repeating-linear-gradient but does have -webkit-repeating-linear-gradient that uses percentages only in this attribute. The result is you will see a set of blurred lines instead of a grid.
repeating-linear-gradient works reliably in Firefox and IE10. If you want to see/use this grid technique you will have to use a supporting browser right now.
Because the layout graphs are only normally present in the IGP:Writer authoring mode and not the final output images we haven't bothered with cross-browser adjustments. We just use the right tools for the job!
The symetrical markers don't have a start and end. Note that markers are rendered on a tangent to the node. This can give some unexpected results with middle markers.
You can use the SVG Primitive markers on <line> <polyline> and <polygon> elements. Just remember to make sure the markers you want to use are in the SVG <defs>.
There are three reserved SVG attribute values to handle placing markers onto a line, path or polygon. These are:
marker-start="url(#Arrow-Start)"
marker-mid="url(#Dot)"
marker-end="url(#Arrow-End)"
The URL for each marker is the ID of the marker in the <defs> Eg:
<marker id="Arrow-End">
Markers have a property markerUnits. This can be set to lineWidth or the rather awkwardly named userSpaceOnUse.
markerUnits="strokeWidth"
markerUnits="userSpaceOnUse"
When you use strokeWidth the markers will scale with the stroke width. This can be seen in the example with the end-markers (right-hand-side) in the above illustration. These effectively double in area with each line size increase and quickly look disproportionate.
If you use userSpaceOnUse the current user coordinate system is used so the markers do not change size with the line but remain fixed in size.
To assist with using markers in real illustrations each marker comes in three variants optimized for line size.
Arrow-Start | Arrow-End These have strokeWidth applied. They work for 1px and 2px lines but rapidly get out of size control with any larger stroke.
Arrow2-Start | Arrow2-End These are the same dimensions as the above set but have userSpaceOnUse applied so they will not expand with line sizes. This is useful when smaller arrows are required. This can be seen on the left of 2px Lines.
Arrow3-Start | Arrow3-End These are drawn larger with userSpaceOnUse and are appropriate for use on 3-4px lines. These can be seen on the left side of the illustration in 2px and 3px lines.
Dot | Dot2 | Dot3 This follows the same pattern. Dot uses strokeWidth. The Dot2 and Dot3 use userSpaceOnUse.
Cross | Cross2 | Cross3 This follows the same pattern. Dot uses strokeWidth. The Dot2 and Dot3 use userSpaceOnUse.
Square | Square2 | Square3 This follows the same pattern. Dot uses strokeWidth. The Dot2 and Dot3 use userSpaceOnUse.
Line There is only one size for line using userSpaceOnUse as this works with a reasonable number of stroke-widths.
Patterns are a little more difficult to define and use because of the way they use the layout system.
Currently there are only two patterns for SVG Primitives. Rulers. There is a centimetre and an inches ruler. We will shortly be adding a protractor and a set of graph-paper options.
The only current use for patterns is to create centimetre (CM) or Inch (IN) rulers. The IN ruler is set with 1/8th markers by default.
These patterns can be problematic to present.
The CM pattern is 100px wide. The IN pattern is 254px wide. The pattern repitition command must be a fraction of the pattern/presentation block width.
View the SVG
Symbols are used almost exclusively for angle arcs for geometry at this stage. This illustration shows the default starter-set of angles.
Angle markers are one of the most important geometry illustration symbols, but also one the hardest to create, position and align in the SVG context. SVG Primitives makes inserting arcs less painful, but a little brain-work is required to position and rotate.
Arcs can be seamlessly joined together. For example to make 197 deg angle180, angle15 and angle2 can all be joined together with the required angle off-set. While this approach does increase the file-size (by a few hundred bytes), the production time and symbol volume is reduced is significantly reduced.
Each arc is available in two sizes (in and out) to create diagrams without arc ends touching.
View the SVG
All angle arcs are defined in a 100px X 100px viewBox. The arcs are drawn from the center, starting on the 0 deg horizontal axis, rotating anti-clockwise. This ensures both acute and obtuse angles can be addressed.
The default <use/> examples show how the arc rotation in SVG is in the opposite direction to the normal maths rotation. In SVG a positive angle rotates clockwise, an negative angle anti-clockwise.
You can use either rotation direction as long as things end up being placed correctly. We use Cartesian Coordinate layout for consistency so all arcs start on the X-axis and rotate counter-clockwise. This also means if you are using an arrow, the marker-end property will be placed consistently.
Angle arc highlighting can be carried out with supplementary colours or gradients.
Angle arcs cannot be animated for degree changes at this stage so should be removed.
In practical geometry and physics arbitrary angles are required for arc, lines, triangles and all polygons as part of the instructional narrative. These have to be constructed. The Arcs, Angles and Ticks article discusses the how-tos and short-cuts in detail.
The SVG Primitives only use the definitions that are required for each illustration. All other definitions are deleted. This is they way each standard SVG Primitive is stored.
Because you are inserting SVG Primitives directly into your HTML5 content you do not want to overload the page with a lot of unused and un-necessary junk definitions cluttering up each SVG file.
In addition SVG Primitives carry the extended set of definitions for a very wide range of properties. If you do not want some of these you have to delete them. You should also delete the associated styles.
If you are combining several SVG Primitives together into a single SVG file you may have to cut-and-paste the definitions depending on how you are assembling the page.
The how-to of all this is explained in the SVG Primitives. Using and Modifying article.
Remember SVG Primitives are a starting point for your project not the final product. While the SVG shapes will remain relatively constant, changing the decoration and huge range of properties will allow any publisher to create new and unique digital content maths learning products.
<svg width="100%" height="100%"> <defs> <pattern id="Ruler-cm" x="0" y="0" width="0.1" height="1"> <path class="l1 s" d=" M 0,0 H 50 0 M 1,0 1,25 M 6,0 6,15 M 11,0 11,15 M 16,0 16,15 M 21,0 21,15 M 26,0 26,20 M 31,0 31,15 M 36,0 36,15 M 41,0 41,15 M 46,0 46,15" /> </pattern> <pattern id="Ruler-in" x="0" y="0" width="0.256" height="1"> <path class="l1 s" d=" M 0,0 127,0 M 1,0 1,25 M 15.875,0 15.875,10 M 31.75,0 31.75,15 M 47.6255,0 47.625,10 M 63.5,0 63.5,20 M 79.373,0 79.375,10 M 95.25,0 95.25,15 M 111.125,0 111.125,10" stroke="transparent"/> </pattern> </defs> <g transform="translate(0, 0) scale(1)"> <rect x="0" y="0" width="522" height="120" stroke="rgba(200, 200, 250, 1)" stroke-width="3" fill="rgba(200, 200, 250, 0.3)"/> <rect fill="url(#Ruler-cm)" stroke="none" x="10" y="3" width="500" height="25" /> <line class="line1" x1="511" y1="3" x2="511" y2="27" /> <text class="ruler" x="10" y="45">0</text> <text class="ruler" x="60" y="45">1</text> <text class="ruler" x="110" y="45">2</text> <text class="ruler" x="160" y="45">3</text> <text class="ruler" x="210" y="45">4</text> <text class="ruler" x="260" y="45">5</text> <text class="ruler" x="310" y="45">6</text> <text class="ruler" x="360" y="45">7</text> <text class="ruler" x="410" y="45">8</text> <text class="ruler" x="460" y="45">9</text> <text class="ruler" x="510" y="45">10</text> <g transform="translate(20, 95) rotate(180, 250, 12.5)" > <rect fill="url(#Ruler-in)" stroke="none" x="10" y="3" width="500" height="25" /> <line class="line1" x1="511" y1="3" x2="511" y2="27" /> <text class="ruler" x="10" y="45">0</text> <text class="ruler" x="139" y="45">1</text> <text class="ruler" x="268" y="45">2</text> <text class="ruler" x="394" y="45">3</text> </g> </g> </svg>
<svg height="400" width="400" x="0" y="0" viewBox="0, 0, 400,400" overflow="hidden"> <defs> <!-- Arrow markers --> <marker id="ArrowStart" viewBox="0 0 20 16" refX="16" refY="8" markerUnits="userSpaceOnUse" markerWidth="15" markerHeight="5" orient="0"> <path d="M 0 8 L 20 0 L 16 8 L 20 16 z" /> </marker> <marker id="ArrowEnd" viewBox="0 0 20 16" refX="4" refY="8" markerUnits="userSpaceOnUse" markerWidth="15" markerHeight="5" orient="auto"> <path d="M 0 0 L 20 8 L 0 16 L4 8 z" /> </marker> <marker id="ArrowArcEnd" viewBox="0 0 20 16" refX="19" refY="8" markerUnits="userSpaceOnUse" markerWidth="10" markerHeight="8" orient="auto"> <path d="m 0 0 l 18 8 l -18 8 l4 -8 z" fill="black"/> </marker> <symbol id="angle30" height="100" width="100"> <path d="M95,50 A 45, 45, 0, 0, 0, 89, 28" /> </symbol> <symbol id="angle45" height="100" width="100" > <path d="M95,50 A 45, 45, 0, 0, 0, 81, 18" /> </symbol> <symbol id="angle60" height="100" width="100"> <path d="M95,50 A 45, 45, 0, 0, 0, 72, 11" /> </symbol> <symbol id="angle90" height="100" width="100" > <path class="linearc" d="M50,25 l25 0 l 0 25" /> </symbol> <symbol id="angle120" height="100" width="100"> <path fill-none" d="M95,50 A 45, 45, 0, 0, 0, 28, 11" /> </symbol> <symbol id="angle180" height="100" width="100" > <path fill-none" d="M95,50 A 45, 45, 0, 0, 0, 5, 50" /> </symbol> <symbol id="angle240" height="100" width="100" > <path fill-none" d="M95,50 A 45, 45, 0, 1, 0, 28, 89" /> </symbol> <symbol id="angle270" height="100" width="100" > <path fill-none" d="M95,50 A 45, 45, 0, 1, 0, 50, 95" /> </symbol> </defs> <!-- 30deg--> <g transform="translate(-25, 50)" > <use class="linearc" xlink:href="#angle30" x="50" y="50" transform="rotate(0 50 50) translate(-50, -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-30 50 50)" /> <text class="t16" x="110" y="40">30°</text> </g> <!-- 45deg --> <g transform="translate(125, 50)"> <use class="linearc" xlink:href="#angle45" x="50" y="50" transform="rotate(0 50 50) translate(-50, -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)"/> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-45 50 50)"/> <text class="text1" x="105" y="35">45°</text> </g> <!-- 60deg --> <g transform="translate(250, 50)"> <use class="linearc" xlink:href="#angle60" x="50" y="50" transform="translate(50, 50) rotate(0 -50 -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)"/> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-60 50 50)"/> <text class="text1" x="100" y="25">60°</text> </g> <!-- 60deg --> <g transform="translate(150, -50)"> <use class="linearc" xlink:href="#angle60" x="50" y="50" transform="translate(50, 50) rotate(0 -50 -50)" marker-end="url(#ArrowArcEnd)" /> <text class="text1" x="100" y="25">60°</text> </g> <!-- 90deg --> <g transform="translate(-25, 150)"> <use class="linearc" xlink:href="#angle90" x="50" y="50" transform="rotate(0 50 50) translate(-50, -50)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-90 50 50)"/> <text class="text1" x="90" y="25">90°</text> </g> <!-- 120deg --> <g transform="translate(100, 150)"> <use class="linearc" xlink:href="#angle120" x="50" y="50" transform="rotate(0 50 50) translate(-50, -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)"/> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-120 50 50)"/> <text class="text1" x="95" y="10">120°</text> </g> <!-- 180deg --> <g transform="translate(270, 150)"> <use class="linearc" xlink:href="#angle180" x="50" y="50" transform="rotate(0 100 200) translate(-50, -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="115" y2="50" transform="rotate(0 50 50)"/> <line class="construction" x1="50" y1="50" x2="115" y2="50" transform="rotate(-180 50 50)"/> <text class="text1" x="50" y="0">180°</text> </g> <!-- 240deg --> <g transform="translate(50, 250)"> <use class="linearc" xlink:href="#angle240" x="50" y="50" transform="rotate(0 50 50) translate(-50, -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)"/> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-240 50 50)"/> <text class="text1" x=60" y="10">240°</text> </g> <!-- 270deg --> <g transform="translate(200, 250)"> <use class="linearc" xlink:href="#angle270" x="50" y="50" transform="rotate(0 50 50) translate(-50, -50)" marker-end="url(#ArrowArcEnd)" /> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(0 50 50)"/> <line class="construction" x1="50" y1="50" x2="125" y2="50" transform="rotate(-270 50 50)"/> <text class="text1" x=60" y="10">270°</text> </g> <text class="t18 bold f-dblue" x="30" y="30">Positioning Angle Arcs</text> </svg>