Create a Gooey effect during a transition

Combining SVG filters with D3.js

Posted: May 31, 2015-Likes: 0-Comments: 2-Categories: D3.js, Tutorial-Tags: D3.js, SVG
You are here: ...
Home / Blog / D3.js / Create a Gooey effect during transitions in D3.js

A short post about perhaps not a very useful, but nonetheless rather fun to watch effect in SVGs applied to D3.js: Gooey effects!
(note: I do understand they are a bit heavy on CPU resources, but I have not yet had any problems so far)

Edit June 2016: I’ve now written a follow-up blog on the Gooey effect that shows even more and advanced uses of the effect in (data) visualizations. You can read all about it here.

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.

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 and then 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 printscreen of this version). And then I remembered the Gooey effects, 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 is 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 a 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 encodings themselves (such as the circles), but on the or svg element that contains the circles.

Create the svg and add the following line (you can also first create a g element and add this line below):



.style("filter", "url(#gooey)") //Set the filter on the container svg

The gooey is the id of the SVG filter that we still have to create. See an example below of how to add this line to the part where you create the SVG element



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 inbetween 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 taken 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!

Along a Line

Taken together a script using the SVG effect might look like this:



var margin = {top: 30, right: 30, bottom: 30, left: 30};
	width = 300 - margin.left - margin.right,
	height = 300 - margin.top - margin.bottom,;
	
//Create scale
var xScale = d3.scale.linear()
	.domain([0, 1])
	.range([0, width]);

//Create SVG
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 svg
	.attr("transform", "translate(" + margin.left + "," + margin.top + ")");

//SVG filter for the gooey effect
//Code taken 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','goo')
	.attr('operator','atop');	

//Append circle at center
svg.append("circle")
		.attr("class", "centerCircle")
		.attr("cx", 0)
		.attr("cy", 0)
		.attr("r", 20)
		.style("fill", "#81BC00");

//Create a circle that will move out of the center circle
svg.append("circle")
		.attr("class", "flyCircle")
		.attr("cx", 0)
		.attr("cy", 0)
		.attr("r", 15)
		.style("fill", "#81BC00")
		.each(update);	

//Continuously keep a circle flying out to a random location along the x-axis
function update() {
	var circle = d3.selectAll(".flyCircle");
		
	(function repeat() {
		circle
			.attr("cx", 0)
			.attr("r", 15)
			.transition().duration(1500)
				.attr("cx", xScale(Math.random()))
			.transition().duration(1000)
				.attr("r", 0)
			.each("end", repeat);			
	})();
}//update

Which turns into the following loop that keeps ejecting a circle from the big green circle

Rectangles

Because people seemed to like the effect, I created one more (also inspired by the original blog) of circles randomly flying out of a rectangle

For fun

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 here

Prev / Next Post
Comments (2)

Add comment

9 − eight =