Related
I'm making a design, that needs to have a bunch of different dashed lines animated. I need it done exactly how this Codepen does it: https://codepen.io/Evgeny/pen/IEGoq
But when I copy my own SVG-code into that pen, then it doesn't animate.
This is my SVG-code:
<svg width="1400px" height="892px" viewBox="0 0 1400 892" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="outer-vector" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" stroke-dasharray="19.796,19.796">
<g id="inner-vector" transform="translate(-40.000000, -65.000000)" stroke="#34A9D6" stroke-width="2">
<path d="M41,956 C436.408926,930.206693 476.595836,649.998441 667.229605,409.842185 C811.794179,227.722893 1042.8769,68.6364821 1581,61" id="Stroke-3"></path>
</g>
</g>
</svg>
If I just copy that in, then it's just static.
If I then add the class path to the <path>-object, then it's animating, but not like the original line was.
How can I animate my dashed SVG-file, in the same fashion as that Codepen?
There's also this Pen here ( https://codepen.io/nevolgograd/pen/WOLaKB ), that has an effect that I'm after, but my dashed SVG-line doesn't animate there either.
Addition1
The dashed lines need to be on top of images, - so I can't simply make a second line on top of the first one, that gets gradually removed with the stroke-dashoffset/dasharray trick.
So unfortunately most things won't just magically work by copy/pasting something into a different example. So what you'll see here will get you closer to what you're looking for and after some effort's given tweaking your values to get exactly what you want come on back if you're still blocked and we'll get you sorted but personally I'm not a fan of providing a full answer when the only effort shown is pasting something into something else and expecting it to just work without trying to learn why it's not working the way it's expected to.
Look at the differences in your samples, the <g> tags are innocuous among other things and the stroke properties need to match your own sample not theirs.
You'll notice I changed a few things to get ya started, cheers!
.dashed{
stroke-dasharray: 10;
}
.path {
stroke-dasharray: 1800;
stroke-dashoffset: 1800;
animation: dash 2s linear alternate infinite;
}
#keyframes dash {
from {
stroke-dashoffset: 1700;
}
to {
stroke-dashoffset: 0;
}
}
<svg width="700px" height="446px" viewBox="0 0 1400 892" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="outer-vector" stroke="none" stroke-width="1" fill="none" stroke-linejoin="round" fill-rule="evenodd" stroke-dasharray="19.796,19.796">
<g id="inner-vector" transform="translate(-40.000000, -65.000000)" stroke="red" stroke-width="4">
<path class="stroke" stroke-miterlimit="10" d="M41,956 C436.408926,930.206693 476.595836,649.998441 667.229605,409.842185 C811.794179,227.722893 1042.8769,68.6364821 1581,61" id="Stroke-3"></path>
</g>
</g>
<g id="outer-vector2" stroke="none" stroke-linejoin="round" stroke-width="2" fill="none" fill-rule="evenodd" stroke-dasharray="19.796,19.796">
<g id="inner-vector2" transform="translate(-40.000000, -65.000000)" stroke="white" stroke-width="4">
<path class="path" stroke-miterlimit="10" d="M41,956 C436.408926,930.206693 476.595836,649.998441 667.229605,409.842185 C811.794179,227.722893 1042.8769,68.6364821 1581,61" id="Stroke-32"></path>
</g>
</g>
</svg>
This question is quite similar to this SO post but I'm using an svg animated spinner defined in a separate file where all my svg icons are stored. The spinner works fine when I display it by using $("#spinner").show(). However, when I try to display the spinner during loading of data (lots of data), it freezes. It restarts towards the end of loading but my code hides it after as it should. Kinda defeats the purpose of showing the loading spinner if it doesn't spin.
I created a demo below with a time out to simulate data processing. You can adjust the timeout time and the number of records if your machine is more powerful.
I know there's a css alternative in the mentioned SO post but I would like to try keeping an svg implementation.
Any input is appreciated. Thanks!
var records = [];
function LoadData() {
for (var i = 0; i < 100000; i++) {
setTimeout(records.push("Record" + i), 100000);
}
$("button").html("Done");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- SEPARATE SVG DEF FILE -->
<div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" style="width:0;height:0;position:absolute;overflow:hidden;">
<defs>
<symbol id="icon-loading" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
<path opacity="0.2" fill="#0353A4" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946 s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634 c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
<path fill="#0353A4" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 C22.32,8.481,24.301,9.057,26.013,10.047z">
<animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 20 20" to="360 20 20" dur="0.5s" repeatCount="indefinite"/>
</path>
</symbol>
</defs>
</svg>
</div>
<!-- VIEW PAGE -->
<div>
<svg><use xlink:href="#icon-loading"></use></svg>
</div>
<button onclick="LoadData();">Load Data</button>
If you use Css animations insted it works without a problem for me.
The only thing that I noticed: the circle is a bit off center. You can fix this with css transform origin or fix the svg.
var records = [];
function LoadData() {
for (var i = 0; i < 100000; i++) {
setTimeout(records.push("Record" + i), 100000);
}
$("button").html("Done");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<style>
#keyframes rotate {
from {
transform: rotateZ(0deg)
}
to {
transform: rotateZ(360deg)
}
}
#loading {
animation: rotate .5s infinite linear;
}
</style>
<!-- SEPARATE SVG DEF FILE -->
<div>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" style="width:0;height:0;position:absolute;overflow:hidden;">
<defs>
<symbol id="icon-loading" viewBox="0 0 40 40" enable-background="new 0 0 40 40" xml:space="preserve">
<path opacity="0.2" fill="#0353A4" d="M20.201,5.169c-8.254,0-14.946,6.692-14.946,14.946c0,8.255,6.692,14.946,14.946,14.946 s14.946-6.691,14.946-14.946C35.146,11.861,28.455,5.169,20.201,5.169z M20.201,31.749c-6.425,0-11.634-5.208-11.634-11.634 c0-6.425,5.209-11.634,11.634-11.634c6.425,0,11.633,5.209,11.633,11.634C31.834,26.541,26.626,31.749,20.201,31.749z"/>
<path fill="#0353A4" d="M26.013,10.047l1.654-2.866c-2.198-1.272-4.743-2.012-7.466-2.012h0v3.312h0 C22.32,8.481,24.301,9.057,26.013,10.047z">
</path>
</symbol>
</defs>
</svg>
</div>
<!-- VIEW PAGE -->
<div>
<svg id="loading"><use xlink:href="#icon-loading"></use></svg>
</div>
<button onclick="LoadData();">Load Data</button>
I am trying to animate a path within an svg.
The path is of a squiggly line to look like a wave. What I am trying to do is have this path translate horizontally on a infinite loop to make it look as though the water is moving.
You can see a similar effect achieved by the outline, only going vertically and this is not within an SVG: https://theoutline.com/
Here is the JsFiddle I have so far with an svg wave/squiggle.
<g class="wave-container">
<path class="wave" d="M1,1c1.6,0,1.6,1.6,3.3,1.6S5.9,1,7.6,1c1.6,0,1.6,1.6,3.3,1.6S12.5,1,14.2,1s1.6,1.6,3.3,1.6
c1.6,0,1.6-1.6,3.3-1.6"/>
</g>
https://jsfiddle.net/bje5rxzs/
I am trying to be able to animate this wave horizontally within it's group/container. I know SVG does not support overflow:hidden; within, so how would this be achieved?
Would a mask work? I am open to using a snap.svg if required. I will have other elements within this svg moving, so the squiggle needs to be within the same svg.
Any help much appreciated! Thank you :)
Updated
Like any animation where you are changing the position of something you can use transforms.
The key here is making the squiggly path wider than the svg viewbox, and setting overflow:hidden on svg (which is supported).
Since your illustration is tiny I had to make the svg viewbox tiny as well, only 15px wide, so that the path could overlap the svg container.
<svg version="1.1" x="0px" y="0px" width="15px" height="3.6px" viewBox="0 0 15 3.6">
<path class="white-path animate" d="M1,1c1.6,0,1.6,1.6,3.3,1.6S5.9,1,7.6,1c1.6,0,1.6,1.6,3.3,1.6S12.5,1,14.2,1s1.6,1.6,3.3,1.6 c1.6,0,1.6-1.6,3.3-1.6"/>
</svg>
css:
svg {
overflow:hidden;
}
.white-path {
fill:none;
stroke:#FFFFFF;
stroke-width:2;
stroke-linecap:round;
stroke-linejoin:round;
stroke-miterlimit:10;
}
#keyframes squiggle {
from {
transform: translateX(-7px)
}
to {
transform: translateX(0px)
}
}
.animate {
animation: squiggle 1s linear infinite;
}
I used a negative x translation, and through trial and error picked the right distance so the looping was seamless.
Demo:
https://jsfiddle.net/bje5rxzs/6/
you can just nest 2 svg.
var x = -5
setInterval(() => {
wave.setAttribute("transform", `translate(${x},0)`)
if (x >= 0) {
x = -5
} else {
x++
}
}, 100)
<svg viewBox="0 0 300 300" width="200" height="200">
<circle cx="150" cy="150" r="150" fill="red"/>
<svg x="50" y="50" viewBox="1 0 10 3.5" width="100" height="35">
<path id="wave" transform="translate(-5,0)" d="M1,1c1.6,0,1.6,1.6,3.3,1.6S5.9,1,7.6,1c1.6,0,1.6,1.6,3.3,1.6S12.5,1,14.2,1s1.6,1.6,3.3,1.6
c1.6,0,1.6-1.6,3.3-1.6" fill="none" stroke="black"/>
</svg>
</svg>
I am trying to make a play and stop button. I don't know how to morph the triangle shape (it is a path) into the square shape (it is a path) when it has been clicked. Only showing one shape at a time. Can anyone help?
<svg class="playStop" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
</style>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</svg>
I think one way is to define your two paths in defs and then use a use xlink:href="#shapeName" with an onclick handler that toggles that attribute or the corresponding DOM property, if supported..
A use element object with fully implemented SVG DOM has a href property with a baseVal property that can be read and set, so inside browsers as far as I have tested (with Firefox, Chrome, IE and Edge on Window) we can simply toggle that property, see https://jsfiddle.net/4x0gnkob/ for an online sample.
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
<svg class="playStop" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<defs>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</defs>
<use xlink:href="#playTriangle" pointer-events="all" onclick="this.href.baseVal = this.href.baseVal == '#playTriangle' ? '#stopSquare' : '#playTriangle';"></use>
</svg>
An alternative is to toggle the DOM attribute, it seems a bit complicated in an HTML5 environment as I thought I could solve it with setAttributeNS and getAttributeNS in one line, after some testing it seems that within HTML5 getAttribute('xlink:href') works better, so the full code tries to test which function returns a value.
function toggleLink(element, value1, value2) {
var xlinkNS = 'http://www.w3.org/1999/xlink';
var linkName = 'xlink:href';
var oldValue = element.getAttributeNS(xlinkNS, linkName) || element.getAttribute(linkName);
if (element.hasAttributeNS(xlinkNS, 'href')) {
element.setAttributeNS(xlinkNS, linkName, oldValue == value1 ? value2 : value1)
}
else {
element.setAttribute(linkName, oldValue == value1 ? value2 : value1);
}
}
.st0{fill:none;
stroke:#000000;
stroke-width:4;
stroke-miterlimit:10;}
<svg class="playStop" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 971 530" style="enable-background:new 0 0 971 530;" xml:space="preserve">
<defs>
<path id="playTriangle" class="st0" d="M432,290.7V187.8c0-11.4,9.2-20.7,20.6-20.8c3.2,0,6.3,0.7,9.2,2.2l86.9,43.3l16.2,8.1c10.2,5,14.5,17.5,9.4,27.7c-2,4.1-5.3,7.5-9.4,9.5l-13.4,6.7l-89.8,44.8c-10.2,5-22.6,0.8-27.6-9.5C432.7,297,432,293.9,432,290.7z"/>
<path id="stopSquare" class="st0" d="M458.6,167h91.3c14.7,0,26.6,11.9,26.6,26.6v91.3c0,14.7-11.9,26.6-26.6,26.6h-91.3c-14.7,0-26.6-11.9-26.6-26.6v-91.3C432,178.9,443.9,167,458.6,167z"/>
</defs>
<use xlink:href="#playTriangle" pointer-events="all" onclick="toggleLink(this, '#stopSquare', '#playTriangle')"></use>
</svg>
Online at https://jsfiddle.net/w36k21uz/1/.
You cannot do all the things just like that, you can either use SMIL, which is to become deprecated, or use a dedicated animation engine. I developed KUTE.js with a SVG Plugin that does most of the things you probably need for SVG.
A quick demo (should work in Firefox only due to some Stackoverflow XSS issue):
<div style="width: 220px">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 600 600">
<path id="rectangle" fill="indigo" d="M38.01,5.653h526.531c17.905,0,32.422,14.516,32.422,32.422v526.531
c0,17.905-14.517,32.422-32.422,32.422H38.01c-17.906,0-32.422-14.517-32.422-32.422V38.075C5.588,20.169,20.104,5.653,38.01,5.653z"></path>
<path id="star" style="visibility:hidden" d="M301.113,12.011l99.25,179.996l201.864,38.778L461.706,380.808
l25.508,203.958l-186.101-87.287L115.01,584.766l25.507-203.958L0,230.785l201.86-38.778L301.113,12.011"></path>
</svg>
</div>
<script id="core" src="https://cdn.jsdelivr.net/kute.js/1.5.5/kute.min.js"></script>
<script id="svg" src="https://cdn.jsdelivr.net/kute.js/1.5.5/kute-svg.min.js"></script>
<script>
var tween = KUTE.to('#rectangle', { path: '#star' }, {duration: 1500, yoyo: true, repeat: 1}).start();
document.addEventListener('click', function(){
!tween.playing && tween.start();
}, false);
</script>
I would like to convert an svg path animation, to a pure javascript one.
SVG code:
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z"/>
</svg>
CSS code:
.path {
stroke-dasharray: 10 10; /* 10px fill, 10px gap */
-webkit-animation: dash 10s linear normal infinite;
}
#-webkit-keyframes dash {
from {
stroke-dashoffset: 1000;
}
to {
stroke-dashoffset: 0;
}
}
Here is the Fiddle
I'm not sure why you need pure javascript, also this answer may not fit your needs as it actually does create inline CSS. But here it is, mostly taken from : https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-dashoffset
function dashOffset() {
var path = document.querySelector('.path');
var length = "1000";
// Clear any previous transition
path.style.transition = path.style.WebkitTransition = 'none';
// Set up the starting positions
path.style.strokeDasharray = "10 10";
path.style.strokeDashoffset = "1000";
// Trigger a layout so styles are calculated & the browser
// picks up the starting position before animating
path.getBoundingClientRect();
// Define our transition
path.style.transition = path.style.WebkitTransition = 'stroke-dashoffset 10s linear';
//listener to restart our loop
path.addEventListener('transitionend', dashOffset, false);
// Go!
path.style.strokeDashoffset = '0';
}
dashOffset();
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z" />
</svg>
There is also the requestAnimationFrame way :
function anim(){
var path = document.querySelector('.path');
path.style.strokeDasharray = "10 10";
path.style.strokeDashoffset--;
requestAnimationFrame(anim);
}
requestAnimationFrame(anim);
function anim(){
var path = document.querySelector('.path');
path.style.strokeDasharray = "10 10";
path.style.strokeDashoffset--;
requestAnimationFrame(anim);
}
requestAnimationFrame(anim);
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="340px" height="333px" viewBox="0 0 340 333" enable-background="new 0 0 340 333" xml:space="preserve">
<path class="path" fill="#FFFFFF" stroke="#000000" stroke-width="4" stroke-miterlimit="10" d="M66.039,133.545c0,0-21-57,18-67s49-4,65,8
s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41
C46.039,146.545,53.039,128.545,66.039,133.545z" />
</svg>
Note that you may be able to reproduce it with the pure SVG animateMotion element.
There are a few javascript SVG libraries you could look into. I'm partial to Raphael (www.raphaeljs.com).
It would be something like this:
var paper = Raphael('canvas', 600, 600);
paper.path("M66.039,133.545c0,0-21-57,18-67s49-4,65,8s30,41,53,27s66,4,58,32s- 5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41C46.039,146.545,53.039,128.545,66.039,133.545z")
.attr({fill:"#FFFFFF", stroke: "#000000", "stroke-width": "4", "stroke-miterlimit": "10"})
fiddle: http://jsfiddle.net/xLekbar4/
(Note: I added a div to the html as a container for the raphael "canvas", and changed the css to apply to 'path' elements, instead of elements with class '.path')
I strongly recommend you give a try to the Raphael.js library.
Using it you could easily reproduce what you want.
Additionally there's this very useful tool to convert your SVG file into Raphael.js reusable code : http://www.readysetraphael.com/
So your SVG file will become :
var rsr = Raphael('rsr', '340', '333');
var path_a = rsr.path("M66.039,133.545c0,0-21-57,18-67s49-4,65,8s30,41,53,27s66,4,58,32s-5,44,18,57s22,46,0,45s-54-40-68-16s-40,88-83,48s11-61-11-80s-79-7-70-41C46.039,146.545,53.039,128.545,66.039,133.545z");
path_a.attr({
class: 'path',
fill: '#FFFFFF',
stroke: '#000000',
"stroke-width": '4',
"stroke-miterlimit": '10',
'stroke-opacity': '1'
}).data('id', 'path_a');
var rsrGroups = [];
Then you just have to add a <div id="rsr"></div> to your document and also replace the CSS selector .path to path.
Et voilĂ !
Check this Fiddle to see the it in action :
http://jsfiddle.net/47nkqgmn/