2016-01-21 4 views
0

Я работаю специально с IE11 (не спрашивайте), поэтому решение не должно работать ни в одном другом браузере. У меня есть SVG, содержащий несколько изображений, на которых я применяю несколько фильтров. Один из них - это фильтр, который затемняет данное изображение. Я могу включить его и выключить, и изменить количество, которое фильтр темнеет, но я не могу заставить его оживить; вместо этого фильтр применяется без какой-либо временной задержки при последних присвоенных значениях фильтра (в этом случае наклон 0,5, который на полпути затемнен).Как оживить SVG-фильтр в IE11?

Вот упрощенная версия 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 ​​Insights).

+0

я обнаружил, что тайм-аут был немедленно запуска, потому что синтаксис был неправ. В приведенной выше форме DarkenDown (...), 100 не работает, но DarkenDown, 100. Однако мне нужно передать аргументы. Альтернативой является timeout1 = window.setTimeout (function() { DarkenDown (аргументы); }, 2000); Однако у меня возникли проблемы с получением элемента для входа, поэтому это не полное исправление. –

+0

Я думаю, проблема в том, что вы устанавливаете пространство имен фрагмента SVG на «SVG». Если вы просто оставите «xmlns =» http://www.w3.org/2000/svg «out», элементы останутся в пространстве имен HTML5 (по умолчанию), и вы сможете нормально использовать обычный jquery. –

ответ

0

Таким образом, частью проблемы был синтаксис 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); 
} 

Однако, в то время как это делает то, что я хочу, это хрупкая. Например, если я хочу изменить количество шагов в процессе перехода, я застрял, делая больше тайм-аутов и больше фильтров. Существует ли более эффективный, менее хрупкий подход?

0

Запись window.setTimeout(DarkenDown(slopeR, slopeG, slopeB, 0.9), 100);, как письма:

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

Вы вызываете DarkenDown затем создать тайм-аут, который не будет вызывать ничего.

У вас есть как минимум 2 решения. Вы можете создать функцию, которая будет вызывать DarkenDown или использовать привязку для определения значения аргументов:

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

Или

window.setTimeout(DarkenDown.bind(slopeR, slopeG, slopeB, 0.9), 100); 
Смежные вопросы