简体   繁体   English

如何在IE11中设置SVG滤镜的动画?

[英]How to animate an SVG filter in IE11?

I'm working specifically with IE11 (don't ask) so a solution doesn't have to work in any other browser. 我专门使用IE11(不要问),因此解决方案不必在任何其他浏览器中都可以使用。 I have an SVG containing several images, on which I am applying several filters. 我有一个包含多个图像的SVG,在该图像上应用了多个滤镜。 One of them is a filter that darkens a given image. 其中之一是使给定图像变暗的过滤器。 I can turn it on and off just fine, and alter the amount that the filter darkens, but I can't seem to get it to animate; 我可以很好地打开和关闭它,并更改滤镜变暗的数量,但是我似乎无法对其进行动画处理。 instead the filter is applied without any time delay at the last assigned filter values (in this case, a slope of 0.5, which is halfway darkened). 取而代之的是,在最后分配的滤波器值(在本例中为0.5的斜率,将其变暗)上没有任何时间延迟地应用滤波器。

Here's a simplified version of the svg: 这是svg的简化版本:

<svg id="svgcanvas" width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">       
        <filter id="darkenMe">
            <feComponentTransfer>
                <feFuncR id="FR" type="linear" slope="1.0"></feFuncR>
                <feFuncG id="FG" type="linear" slope="1.0"></feFuncG>
                <feFuncB id="FB" type="linear" slope="1.0"></feFuncB>
            </feComponentTransfer>
        </filter>
        <image id="whatever" href="./images/whatever.png" y="0" x="0" width="200" height="200"></image>
</svg>

Here are the relevant JS functions: 以下是相关的JS函数:

function applySelectiveDarken(el) {
    var elementsToDarken = Array.prototype.slice.call(document.getElementsByClassName("elements-to-darken"),0);
    for (i = 0; i < elementsToDarken.length; i++) {
        if (elementsToDarken[i].id == el) {
            //skip, we just need to darken everything but this
        } else {
            elementsToDarken[i].setAttribute("filter","url('#darkenMe')");
        }
    }
    animateDarkenDown();
}

function DarkenDown(slopeR, slopeB, slopeG, slope) {
    slopeR.setAttribute("slope",slope);
    slopeG.setAttribute("slope",slope);
    slopeB.setAttribute("slope",slope);
 }

var timeoutID, timeout1, timeout2, timeout3, timeout4, timeout5;
function animateDarkenDown() {
    var slopeR = document.getElementById("FR");
    var slopeG = document.getElementById("FG");
    var slopeB = document.getElementById("FB");
    var slope = 1.0;

    // my first attempt
    /*for (i = 0; i < 5; i++) {
        timeout = window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, slope), 100);
        slope = slope - 0.1;
    }*/

    //second attempt, also not working, behaves the same as above
    timeout1 = window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.9), 100);
    timeout2 = window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.8), 200);
    timeout3 = window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.7), 300);
    timeout4 = window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.6), 400);
    timeout5 = window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.5), 500);
}

document.getElementById("whatever").addEventListener("mouseover", function(e) {
    applySelectiveDarken("whatever");
});

I'm hoping it's something wrong with the timeout (and if there is a better approach, I'm interested. I can use jquery and other libraries, but I'd prefer native JS as the client is picky about passing PageSpeed Insights). 我希望超时有问题(如果有更好的方法,我很感兴趣。我可以使用jquery和其他库,但是我更喜欢本机JS,因为客户端对于传递PageSpeed Insights十分挑剔)。

So part of the problem was the syntax of the setTimeout, but it also wasn't accepting an element as an argument (have no idea why). 因此,问题的一部分是setTimeout的语法,但它也不接受元素作为参数(不知道为什么)。 So I changed the logic a bit, and created 5 separate filters each with a different slope, and moved the loop that goes through all the images that need to have their filter changed into a helper function that gets called from a timeout. 因此,我稍微改变了逻辑,创建了5个单独的滤镜,每个滤镜具有不同的斜率,然后将遍历所有需要更改滤镜的所有图像的循环移动到一个从超时中调用的帮助函数。 I then did five different timeouts (so it's not being overwritten). 然后,我做了五个不同的超时(因此不会被覆盖)。 Here's the revised SVG: 这是修改后的SVG:

<svg id="svgcanvas" width="200" height="200" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <filter id="darkenMe">
        <feComponentTransfer>
            <feFuncR id="FR" type="linear" slope="1.0"></feFuncR>
            <feFuncG id="FG" type="linear" slope="1.0"></feFuncG>
            <feFuncB id="FB" type="linear" slope="1.0"></feFuncB>
        </feComponentTransfer>
    </filter>
    <filter id="darkenMe2">
        <feComponentTransfer>
            <feFuncR type="linear" slope="0.9"></feFuncR>
            <feFuncG type="linear" slope="0.9"></feFuncG>
            <feFuncB type="linear" slope="0.9"></feFuncB>
        </feComponentTransfer>
    </filter>
    <filter id="darkenMe3">
        <feComponentTransfer>
            <feFuncR type="linear" slope="0.8"></feFuncR>
            <feFuncG type="linear" slope="0.8"></feFuncG>
            <feFuncB type="linear" slope="0.8"></feFuncB>
        </feComponentTransfer>
    </filter>
    <filter id="darkenMe4">
        <feComponentTransfer>
            <feFuncR type="linear" slope="0.7"></feFuncR>
            <feFuncG type="linear" slope="0.7"></feFuncG>
            <feFuncB type="linear" slope="0.7"></feFuncB>
        </feComponentTransfer>
    </filter>
    <filter id="darkenMe5">
        <feComponentTransfer>
            <feFuncR type="linear" slope="0.6"></feFuncR>
            <feFuncG type="linear" slope="0.6"></feFuncG>
            <feFuncB type="linear" slope="0.6"></feFuncB>
        </feComponentTransfer>
    </filter>
    <image id="whatever" href="./images/whatever.png" y="0" x="0" width="200" height="200"></image>
</svg>

Here's the relevant JS: 这是相关的JS:

function filterHelper(el,filter) {
    var elementsToChange = Array.prototype.slice.call(document.getElementsByClassName("apple-table"),0);
    for (i = 0; i < elementsToChange.length; i++) {
        if (elementsToChange[i].id == el) {
            //skip
        } else {
            elementsToChange[i].setAttribute("filter",filter);
        }
    }
}

var timeoutID, timeout1, timeout2, timeout3, timeout4, timeout5;

function applySelectiveDarken(el) {
    timeout1 = window.setTimeout(function() {
        filterHelper(el,"url('#darkenMe)");
    }, 50);
    timeout2 = window.setTimeout(function() {
        filterHelper(el,"url('#darkenMe2)");
    }, 100);
    timeout3 = window.setTimeout(function() {
        filterHelper(el,"url('#darkenMe3)");
    }, 150);
    timeout4 = window.setTimeout(function() {
        filterHelper(el,"url('#darkenMe4)");
    }, 200);
    timeout5 = window.setTimeout(function() {
        filterHelper(el,"url('#darkenMe5)");
    }, 250);
}

However, while this does what I want, it's fragile. 但是,尽管这样做符合我的要求,但它仍然很脆弱。 For instance, if I want to change the number of steps in the transition I'm stuck making more timeouts and more filters. 例如,如果我想更改转换中的步骤数,则我将停留更多的超时时间和更多的过滤器。 Is there a more efficient, less fragile approach? 有没有更有效,更不脆弱的方法?

Writing window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.9), 100); 编写window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.9), 100); is like writing: 就像写:

var result = DarkenDown(slopeR, slopeG, slopeB, 0.9);
window.setTimeout(result, 100);

You are calling DarkenDown then creating a timeout that will call nothing. 您正在调用DarkenDown然后创建一个超时,该超时将不进行任何调用。

You have at least 2 solutions here. 您在这里至少有2个解决方案。 You can create a function that will call DarkenDown or use bind to define the value of the arguments: 您可以创建一个函数来调用DarkenDown或使用bind来定义参数的值:

window.setTimeout(function() { DarkenDown(slopeR, slopeG, slopeB, 0.9) }, 100);

Or 要么

window.setTimeout(DarkenDown.bind(slopeR, slopeG, slopeB, 0.9), 100);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM