【问题标题】:How to animate an SVG filter in IE11?如何在 IE11 中为 SVG 过滤器设置动画?
【发布时间】:2017-10-13 15:25:38
【问题描述】:

我专门使用 IE11(不要问),因此解决方案不必在任何其他浏览器中工作。我有一个包含多个图像的 SVG,我在其上应用了多个过滤器。其中之一是使给定图像变暗的滤镜。我可以很好地打开和关闭它,并改变滤镜变暗的量,但我似乎无法让它动画化;而是在最后分配的过滤器值处应用过滤器,没有任何时间延迟(在这种情况下,斜率为 0.5,中间变暗)。

这是 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>

下面是相关的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");
});

我希望超时有问题(如果有更好的方法,我很感兴趣。我可以使用 jquery 和其他库,但我更喜欢原生 JS,因为客户端对传递 PageSpeed 很挑剔见解)。

【问题讨论】:

  • 我发现超时是立即触发的,因为语法错误。在上面的表格中, DarkenDown(...), 100 不起作用,但 DarkenDown, 100 起作用。但是我需要传递参数。另一种方法是 timeout1 = window.setTimeout(function() { DarkenDown(arguments); }, 2000);但是,我在获取要传递的元素时遇到问题,因此这不是一个完整的解决方案。
  • 我认为问题在于您将 SVG 片段的命名空间设置为“SVG”。如果您只是将 "xmlns="w3.org/2000/svg" 留在外面 - 元素将保留在 HTML5 命名空间中(默认),您应该可以正常使用 jquery。

标签: javascript svg internet-explorer-11 svg-filters


【解决方案1】:

所以问题的一部分是 setTimeout 的语法,但它也不接受元素作为参数(不知道为什么)。所以我稍微改变了逻辑,并创建了 5 个独立的过滤器,每个过滤器都有不同的斜率,并将遍历所有需要更改其过滤器的图像的循环移动到一个从超时调用的辅助函数。然后我做了五次不同的超时(所以它没有被覆盖)。这是修改后的 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>

这是相关的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);
}

但是,虽然这可以满足我的要求,但它很脆弱。例如,如果我想更改转换中的步骤数,我会遇到更多的超时和更多的过滤器。有没有更有效、更不脆弱的方法?

【讨论】:

    【解决方案2】:

    window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.9), 100);就像写:

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

    您正在调用 DarkenDown,然后创建一个不会调用任何内容的超时。

    您在这里至少有 2 个解决方案。您可以创建一个调用DarkenDown 的函数或使用bind 来定义参数的值:

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

    或者

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-20
      相关资源
      最近更新 更多