APEX@IGP

Infogrid Pacific-The Science of Information

25

SVG Primitives. Graphs, Grids and Coordinates

How to create graphs with any ruling, convert SVG coordinates to Cartesian Coordinates, and pan and zoom around an SVG image. Updated: 20 December 2015

Drawings on graph paper are an integral part of  K-12 mathematics at various times.

Graphs, grids and coordinates should be easy to work with. They are easy with a few simple SVG techniques.

Do you want to learn how to make great handcrafted SVG?

Visit our new  Interactive SVG Tutorial Site here ►.

It is necessary to be able to instantly create a graph sheet drawing with any combination of major and minor lines and axes with varying scales.

Slightly more challenging is the requirement to use cartesian coordinates for math presentation. SVG starts with zero in the top-left corner of the image and increase positively moving to the left and downward.

The cartesian coordinate system of course starts in the middle and number value changes in each quadrant in an anti-clockwise rotation.

+10 -10 -10 +10 0

SVG with coordinates oriented to Cartesian layout. This is what we want.

SVG With Cartesian Coordinates

Working with the standard SVG Primitive 400px X 400px block the origin coordinates are in the top left corner. Numbers increase in value going down on the Y axis. They need to be up the other way.

The designers of SVG thought of everything. To invert an image horizontally or vertically you can use the transform-translate-scale value -1.

We need to flip around the Y axis so create a create a group like this. Make sure you put all the geometry inside this <g>...</g> element.

<g transform="translate(200, 200) scale(1,-1)">
 ... Your geometric shapes go here...
</g>

Next the origin is moved to the center of the SVG Primitive block using the transform-translate function. We now have cartesian coordinates in our SVG Primitive 400px X 400px block with the zero origin smack bang in the middle.

In this little example you can see the x and y text positioning coordinates match the value in each of the four quadrants

This makes it very easy to work with various geometry and trigonometry lines and shapes without any mind-numbing calculations. There is of course a little arithmetic needed to address the drawing scale.

alt

The Flip Trap!

There is one little trap with this. The coordinates of everything are flipped around the Y axis so text will be rendered upside down. To address this just put any label or explanatory text into another <g> inside the cartesian <g>and flip everything back. Elements inside a <g> inherit the properties from the parent. So text is again up the right way.

The other alternative is to keep all text outside the cartesian <g> and use standard SVG coordinates to position it.

Graph Lines

Different maths needs different graphs. SVG patterns make it relatively trivial to create the graph layout you need.

Without going into an explanation of SVG properties this pattern in the definitions at the top of the SVG file does all the work and delivers a default major/minor grid.

<defs> 
   <pattern id="minorGrid" width="10" height="10" patternUnits="userSpaceOnUse">
      <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"/>
   </pattern>
   <pattern id="grid" width="100" height="100" patternUnits="userSpaceOnUse">
      <rect width="100" height="100" fill="url(#minorGrid)" fill="none"/>
      <path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
   </pattern>
</defs>

+ + - + + - - -

Major/Minor Graph Lines

Here is the default graph rendering with the minor grid at 10px and the major grid at 100px. This can of course be adjusted for any combination of major and minor grid.

The grid background is transparent which means it will show any surface behind. In this example we have placed an additional rectangle with white fill at the bottom of the SVG

View the SVG

Simpler Grid

For basic geometry the major/minor grid just has too many lines. We can remove or disable the minor grid and resize the major grid.

In this example everything has been left in place except the fill="#minorGrid" has been replaced with fill="none" and the big pattern has been turned into 20 X 20.

<defs> 
   <pattern id="minorGrid" width="10" height="10" patternUnits="userSpaceOnUse">
      <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"/>
   </pattern>
   <pattern id="grid20" width="20" height="20" patternUnits="userSpaceOnUse">
      <rect width="20" height="20" fill="none"/>
      <path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
   </pattern>
</defs>

Alternatively just delete the minorGrid items totally and save a few bytes. This is the best approach.

<svg height="400" viewBox="0 0 400 400" width="400">
   <defs> 
      <pattern id="grid20" width="20" height="20" patternUnits="userSpaceOnUse">
         <path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
      </pattern>
   </defs>
   <rect fill="white" height="400" width="400" y="0"></rect>
   <rect fill="url(#grid20)" height="400" width="400" y="0"></rect>

You can adjust the pattern to any size you need. It is relatively trivial to do this even on a drawing by drawing basis. Just change the width and height values to what you need.

+ + - + + - - -

Simple Graph Lines

We arbitrarily selected 20px per integer. On the standard 400px SVG Primitive 400 square this gives plus and minus 10 integers on each cartesian axis with the origin at the center.

View the SVG

One Last Trick

For various reasons you will need to be able to move the coordinates around the viewBox. Now that we have the cartesian coordinates in place you can reframe the image with the viewBox.

To do this you have to make sure you have the graph extending outside the viewBox so you can move left/right and up/down. You can even zoom in and out.

So the default drawing has the background graph tiled 300px on all sides

<svg height="400" viewBox="0 0 400 400" width="400">
   <defs> 
      <pattern id="grid20" width="20" height="20" patternUnits="userSpaceOnUse">
         <path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"/>
      </pattern>
   </defs>
   <rect fill="white" height="1000" width="1000" y="-300" x="-300"></rect>
   <rect fill="url(#grid20)" height="1000" width="1000" y="-300" x="-300"></rect>
.... your content here ...
</svg>

+ + - + + - - -

Zooming and Panning

Here we have used the viewBox to both pan across the image and zoom into it. This means it is possible to reuse one image many times in a lesson dialog.

<svg height="400"  width="400"
     viewBox="100 -50 300 300">
...
</svg>

 Here you can see the viewbox has panned 100 pixels to the right and 50 pixels up. The viewbox has been set to 300 X 300 effectively giving a 25% zoom in effect.

It is generally better to use the viewBox to move around a static drawing than using transform scale or translate properties on the image.

Summary

That's graphs, grids and Coordinates covered. This topic is an introduction to some of the background details for drawings in digital textbooks on appropriate mathematical subjects. These tools and techniques can also be used in print books with IGP:Digital Publisher.

Handcrafted SVG is a skill that any digital content production person should have under their belt. When you create your SVG by hand you can create sophisticated images with amazingly small files. IGP:Digital Publisher has the editing tools built in to allow SVG files to be used as native HTML5 components without namespace declarations. These are processed in during format packaging when required.

<svg height="400" viewBox="0 0 400 400" width="400">
    <defs>
        <pattern id="smallGrid" width="10" height="10" patternUnits="userSpaceOnUse">
            <path d="M 10 0 L 0 0 0 10" fill="none" stroke="gray" stroke-width="0.5"></path>
        </pattern>
        <pattern id="grid10" width="100" height="100" patternUnits="userSpaceOnUse">
            <rect width="100" height="100" fill="url(#smallGrid)"></rect>
            <path d="M 100 0 L 0 0 0 100" fill="none" stroke="gray" stroke-width="1"></path>
        </pattern>
    </defs>
    <rect fill="white" height="800" width="800" y="0"></rect>
    <rect fill="url(#grid10)" height="400" width="400" y="0"></rect>
    <g transform="translate(0,0) scale(1, 1)">
        <line class="l1 s-black " x1="-200" x2="800" y1="200" y2="200"></line>
        <line class="l1 s-black " stroke="black" x1="200" x2="200" y1="-200" y2="800"></line>
    </g>
    <g transform="translate(200, 200) scale(1,-1)">
        <text class="t36 t-mid bold f-black" x="50" y="50">+ +</text>
        <text class="t36 t-mid bold f-black" x="-50" y="50">- +</text>
        <text class="t36 t-mid bold f-black" x="50" y="-50">+ -</text>
        <text class="t36 t-mid bold f-black" x="-50" y="-50">- -</text>
    </g>
</svg>
<svg height="400" viewBox="0 0 400 400" width="400">
    <defs>
        <pattern id="grid20" width="20" height="20" patternUnits="userSpaceOnUse">
            <path d="M 20 0 L 0 0 0 20" fill="none" stroke="gray" stroke-width="1"></path>
        </pattern>
    </defs>
    <rect fill="white" height="800" width="800" y="0"></rect>
    <rect fill="url(#grid20)" height="800" width="800" y="0"></rect>
    <g transform="translate(0,0) scale(1, 1)">
        <line class="l1 s-black " x1="-200" x2="800" y1="200" y2="200"></line>
        <line class="l1 s-black " stroke="black" x1="200" x2="200" y1="-200" y2="800"></line>
    </g>
    <g transform="translate(200, 200) scale(1,-1)">
        <text class="t36 t-mid bold f-black" x="50" y="50">+ +</text>
        <text class="t36 t-mid bold f-black" x="-50" y="50">- +</text>
        <text class="t36 t-mid bold f-black" x="50" y="-50">+ -</text>
        <text class="t36 t-mid bold f-black" x="-50" y="-50">- -</text>
    </g>
</svg>
comments powered by Disqus