I am new to SVG.
I am trying to define a "template" with a path in defs and reuse it. I want it the paths to rotate around the center with equal spacing between them
This is how far i got. The red dot is the middle.
Here is my code:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
<rect x="0" y="0" width="300" height="300" fill="#0B3E27"/>
<defs>
<path id="rotor" d="M140,140
c0,0,-40,-20,-100,0
c0,0,50,-10,50,20
c0,0,0,-5,50,-20"
fill="none"
stroke-width="2"
stroke="white"/>
</defs>
<g>
<use href="#rotor" x="-2" y="0"/>
<use href="#rotor" x="54" y="-160" transform="rotate(50)"/>
<use href="#rotor" x="-32" y="-305" transform="rotate(100)"/>
<use href="#rotor" x="-198" y="-332" transform="rotate(150)"/>
<use href="#rotor" x="-326" y="-223" transform="rotate(200)"/>
<use href="#rotor" x="-325" y="-55" transform="rotate(250)"/>
<use href="#rotor" x="-195" y="53" transform="rotate(300)"/>
</g>
<circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>
How can this be smoothly done in SVG?
Thanks so much in advance,
Simon
You need to specify a "pivot-point" the for the rotation.
You can either use the transform-origin
attribute or CSS property or you can specify this point in the rotate()
attribute directly as 2. and 3. arguments like so rotate(50 150 150)
.
Besides, you can tweak the position of the rotor shape by adjusting the first coordinates in the the path data d
attribute (M150 150
)
M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20
This way you don't need additional x and y offsets for each <use>
instance. We can move the entire path this way because it is based on relative commands. If you're uncertain whether your path is fully relative you can convert the path data with a tool like svg-path-editor
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
<rect x="0" y="0" width="300" height="300" fill="#0B3E27"/>
<defs>
<path id="rotor" d="M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20"
fill="none"
stroke-width="2"
stroke="white"/>
<style>
</defs>
<g >
<use href="#rotor" />
<use href="#rotor" transform="rotate(50 150 150)" />
<use href="#rotor" transform="rotate(100 150 150)"/>
<use href="#rotor" transform="rotate(150 150 150)"/>
<use href="#rotor" transform="rotate(200 150 150)"/>
<use href="#rotor" transform="rotate(250 150 150)"/>
<use href="#rotor" transform="rotate(300 150 150)"/>
</g>
<circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>
Using CSS transform-origin
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300">
<rect x="0" y="0" width="300" height="300" fill="#0B3E27"/>
<defs>
<path id="rotor" d="M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20"
fill="none"
stroke-width="2"
stroke="white"/>
<style>
use{
transform-origin: 150px 150px;
}
</style>
</defs>
<g >
<use href="#rotor" />
<use href="#rotor" transform="rotate(50)" />
<use href="#rotor" transform="rotate(100)"/>
<use href="#rotor" transform="rotate(150)"/>
<use href="#rotor" transform="rotate(200)"/>
<use href="#rotor" transform="rotate(250)"/>
<use href="#rotor" transform="rotate(300)"/>
</g>
<circle cx="150" cy="150" r="2" fill="red"></circle>
</svg>
The angle calculation is a bit odd – the 7 rotor blades with a 50 degree offset don't match up that well (covering only 350deg).
You may also move some transformations to an external CSS - combined with CSS vars and calc()
– this way you don't need to calculate the rotation angles explicitly.
Besides, you can easily avoid a background <rect>
element by applying a background directly to the outermost SVG element.
:root {
--blades: 7;
--blade: 0;
}
/* base style for rotor blades */
.b {
transform-origin: 150px 150px;
stroke-width: 2px;
stroke: #fff;
transform: rotate(calc(360deg / var(--blades) * var(--blade)));
}
.b1 {
--blade: 1;
}
.b2 {
--blade: 2;
}
.b3 {
--blade: 3;
}
.b4 {
--blade: 4;
}
.b5 {
--blade: 5;
}
.b6 {
--blade: 6;
}
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300" style="background:#0B3E27">
<defs>
<path id="rotor" d="M145 150 c0 0-40-20-100 0 0 0 50-10 50 20 0 0 0-5 50-20" />
</defs>
<!-- rotor blades -->
<use class="b b0" href="#rotor"/>
<use class="b b1" href="#rotor"/>
<use class="b b2" href="#rotor"/>
<use class="b b3" href="#rotor"/>
<use class="b b4" href="#rotor"/>
<use class="b b5" href="#rotor"/>
<use class="b b6" href="#rotor"/>
</svg>