SVG hide an object until needed - svg

I'm able to move an object along a Bezier Curve but am having some difficulty with 'defs' and 'use'. My object (circle) appears at 0,0 before the animation begins, then appears in the correct position.
<svg viewBox="0 0 500 300" style="border:1px solid black; width:500; height:500;" xmlns="http://www.w3.org/2000/svg" >
<path id="track" d="M100,200 C200,150 300,250 400,200" stroke-width="3" stroke="#000" fill="none"/>
<circle id="circ1" r="10" cx="0" cy="0" fill="red" >
<animateMotion begin="1s" dur="6s" fill="freeze">
<use href="#circ1" cx="100" cy="200"/>
<mpath xlink:href="#track"/>
</animateMotion>
</circle>
</svg>
How can I make it appear at the beginning of the Bezier line, not at 0,0?

You can use <set> elements to set the position of the circle at the begining of the curve. Next at 1s you need to set again the position of the circle on 0,0
<svg viewBox="0 50 500 300" style="border:1px solid black; width:500; height:300;" xmlns="http://www.w3.org/2000/svg" >
<path id="track" d="M100,200 C200,150 300,250 400,200" stroke-width="3" stroke="#000" fill="none"/>
<circle id="circ1" r="10" cx="0" cy="0" fill="red">
<set begin="0" attributeName="cx" to="100" />
<set begin="0" attributeName="cy" to="200" />
<set begin="1s" attributeName="cx" to="0" />
<set begin="1s" attributeName="cy" to="0" />
<animateMotion begin="1s" dur="6s" fill="freeze">
<!--<use href="#circ1" cx="100" cy="200"/>-->
<mpath xlink:href="#track"/>
</animateMotion>
</circle>
</svg>
Yet another solution would be changing the origin of the curve so that it begins in the 0,0.
Please observe that I've changed the value of the viewBox attribute so that you can still see the curve in the middle of the svg canvas.
<svg viewBox="-100 -150 500 300" style="border:1px solid black; width:500; height:300;" xmlns="http://www.w3.org/2000/svg" >
<path id="track" d="M0,0C100,-50,200,50,300,0" stroke-width="3" stroke="#000" fill="none"/>
<circle id="circ1" r="10" cx="0" cy="0" fill="red" >
<animateMotion begin="1s" dur="6s" fill="freeze">
<!--<use href="#circ1" cx="100" cy="200"/>-->
<mpath xlink:href="#track"/>
</animateMotion>
</circle>
</svg>

Related

Svg alternate animateMotion

I want to have repeating alternate direction for the animation
<animateMotion keyPoints="0;1;0" keyTimes="0;0.5;1" dur="6s" repeatCount="indefinite" rotate="auto" >
<mpath href="#path1"/>
</animateMotion>
Keypoints and KeyTimes are not working
Full code:
<svg width="200" height="200" viewBox="0 0 700 700">
<g>
<path id="path1" d="M200,350 C 200,440 400,150 400,250 M200,350"
fill="none" stroke="blue" stroke-width="7.06" />
<path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z"
fill="yellow" stroke="red" stroke-width="7.06" />
<animateMotion keyPoints="0;1;0" keyTimes="0;0.5;1" dur="6s" repeatCount="indefinite" rotate="auto" >
<mpath href="#path1"/>
</animateMotion>
</g>
</svg>
First there is an issue with your code. You are animating a group of shapes and you are using one of those shapes as mpath.
In the next examples I'm animating the triangle over the integral like shape. In order to animate the triangle in both ways I'm rewriting the mpath so that the path will reverse to the starting point.
svg{width:90vh}
<svg viewBox="0 0 700 700">
<path id="path1" d="M200,350 C 200,440 400,150 400,250 C400,150 200,440 200,350" fill="none" stroke="blue" stroke-width="7.06" />
<path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z" fill="yellow" stroke="red" stroke-width="7.06" >
<animateMotion keyPoints="0;1;0" keyTimes="0;0.5;1" dur="6s" repeatCount="indefinite" rotate="auto" >
<mpath href="#path1"/>
</animateMotion>
</path>
</svg>
However if you want the triangle to stay the same side of the curve when reversing, in this case I'm using 2 animations, each one begining when the previous one ends. For the second animation I'm using rotate="auto-reverse"
svg{width:90vh}
<svg viewBox="0 0 700 700">
<path id="path1" d="M200,350 C 200,440 400,150 400,250" fill="none" stroke="blue" stroke-width="7.06" />
<path id="path2" d="M400,250 C400,150 200,440 200,350" fill="none" stroke="blue" stroke-width="7.06" />
<path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z" fill="yellow" stroke="red" stroke-width="7.06">
<animateMotion id="a1" dur="3s" rotate="auto" begin="0;a2.end">
<mpath href="#path1" />
</animateMotion>
<animateMotion id="a2" dur="3s" rotate="auto-reverse" begin="a1.end">
<mpath href="#path2" />
</animateMotion>
</path>
</svg>
Please observe that the path for the second animation is the path for the first animation reversed.

How to draw circles in SVG like if they were a single shape?

I need to draw an indeterminate number of circles in SVG like if they were a single shape. Making all circles have the same fill color does not work because I need those circles to have a filter applied in them, like in the picture, and as you can see the overlapping areas are in a different color.
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"
width="1"
height="3"
patternTransform="rotate(-45 2 2)">
<path
d="M -1,2 l 6,0"
[attr.stroke]="'#' + color"
stroke-width=".5"
/>
</pattern>
<ng-container *ngFor="let cone of cones, index as i">
<svg:circle
fill="url(#diagonalHatch)"
[attr.cx]="scaleX * (offset + cone.cX)"
[attr.cy]="cone.cY"
[attr.r]="scaleX * radius"
/>
</ng-container>
Result I am getting
Result I need
I suppose that what you have right now is something like this where due to the semitransparency of the pattern you can see the overlapped parts as darker:
<svg viewBox="0 0 100 50" width="400">
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"
width="1"
height="3"
patternTransform="rotate(-45 2 2)">
<path
d="M -1,2 l 6,0"
stroke="rgba(0, 100, 100, .3)"
stroke-width="0.5"
/>
</pattern>
<g>
<circle fill="url(#diagonalHatch)" r="20" cx="25" cy="25"/>
<circle fill="url(#diagonalHatch)" r="20" cx="50" cy="25"/>
<circle fill="url(#diagonalHatch)" r="20" cx="75" cy="25"/>
</g>
</svg>
As a possible solution you could use the circles as a clipping path and clip a rectangle the size of the svg canvas like so:
<svg viewBox="0 0 100 50" width="400">
<pattern
id="diagonalHatch"
patternUnits="userSpaceOnUse"
width="1"
height="3"
patternTransform="rotate(-45 2 2)">
<path
d="M -1,2 l 6,0"
stroke="rgba(0, 100, 100, .3)"
stroke-width="0.5"
/>
</pattern>
<clipPath id="c">
<circle r="20" cx="25" cy="25"/>
<circle r="20" cx="50" cy="25"/>
<circle r="20" cx="75" cy="25"/>
</clipPath>
<rect fill="url(#diagonalHatch)" width="100" height="50" clip-path="url(#c)"/>
</svg>

How to rotate svg circle

I want to use the same svg, but instead want the half circle svg to be rotated 90 degrees. How do I do this? Thanks.
<svg width="100" height="100">
<circle cx="50" cy="50" r="50" fill="grey" />
<path d="M0,50 a1,1 0 0,0 100,0" fill="orange" />
</svg>
SVG syntax
must not use units in the rotate() function
can state the rotation center only as part of the attribute
<svg width="100" height="100">
<circle cx="50" cy="50" r="50" fill="grey" />
<path d="M0,50 a1,1 0 0,0 100,0" transform="rotate(90, 50 50)" fill="orange" />
</svg>
CSS syntax
must use units for rotate() function and transform origin
can state the rotation center only as CSS transform-origin
path {
transform: rotate(90deg);
transform-origin: 50px 50px;
}
<svg width="100" height="100">
<circle cx="50" cy="50" r="50" fill="grey" />
<path d="M0,50 a1,1 0 0,0 100,0" fill="orange" />
</svg>
To use the same SVG (which is what is desired and differentiates this answer from other answers) you can reference the original SVG from a <use> element in a new SVG and apply a CSS rotation.
.rotate90 {
transform: rotate(90deg);
}
<svg id="mySVG" width="100" height="100">
<circle cx="50" cy="50" r="50" fill="grey" />
<path d="M0,50 a1,1 0 0,0 100,0" fill="orange" />
</svg>
<svg class="rotate90" width="100" height="100">
<use href="#mySVG"/>
</svg>

animateMotion a path with marker-start and marker-end svg only

is it possible to animate a path with marker elements? the path id in question is #orbit1. the reason i created the markers is that they will be used multiple times.
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1" viewBox="0 0 1500 1000">
<defs>
<marker id="arrowRight" viewBox="0 0 7.1 11.5" refX="5" refY="5.75"
markerUnits="userSpaceOnUse" orient="auto-start-reverse"
markerWidth="7.1" markerHeight="11.5">
<polygon points="1,11.5 0,10.4 5.1,5.7 0,1 1,0 7.1,5.7" fill="#00897b"/>
</marker>
<marker id="circle" viewBox="0 0 6 6" refX="1" refY="3"
markerUnits="userSpaceOnUse" orient="auto"
markerWidth="6" markerHeight="6">
<circle cx="3" cy="3" r="3" fill="#4caf50"/>
</marker>
</defs>
<!-- arrowhead symbol -->
<symbol>
<path id="d_arrow1" fill="red" d="M-10-10L10 0l-20 10 2-10-2-10z" />
</symbol>
<!-- animateMotion defines the motion path animation -->
<animateMotion xlink:href="#a1" begin="0s" dur="3s" rotate="auto" repeatCount="indefinite">
<mpath xlink:href="#orbit1" />
<!-- mpath = sub-element for the <animateMotion> element provides the ability to reference an external <path> element as the definition of a motion path -->
</animateMotion>
<animateMotion xlink:href="#a2" begin="0s" dur="3s" rotate="auto-reverse" keyPoints="1;0" keyTimes="0;1" calcMode="linear" repeatCount="indefinite">
<mpath xlink:href="#orbit2" />
</animateMotion>
<!-- arrow paths -->
<path id="orbit2" d='M 365 400 A 370 200 0 0 1 1100 400' fill="none" stroke-width="3" style="stroke: green; stroke-dasharray: 50 818; stroke-dashoffset: 50"/>
<!-- marker arrows -->
<!-- orbit1 to be animated using mpath -->
<path id="orbit1" d="M308.7 34.9C381.3 37.4 444.3 78 478.7 137.5" stroke="#4caf50" fill="none" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="50 1000" stroke-dashoffset="50"
marker-start="url(#circle)"
marker-end="url(#arrowRight)"/>
<!-- <animate> svg element used to animate an attribute or property of an element over time. it's normally inserted inside the element or referenced by the href attribute of the target element -->
<animate id="anim1" xlink:href="#orbit1" attributeName="stroke-dashoffset" from="50" to="-960" dur="3s" begin="0s" fill="freeze" repeatCount="indefinite" />
<!-- animate using the animateMotion definition above -->
<animate id="anim2" xlink:href="#orbit2" attributeName="stroke-dashoffset" from="-810" to="50" dur="3s" begin="0s" fill="freeze" repeatCount="indefinite" />
<!-- <use id="a1" xlink:href="#d_arrow1" x="0" y="0" width="100" height="50" />-->
<use id="a2" xlink:href="#d_arrow1" x="0" y="0" width="100" height="50" />
</svg>

how to repeat infinitely the whole svg

I mean after my SVG stops completing the animation I want the animation to start over again and end and then again start over and so on.
I tried:
<svg>
<animate repeatCount="indefinite"/>
</svg>
But it doesn't work.
See example animMotion01 in the w3 SVG spec for a fairly reduced example illustrating SVG animation (including use of repeatCount="indefinite"):
<svg width="5cm" height="3cm" viewBox="0 0 500 300"
xmlns="http://www.w3.org/2000/svg" version="1.1"
xmlns:xlink="http://www.w3.org/1999/xlink" >
<desc>Example animMotion01 - demonstrate motion animation computations</desc>
<rect x="1" y="1" width="498" height="298"
fill="none" stroke="blue" stroke-width="2" />
<!-- Draw the outline of the motion path in blue, along
with three small circles at the start, middle and end. -->
<path id="path1" d="M100,250 C 100,50 400,50 400,250"
fill="none" stroke="blue" stroke-width="7.06" />
<circle cx="100" cy="250" r="17.64" fill="blue" />
<circle cx="250" cy="100" r="17.64" fill="blue" />
<circle cx="400" cy="250" r="17.64" fill="blue" />
<!-- Here is a triangle which will be moved about the motion path.
It is defined with an upright orientation with the base of
the triangle centered horizontally just above the origin. -->
<path d="M-25,-12.5 L25,-12.5 L 0,-87.5 z"
fill="yellow" stroke="red" stroke-width="7.06" >
<!-- Define the motion path animation -->
<animateMotion dur="6s" repeatCount="indefinite" rotate="auto" >
<mpath xlink:href="#path1"/>
</animateMotion>
</path>
</svg>

Resources