It’s time for part 2 – grouping and transforming SVG paths.
A short reminder: in first part I have showed you how to create simple SVG shapes if you have a raster image. We went through some of the path
syntax mysteries and ended up with all the simple shapes ready to merge into letters.
What we do today is creating this image as SVG:
To do this we will use SVG transforms and put use
element into use.
SVG Transforms
All of the transforms will go into transform
property like this:
<path transform="translate(180 0)"></path>
We will use following transforms:
- translate – to move elements to left, right, top and bottom
- scale – to change size or mirror the element
- rotate – to rotate the element around a point
SVG use
In the process we will reuse both single shapes and groups of shapes multiple times and it’s good to know how SVG’s use
element works.
Let’s have a look at the example:
<svg width="120" height="100" viewbox="0 0 120 100">
<defs>
<path id="m-one" d="M0,0m0,92h25l2,-6,-13,-51z"></path>
<path id="m-two" d="M0,0m40,92h30l-24,-92h-20l-5,17z"></path>
</defs>
<g id="M">
<use href="#m-one"/>
<use href="#m-two"/>
<use href="#m-two" transform="translate(40)"/>
</g>
</svg>
First, we declare <defs>
in the beginning of the SVG file. Then we give every reusable element an id
. Outside the <defs>
we will instruct the browser to render these shapes by using href
attribute with an id
as value.
Reused shapes can be modified with inline attributes like transform
, fill
, stroke
, which is great. It makes resulting code shorter (path’s d
attribute can get veery long) and it gives the possibility to use the same elements in multiple icons – you create one arrow, and reuse it as left arrow, right arrow and so on, changing only its transform
.
<use>
is a self-closing tag, which means we cannot put anything inside it. That space is reserved for shadow DOM containing copies of referenced elements.
Compositing SVG group from paths
Some of the letters can be assembled easily just by grouping shapes we created earlier. For example letter “E”:
<svg width="120" height="100" viewbox="0 0 120 100">
<defs>
<path id="i" d="M0,0h32v92h-32z"></path>
<path id="e-one" d="M0,0m35,0h30v33z"></path>
<path id="e-two" d="M0,0m54,26v36l-19,-18z"></path>
<path id="e-three" d="M0,0m35,92h31v-40z"></path>
</defs>
<g id="E" >
<use href="#i"/>
<use href="#e-one"/>
<use href="#e-two"/>
<use href="#e-three"/>
</g>
</svg>
We can go one step further and put this group in defs
to reuse later as <use href="#e"/>
.
<svg width="120" height="100" viewbox="0 0 120 100">
<defs>
<path id="i" d="M0,0h32v92h-32z"></path>
<path id="e-one" d="M0,0m35,0h30v33z"></path>
<path id="e-two" d="M0,0m54,26v36l-19,-18z"></path>
<path id="e-three" d="M0,0m35,92h31v-40z"></path>
<g id="e">
<use href="#i"/>
<use href="#e-one"/>
<use href="#e-two"/>
<use href="#e-three"/>
</g>
</defs>
<use href="#e"/>
</svg>
Note, that whatever we have put in defs
, will not be rendered. Only the resulting letter “E” will appear on the screen. If you try to inspect it with developer tools, you would see something like this:
Translation in SVG
To translate an element by 30 units to the right and 20 units to the bottom use transform="translate(30 20)"
. Note, that these are SVG internal units and not pixels.
If you only want to move an element horizontally, you can omit the second value: transform="translate(30)"
.
To create the letter “M”, we would write:
<svg width="120" height="100" viewbox="0 0 120 100">
<defs>
<path id="m-one" d="M0,0m0,92h25l2,-6,-13,-51z"></path>
<path id="m-two" d="M0,0m40,92h30l-24,-92h-20l-5,17z"></path>
</defs>
<g id="M">
<use href="#m-one"/>
<use href="#m-two"/>
<use href="#m-two" transform="translate(40)"/>
</g>
</svg>
Elements m-one
and first m-two
would we rendered as defined in their d
attributes. The second m-two
would be moved 40 units to the right.
Rotating in SVG
To rotate an element by 30 degrees use transform="rotate(30)"
.
Rotation will happen around the point at 0,0
, which is rarely what we need. We can add the coordinates of the point, we want our element to rotate around like this: transform="rotate(30, 10, 15)"
. It translates into: rotate by 30 degrees around the point with coordinates 10 (x-axis) and 15 (y-axis).
We will use rotation and translation to built the letter “O”:
<svg width="120" height="100" viewbox="0 0 120 100"> <defs> <path id="o-one" d="
M0,0m36,92c-36,0,-36,-92,0,-92z"></path> </defs> <g id="O"> <use href="#o-one"/> <use href="#o-one" transform="rotate(180) translate(-82 -92)"/> </g> </svg>
Transforms always happen in order they are written in. In our case it means: first rotate, than translate.
Scaling SVG
To scale an element – make it 2 times wider and 5 times taller – use transform="scale(2,5)"
.
Elements are scaled so that the top left corner (point (0,0)
) does not move.
We will use transform="scale(-1,1)"
to mirror a part of the letter “T” (invert it horizontally and keep original vertically):
<svg width="120" height="100" viewbox="0 0 120 100">
<defs>
<path id="t-one" d="M0,0m0,41v-41h19z"></path>
<path id="i" d="M0,0h32v92h-32z"></path>
</defs>
<g id="T">
<use href="#t-one"/>
<use href="#i" transform="translate(21)"/>
<use href="#t-one" transform="translate(73) scale(-1 1)"/>
</g>
</svg>
Assembling the full image
Now, as we have assembled all the letters from basic shapes, we can use them to put together the static image from the beginning of this post:
Our SVG code looks like this:
<svg width="1000" height="1000" viewbox="0 0 1000 1000">
<defs>
<path id="n-one" d="M0,0m0,26v66h26v-11z"></path>
<path id="n-two" d="M0,0m0,6v-6h36l41,86v6h-36z"></path>
<path id="o-one" d="M0,0m36,92c-36,0,-36,-92,0,-92z"></path>
<path id="t-one" d="M0,0m0,41v-41h19z"></path>
<path id="I" d="M0,0h32v92h-32z"></path>
<path id="m-one" d="M0,0m0,92h25l2,-6,-13,-51z"></path>
<path id="m-two" d="M0,0m40,92h30l-24,-92h-20l-5,17z"></path>
<path id="e-one" d="M0,0m35,0h30v33z"></path>
<path id="e-two" d="M0,0m54,26v36l-19,-18z"></path>
<path id="e-three" d="M0,0m35,92h31v-40z"></path>
<g id="N">
<use href="#n-one"/>
<use href="#n-two"/>
<use href="#n-one" transform="rotate(180) translate(-77 -92)"/>
</g>
<g id="O">
<use href="#o-one"/>
<use href="#o-one" transform="rotate(180) translate(-82 -92)"/>
</g>
<g id="T">
<use href="#t-one"/>
<use href="#I" transform="translate(21)"/>
<use href="#t-one" transform=" translate(73) scale(-1 1)"/>
</g>
<g id="M">
<use href="#m-one"/>
<use href="#m-two"/>
<use href="#m-two" transform="translate(40)"/>
</g>
<g id="E">
<use href="#I"/>
<use href="#e-one"/>
<use href="#e-two"/>
<use href="#e-three"/>
</g>
<g id="D">
<use href="#I"/>
<use href="#o-one" transform="rotate(180) translate(-77 -92)"/>
</g>
</defs>
<use href="#N" transform="translate(8 11)"/>
<use href="#O" transform="translate(96 11)"/>
<use href="#T" transform="translate(8 113)"/>
<use href="#I" transform="translate(96 113)"/>
<use href="#M" transform="translate(136 113)"/>
<use href="#E" transform="translate(250 113)"/>
<use href="#T" transform="translate(96 225)"/>
<use href="#O" transform="translate(180 225)"/>
<use href="#D" transform="translate(180 327)"/>
<use href="#I" transform="translate(260 327)"/>
<use href="#E" transform="translate(300 327)"/>
</svg>
If you are asking yourself where do the numbers in letters’ translate
come from – I have read them from the jpeg file the same way I have read the coordinates to create shapes in the firs part of this series.
That’s it for this part. See you in the next part – animation.