Question

I'm trying to create a dynamic blur effect, that can be modified with javascript on the fly.

To start with, I'm using this really simple svg filter:

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<filter id="blur">
<feGaussianBlur stdDeviation="0" />
</filter>
</svg>

The stdDeviation starts at 0, and I want to be able to change that with the javascript. I've tried a few different things, but I haven't quite been able to nail it down.

Firstly, (and I should note that I am using jQuery) I tried to simply select the feGaussianBlur element and modify it's attribute:

$('feGaussianBlur').attr('stdDeviation',5);

This didn't replace the already existing attribute like I expected, but rather, added another, leaving me with <feGaussianBlur stdDeviation="0" stdDeviation="5" /> Removing the original stdDeviation from the HTML made it so that there was only one attribute after the change, but it had no effect.

Next, I attempted to simply replace the contents of the filter with the new one:

$('filter#blur').html('<feGaussianBlur stdDeviation="5" />');

This time, not only did it not succeed in changing, but it caused the element that this filter is applied to, to disappear completely (I assume the filter was corrupted, or somesuch).

I even tried re-applying the css declaration for the filter afterwards, for both of the previous cases.

The one thing that I tried that DID work, was to build out 10 different filters, with 10 different values, and then rather than changing the SVG with the javascript, I simply reassigned the css to a different filter ID. To be honest, this approach seems a little more.. proper? The big downside though is that it isn't very versatile, and takes a lot of work to change things. Also, I'd prefer to use values with a decimal place, which would require 100 filter declarations to accomplish.

So, my question is... Is there a good way to dynamically modify an SVG filter (in my case, the blur filter specifically) using javascript? If there is, is it a respectable approach, in terms of semantics and standards? If nothing else, I'm more than willing to fall back to my solution of using a few (I can live without decimals) filters and swapping them out, but I want to explore my options first.

Or, if you don't have a solution, but could at least explain to me why my first couple attempts did not work, please let me know! I'm curious what the reasons are.

Was it helpful?

Solution 2

This question is old, but it's worth answering.

There are two reasons why setting/getting attributes with jQuery on SVG elements might not work:

1. Letter case

jQuery has this code in its attr() implementation:

if ( .... || !jQuery.isXMLDoc( elem ) ) {
   name = name.toLowerCase();

In other words, it reads/sets the attribute stddeviation, not stdDeviation.

2. Attributes vs properties

In old jQuery versions, the propetry, instead of the attribute, is used. This casuses things to fail if the property is not a simple string value (E.g., "For an SVG element, className is not a string, but an instance of SVGAnimatedString". E.g., There isn't really a stdDeviation property at all, but X and Y ones). See the documentation of prop() and attr() for more information.

So, what to do?

Here's an implementation of xattr(), which works where attr() fails, because it doesn't try to be smart. Use it instead of attr().

jQuery.fn.xattr = function(name, val) {
  if (val !== undefined) {
    this.each(function() {
      this.setAttribute(name, val);
    });
    return this;
  }
  else {
    if (this.length)
      return this[0].getAttribute(name);
  }
};

OTHER TIPS

It would be simpler to do this using ordinary DOM rather than jquery. Move the id to the feGaussianBlur element

<svg version="1.1" xmlns="http://www.w3.org/2000/svg">
<filter>
<feGaussianBlur id="blur" stdDeviation="0" />
</filter>
</svg>

And then

document.getElementById("blur").setAttribute("stdDeviation", "5");

or alternatively

document.getElementById("blur").setStdDeviation(5, 5);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top