Detecting when a SVG animation has ended - javascript

I have a SVG image inside my body tag that is being animated by the following code:
<clipPath id="left-to-right">
<rect x="0" y="0" width="0%" height="100%" >
<animate attributeName="width" values="0%;100%" dur="5s" fill="freeze"/>
</rect>
</clipPath>
I'm adding the .svg to the body via an image tag like so:
<body>
<div id="loading-container">
<img id="silhoutte" src="Images/Silhoutte.svg">
</div>
<div id="content">
/* Content in here */
<div>
</body>
The svg is serving as a "loading" animation while i preload/cache some high resolution images before displaying the actual content.
My difficulty is in trying to detect the end of the SVG animation in order to reveal the content div. How would i go about detecting the animation if at all possible?
I'm open to suggestions on better ways to implement a web page loading screen using the animated SVG i created.
Thank you!

The SVG animation element should fire an endEvent once the animation is finished, so something like this should work:
document.querySelector('#left-to-right animate').addEventListener('endEvent', function() {
console.log('Animation finished');
}, false);

Related

SVG animation breaks in img tag on different zoom levels in macOS Safari

I have an SVG animation which runs well on every browser. But, when zoomed in on Safari, the animation breaks. It looks like the animation is bleeding through the right and bottom edges.
And, this only happens when the SVG is in an img tag. If the SVG is used inline, there is no issue as such.
When the page is zoomed in to 125% on macOS Safari, you'll get,
At first, it looked like an issue with my screen or with my personal preferences set in my browser. But, this is a real issue that I could reproduce on other machines too and also with other animated SVGs. For example, open up https://loading.io/spinner or http://samherbert.net/svg-loaders/ in macOS Safari with a zoom level other than 100% as you'll see the same behavior.
Snippet (save this SVG as a .svg image and use it in an img tag to reproduce this behavior)
<svg width="36" height="36" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z" opacity=".25" />
<path d="M12,4a8,8,0,0,1,7.89,6.7A1.53,1.53,0,0,0,21.38,12h0a1.5,1.5,0,0,0,1.48-1.75,11,11,0,0,0-21.72,0A1.5,1.5,0,0,0,2.62,12h0a1.53,1.53,0,0,0,1.49-1.3A8,8,0,0,1,12,4Z">
<animateTransform
attributeName="transform"
type="rotate"
dur="0.75s"
values="0 12 12;360 12 12"
repeatCount="indefinite"
/>
</path>
</svg>
I could reproduce this rendering bug on Otter Browser on windows (also webkit based) and found a kind of workaround:
Once the html body contains an inlined svg element with an <animateTransform> definition – SMIL animations in <img> tags will be rendered correctly.
In my tests you can append a hidden pseudo animation (not containing any animated element) like this:
<svg style="position:absolute; width:0; height:0; overflow:hidden;" >
<animateTransform
repeatCount="indefinite"
dur="1s"
attributeName="transform" />
</svg>
So it doesn't need to be the exact animation as used in the svg file.
Example: add animation fix via js:
function addAnimateFix() {
let svgFix =
`<svg style="position:absolute; width:0; height:0; overflow:hidden;" >
<animateTransform
repeatCount="indefinite"
dur="1s"
attributeName="transform" />
</svg>`;
document.body.insertAdjacentHTML('beforeend', svgFix)
}
<p><button type="button" onclick="addAnimateFix()">addAnimateFix</button></p>
<img height="200px" width="200px" src="https://svgshare.com/i/ia5.svg" alt="">
<img height="200px" width="200px" src="https://svgshare.com/i/i_v.svg" alt="">
Alternative workaround
background-image is apparently not affected by this bug.
So setting a background image on your image or wrapping parent element (like <figure>) could be a viable option.

Including an svg element in my html breaks jquery ui

I am having a very weird issue that I have no idea whatsoever how to debug.
I have a html file with a div that has the jquery UI draggable enabled:
$(function() {
$(".ideanode").draggable({ containment: "parent" });
});
this is working fine and dandy until I include this in my html:
<svg id="connectors" height="100%" width="100%">
<defs>
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6"
orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" />
</marker>
</defs>
<line x1="0" y1="0" x2="200" y2="100" class="arrow" />
</svg>
This just completely removes the draggable functionality of my div and I can't even begin to understand why. I will link to a full example as well.
https://codepen.io/ricodon1000/pen/XWmqxeB
If any additional information is needed please ask, I'm still learning how to post really good questions here. Thank you!
add a global style
svg{
background:red;
opacity:.5;
}
and you will see the SVG is covering the whole screen, thus blocking every element underneath

gsap animation - import only one svg or multiple svgs

I would like to do "complex" animation with gsap and svgs.
but I don't know what is the best approach to this.
it is better to create and to import an unique svg with all the elements or maybe it is better 4 different svgs?
I have 4 different characters: a tree, a lamp, a desk and a man.
basically my animation is move the objects on the x, and appearing and to disappearing stuff.
If the elements of the animation are part of one complex animation, you can use one single SVG for this.
To control the DOM of the SVG via CSS and JavaScript you need to add the SVG directly inline into your HTML page. Not embed via img tag or object tag or similar.
<body>
<h1>My SVG Animation</h1>
<svg width="100" height="100" viewBox="0 0 300 100">
<circle class="animation-element-01" cx="50" cy="50" r="40"/>
<rect class="animation-element-01" x="150" y="20" width="150" height="150"/>
<!-- etc -->
</svg>
</body>
Another advantage of this method is, that there is no additional html requests.
Plus the whole animation can be made responsive via the viewBox.

SVG element width and height set in html but appearing as 0 0 in inspector

I have an svg rect like this:
<svg class="legend-square">
<defs>
<pattern id="pattern1" width="3"
height="3" patternunits="userSpaceOnUse" patterntransform="rotate(-45)">
<rect width="2" height="3" transform="translate(0,0)" fill="purple"></rect>
</pattern>
</defs>
<rect width="12" height="12" fill="url(#pattern1)"></rect>
</svg>
When I inspect the second rect with Chrome it has no width and height. There are no CSS rules applying to it. Why doesn't it get affected by width and height?
One of the reasons why SVG file is rendered on front-end with zero height and width is missing <svg> tag attributes "height" and "width".
Incorrect:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 30">
Correct:
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 49 30" width="49" height="30">
It works fine.
If the snippet works individually but size of div containing it in you code appears 0x0 then look into : Why is my div's height zero
Its usually caused when float is set.
<div>
<svg class="legend-square">
<defs>
<pattern id="pattern1" width="3" height="3" patternunits="userSpaceOnUse" patterntransform="rotate(-45)">
<rect width="2" height="3" transform="translate(0,0)" fill="purple"></rect>
</pattern>
</defs>
<rect width="12" height="12" fill="url(#pattern1)"></rect>
</svg>
</div>
You really haven't provided enough information. For instance, what is the parent element of your SVG?
Just because your <rect> has a width and hight, it doesn't mean your SVG does. SVG is not like HTML, where elements expand to fit their children. SVG is like the <canvas> element. You have to make sure it either explicitly (or implicitly) has a size.
You have not specified width or height attributes for your <svg> element, so they are both defaulting to "100%". What they are 100% of depends on what size the SVG's parent element is. Hence my first question above.
For an 'inline' SVG element you have to apply the styles, inside the svg element itself.
inside the <defs></defs> tags. Since it has its Own DOM[Document Object Model], Css Apllied to it from Outside, will have no effect.
You have Several different options for embeding an SVG, You can use it inline as in your example where you declare the <svg></svg> inside of your html/php document or you can use one of the many other methods listed below;
embed an: ..............................................<img src="../pathtoyourSvg"></img>
embed as an img with a fallback option: <img src="logo.png" srcset="logo.svg" alt="My logo">
use an: ....................................................<object type="image/svg+xml" data="image.svg">
<!-- Your fall back here -->
<img src="image.svg" />
</object>
use: .........................................................<embed type="image/svg+xml" src="image.svg" />
use an: ....................................................<iframe></iframe>
embed the Svg inside of a canvas element using Javascript:
var img = new Image();
img.onload = function() {
ctx.drawImage(img, 0, 0);
}
img.src = "path2your.svg";
You may Also Embed the Svg using Css Background image,
ie:
.mySvgContainer{
background-image:url('PathToMySvg');
}
But from the comments & Questions I have read, this need to be either Url or Base64 encoded, which seems a bit Hacky and not very convenient.
each of them have their own advantages and disadvantages.
Because of security reasons, some SVG embedding methods will block access to external resources including CSS, fonts and javascript. Especially when we have multiple images, ideally our embedding method should be able to refer to a single CSS, font or javascript file (to save resources) and be able to manipulate our embedded SVG.
Also worth mentioning that if you have display:flex; attached to an elemnet or its parent then the width and height values will have no effect on the flex items. So It may appear as 0, 0, in the console.
Some Useful Information & related questions:
Svg Coords & Units w3.org
Svg Width - Height
Applying Styles to an embedded Svg
You can wrap your svg element inside the html5 object element.
<style type="text/css">
object{
width:300px;
height:200px;
}
object svg{
width:100%;
height:100%;
}
</style>
<object>
<svg class="legend-square">
<defs>
<pattern id="pattern1" width="3"
height="3" patternunits="userSpaceOnUse" patterntransform="rotate(-45)">
<rect width="2" height="3" transform="translate(0,0)" fill="purple"></rect>
</pattern>
</defs>
<rect width="12" height="12" fill="url(#pattern1)"></rect>
</svg>
</object>
You can set height and width on the object element just link any other html element while you can set height width to 100% for SVG element. It will work. But first, test your SVG by opening the file directly in chrome.

Changing Clickable Area of an Image without Resizing Image

I am currently working on a PHP/Javascript project where an action occurs when an image is clicked. The image is small, so I would like to expand the clickable area to further around the image without enlarging the image itself. Is this possible? Below is a general idea of the structure of what I'm working on.
<g id="pictures">
<image id="marker_image" cx="145" cy="460" r="1" preserveAspectRatio="none"
x="136" y="451" width="18" height="18"
xmlns:xlink="http://www.w3.org/1999/xlink"
xlink:href="//link.thislink.com/image_assets/markers/pool.png"
style="opacity: 1" fill="#000000" fill-opacity="1" stroke="#000000"
stroke-opacity="1" stroke-width="2" stroke-linecap="round" stroke-
linejoin="round"></image>
</g>
I'm new to working with SVGs, but from what I've read, I think I can use the <g> to add padding?
Wrap you image in a div, make the div as big as you want using padding, and bind your action on the div instead of the img

Categories