0

I'm trying to create an SVG animation that smoothly blurs an element when it's clicked, then smoothly unblurs it when clicked again (and keeps alternating like that with each click).

So I have the following SVG:

<?xml version="1.0" standalone="no"?>
<svg width="1" height="1" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <filter id="blurred">
            <feGaussianBlur in="SourceGraphic" stdDeviation="0 0">
                <animate attributeType="XML" attributeName="stdDeviation" from="0 0" to="0 50" dur="0.4s" fill="freeze" />
            </feGaussianBlur>
        </filter>
        <filter id="unblurred">
            <feGaussianBlur in="SourceGraphic" stdDeviation="0 50">
                <animate attributeType="XML" attributeName="stdDeviation" from="0 50" to="0 0" dur="0.4s" fill="freeze" />
            </feGaussianBlur>
        </filter>
    </defs>
</svg>

And then I toggle which filter is shown with these functions:

function blurItem(item) {
    var background = item.find(".background");

    background.css("filter", "url(css/filter.svg#blurred)");
}

function unblurItem(item) {
    var background = item.find(".background");

    background.css("filter", "url(css/filter.svg#unblurred)");
}

The first time I click the element, it smoothly blurs just like it should. But when I click again, it unblurs without any animation. And then from that point on, it just toggles between blurred and unblurred on each click without any animation.

Why does the animation only work on the very first click, and how do I get it to work each time?


Here's a fiddle: http://jsfiddle.net/7Pcdp/2/

For some reason, with the SVG inline in the HTML in the fiddle, the animation doesn't work at all. If I split it out into a separate .svg file, then it'll animate in Firefox, but again only the first time.

daGUY
  • 27,055
  • 29
  • 75
  • 119
  • Have you tried it without having the SVG as a link out of interest ? – Ian Jun 11 '14 at 16:21
  • What do you mean? How else would I reference it? – daGUY Jun 11 '14 at 16:56
  • Is it possible to include an example jsfiddle, it may help to test ? – Ian Jun 11 '14 at 17:54
  • Updated my question with a link, but note that the animation doesn't work in JSFiddle with the SVG defined in the HTML section. You'll have to reproduce it locally and split the SVG out into a separate .svg file to see the animation (in Firefox). – daGUY Jun 11 '14 at 18:37

2 Answers2

1

Once you click on the background the animation timeline runs from 0s to 0.4s and then stops as the animation is over. The next time you click the document timeline is still 0.4s so nothing happens as the animations only run from 0s to 0.4s.

One way around this is to make the animations start="indefinite" and then begin them using javascript by calling beginElement on the animations. Like so...

<div class="background" style="background-image: url('https://www.google.com/images/srpr/logo11w.png');"></div>

<svg>
    <defs>
        <filter id="blurred">
            <feGaussianBlur in="SourceGraphic" stdDeviation="0 0">
                <animate id="blurredAnimation" attributeType="XML" attributeName="stdDeviation" from="0 0" to="2 50" dur="0.4s" fill="freeze" begin="indefinite" />
            </feGaussianBlur>
        </filter>
        <filter id="unblurred">
            <feGaussianBlur in="SourceGraphic" stdDeviation="2 50">
                <animate id="unblurredAnimation" attributeType="XML" attributeName="stdDeviation" from="2 50" to="0 0" dur="0.4s" fill="freeze" begin="indefinite" />
            </feGaussianBlur>
        </filter>
    </defs>
</svg>

$(document).on("click", ".background", function(){ var background = $(this); toggleBlur(background); });

function toggleBlur(background) {
    if (!(background.hasClass("blurred"))) {
        background.addClass("blurred");
        background.css({
            filter: "url(#blurred)",
            webkitFilter: "url(#blurred)"
        });
        document.getElementById("blurredAnimation").beginElement();
    } else {
        background.removeClass("blurred");
        background.css({
            filter: "url(#unblurred)",
            webkitFilter: "url(#unblurred)"
        });
        document.getElementById("unblurredAnimation").beginElement();
    }
};
Robert Longson
  • 118,664
  • 26
  • 252
  • 242
  • Wow! That helps a lot. One weird thing though is that when I click again to unblur the image, in Safari it leaves behind an artifact of the blurred version below it: https://www.dropbox.com/s/scg3s9qa06bxe0e/artifact.png. No such problem in Firefox. Any ideas? (I tried wrapping the image in another `div` with `overflow: hidden;`, but it didn't help). – daGUY Jun 11 '14 at 19:44
  • I only contribute to Firefox. Safari bugs aren't therefore down to me! – Robert Longson Jun 11 '14 at 19:49
-1

I got the same problem on Safari. The animations worked well on click. They worked again in FF and Chrome (IE does not work at all), but not in Safari.

Safari just did the animation once, but never twice.

Workaround: After closing the menu (so the svg was in initial state again) i replaced the element with itself. After that the animation could be started again, as Safari started it "from scratch"

Only disadvantage: You need to replace the element with JavaScript.

This piece of code helped me out:

window.setTimeout(function(){
    $('svg#button').replaceWith('<svg id="button" viewBox="-374 350 210 70"><polygon style="stroke:#dfdfdf;stroke-width:5;stroke-linejoin:round" fill="#eeeeee" points="-366.500 308.500, -366.500 253.500, -196.900 253.500, -171.500 281.000, -196.900 308.500, -366.500 308.500"><animate id="animation-to-check" begin="indefinite" fill="freeze" attributeName="points" dur="500ms" to="-366.500 497.500, -366.500 253.500, -171.500 253.500, -171.500 281.000, -171.500 497.500, -366.500 497.500" values="-366.500 308.500, -366.500 253.500, -196.900 253.500, -171.500 281.000, -196.900 308.500, -366.500 308.500;-366.500 308.500, -366.500 253.500, -171.500 253.500, -171.500 281.000, -171.500 308.500, -366.500 308.500;-366.500 497.500, -366.500 253.500, -171.500 253.500, -171.500 281.000, -171.500 497.500, -366.500 497.500"/><animate id="animation-to-star" begin="indefinite" fill="freeze" attributeName="points" dur="500ms" to="-366.500 308.500, -366.500 253.500, -196.900 253.500, -171.500 281.000, -196.900 308.500, -366.500 308.500" values="-366.500 497.500, -366.500 253.500, -171.500 253.500, -171.500 281.000, -171.500 497.500, -366.500 497.500;-366.500 308.500, -366.500 253.500, -171.500 253.500, -171.500 281.000, -171.500 308.500, -366.500 308.500;-366.500 308.500, -366.500 253.500, -196.900 253.500, -171.500 281.000, -196.900 308.500, -366.500 308.500;"/></polygon></svg>');
},700);

Maybe you could use a placeholder onload, so you don´t need to load the svg-sources twice...

droeti
  • 9
  • 3