A short post about perhaps not a very useful, but nonetheless rather fun to watch effect in SVGs applied to d3.js: gooey effects!
I came across a blog showing several SVG gooey effects applied to DOM elements a while ago and thought it looked interesting, but I did not yet have something in mind where it would make sense to apply.
I’ve also written a follow-up blog on the gooey effect that shows even more and advanced uses of the effect in (data) visualizations.
Last week I was working on a project where I wanted to show the speeds of a ball being hit by a golf club. I was looking for an effect where it sort-of looked like a golf ball being hit/ejected out in the field.
I had a green circle at the zero point, an x axis towards the right. Smaller green circles were moved from the zero point towards the actual speed. It looked fine, but a bit boring actually (I forgot to take a print screen of this version). And then I remembered the gooey effect. Maybe that could spice things up a bit.
It took me an hour or two to finally get it to work, although in the end it’s amazingly easy. I was just doing it the wrong way for practically two hours (ー_ー﹡; )
Below you can see a small animated gif of the end result for my ball speed chart. As you can see, the gooey effect has no real added value besides making the animation a bit more fun to watch ｡^‿^｡
Creating the gooey effect
So, how to add a gooey effect to d3.js created elements? You’ll have to attach an SVG effect to the container element. This is very important (which I did wrong for some time). Do not set the filter on the visual elements themselves (such as the circles), but on the
svg element that contains the circles.
svg and add a line to set a filter style on the
g. The name
gooey is the
id of the SVG filter that we still have to create.
var svg = d3.select(".chart").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .style("filter", "url(#gooey)") //Set the filter on the container .attr("transform", "translate(" + margin.left + "," + margin.top + ")");
The SVG statement from Lucas Bebber’s post now needs to be turned into d3.js code so we can create this filter right in between the rest of the script
<svg xmlns="http://www.w3.org/2000/svg" version="1.1"> <defs> <filter id="gooey"> <feGaussianBlur in="SourceGraphic" stdDeviation="10" result="blur"/> <feColorMatrix in="blur" mode="matrix" values="1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7" result="gooey"/> <feComposite in="SourceGraphic" in2="gooey" operator="atop"/> </filter> </defs> </svg>
I used the SVG2D3 page that turns any SVG code into D3 code. It won’t be beautiful code, but it works :)
//SVG filter for the gooey effect //Code from http://tympanus.net/codrops/2015/03/10/creative-gooey-effects/ var defs = svg.append('defs'); var filter = defs.append('filter').attr('id','gooey'); filter.append('feGaussianBlur') .attr('in','SourceGraphic') .attr('stdDeviation','10') .attr('result','blur'); filter.append('feColorMatrix') .attr('in','blur') .attr('mode','matrix') .attr('values','1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 18 -7') .attr('result','gooey'); filter.append('feComposite') .attr('in','SourceGraphic') .attr('in2','gooey') .attr('operator','atop');
And that’s really all there is to add. Now all circles or other elements that get created within the SVG that move over each other will have the gooey effect. That was really simple right!
Here are a few very minimal examples using the gooey effect during movement of the elements
Just to illustrate, the gooey effect is applied to all elements. So if you make the circle from the first example so small that the circles almost touch each other, they will start to merge as well
Maybe you’ll never want to use this effect, but if you do, I hope this small post helped to explain how. If you enjoyed this effect you can read my follow-up blog on the gooey effect that shows even more and advanced uses in (data) visualizations.
Note The gooey effect filters are a bit heavy on CPU resources