Skip to content

Instantly share code, notes, and snippets.

@nbremer
Last active June 18, 2016 20:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nbremer/077ef487fefcff72a02605422298e2b3 to your computer and use it in GitHub Desktop.
Save nbremer/077ef487fefcff72a02605422298e2b3 to your computer and use it in GitHub Desktop.
Motion blur - Diagonal movement & Multiple filters

This example was used in my blog on Creating real-life based motion effects in d3.js visuals, which is part of the SVGs beyond mere shapes series

This is an example of using a SVG gaussian blur filter in one direction to mimic motion blur that occurs in real life. Although the blur can only be applied in either the x or y direction, we can use a transform of a group element to make it appear as if the element has a blur along any angle. Also this example shows how to create, apply and manipulate a motion blur filter separately for each circle

Other examples about motion blur are

Built with blockbuilder.org

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<!-- D3.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.6/d3.min.js" charset="utf-8"></script>
<!-- Google fonts -->
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300,400' rel='stylesheet' type='text/css'>
<style>
body {
text-align: center;
font-family: 'Open Sans', sans-serif;
font-weight: 400;
}
.title {
font-size: 24px;
fill: #4F4F4F;
font-weight: 300;
text-anchor: middle;
}
#explanation {
font-size: 12px;
color: #737373;
}
</style>
</head>
<body>
<div id="movingCircles"></div>
<div id="explanation">Click anywhere to turn on/off the motion blur filter</div>
<script language="javascript" type="text/javascript">
///////////////////////////////////////////////////////////////////////////
//////////////////// Set up and initiate svg containers ///////////////////
///////////////////////////////////////////////////////////////////////////
var margin = {
top: 50,
right: 50,
bottom: 20,
left: 50
};
var width = document.getElementById('movingCircles').offsetWidth - margin.left - margin.right - 10,
height = 400;
//SVG container
var svg = d3.select('#movingCircles')
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.on("click", switchBlur)
.append("g")
.attr("transform", "translate(" + (margin.left + width/2) + "," + (margin.top + height/2) + ")");
var color = "#F92672";
//Title on top
svg.append("text")
.attr("class", "title")
.attr("x", 0)
.attr("y", -height/2 - 20)
.style("text-anchor", "middle")
.text("With motion blur filter");
///////////////////////////////////////////////////////////////////////////
//////////////////// Switch between blur and no blur //////////////////////
///////////////////////////////////////////////////////////////////////////
//Switch between blur filter and no filter on click
var blurOn = true;
function switchBlur() {
//Change title
d3.selectAll(".title")
.text(blurOn ? "Without motion blur filter" : "With motion blur filter");
d3.selectAll(".flyCircle")
.style("filter", function(d,i) { return blurOn ? "none" : "url(#motionBlurFilter-"+i+")"; });
blurOn = blurOn ? false : true;
}//switchBlur
///////////////////////////////////////////////////////////////////////////
//////////////////////////////// Create Data //////////////////////////////
///////////////////////////////////////////////////////////////////////////
//Create the circles that will move out and in the center circle
var steps = 15;
var flyCircleData = [];
for (var i = 0; i < steps; i++) {
flyCircleData.push({
id: i,
fixedAngle: (i/steps)*(2*Math.PI)+0.01
})
}//for i
///////////////////////////////////////////////////////////////////////////
//////////////////////////// Create fuzzy filter //////////////////////////
///////////////////////////////////////////////////////////////////////////
//SVG filter for the fuzzy effect
//Code based on http://tympanus.net/codrops/2015/04/08/motion-blur-effect-svg/
var defs = svg.append("defs");
//Create a filter per circle so we can adjust the fuzzyness per circle that is flying out
defs.selectAll(".flyCircleFilters")
.data(flyCircleData)
.enter().append("filter")
.attr("class", "flyCircleFilters")
.attr("id",function(d,i) { return "motionBlurFilter-"+i; })
.attr("width", "300%") //increase the width of the filter region to remove blur "boundary"
.attr("x", "-100%") //make sure the center of the "width" lies in the middle
.attr("height", "200%")
.attr("y", "-50%")
.attr("color-interpolation-filters","sRGB") //to fix safari: http://stackoverflow.com/questions/24295043/svg-gaussian-blur-in-safari-unexpectedly-lightens-image
.append("feGaussianBlur")
.attr("class", "blurValues")
.attr("in","SourceGraphic")
.attr("stdDeviation","0,0");
///////////////////////////////////////////////////////////////////////////
//////////////////////// Create fly out circles ///////////////////////////
///////////////////////////////////////////////////////////////////////////
var circleWrapper = svg.append("g")
.attr("class", "circleWrapper");
//Since we can only do a blur in the x and y direction the group should be rotated
//so the coordinated system turns along with the direction the circle
//will be flying out from
var flyCircles = circleWrapper.selectAll(".flyCircle")
.data(flyCircleData)
.enter().append("circle")
.attr("class", "flyCircle")
.attr("transform", function(d,i) { return "rotate(" + (d.fixedAngle*180/Math.PI - 90) + ")"; })
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 12)
.style("fill", color)
.style("filter", function(d,i) { return "url(#motionBlurFilter-"+i+")"; });
//Append circle at center
circleWrapper.append("circle")
.attr("class", "centerCircle")
.attr("cx", 0)
.attr("cy", 0)
.attr("r", 25)
.style("fill", color);
repeat();
///////////////////////////////////////////////////////////////////////////
/////////////////////// Move in and out function //////////////////////////
///////////////////////////////////////////////////////////////////////////
//Continuously moves the circles outward and inward
function repeat() {
var dur = 1000,
del = 500;
//Interpolate the fuzzyness
d3.selectAll(".blurValues")
.transition().duration(dur*0.1)
.delay(function(d,i) { return i*del; })
.attrTween("stdDeviation", function() { return d3.interpolateString("0 0", "9 0"); })
.transition().duration(dur*0.2)
.attrTween("stdDeviation", function() { return d3.interpolateString("9 0", "0 0"); })
.transition().duration(dur*0.4) //Another one for the circles moving back in
.delay(function(d,i) { return steps*del + i*del; })
.attrTween("stdDeviation", function() { return d3.interpolateString("0 0", "9 0"); })
.transition().duration(dur*0.3)
.attrTween("stdDeviation", function() { return d3.interpolateString("9 0", "0 0"); });
//Move circles in an out
d3.selectAll(".flyCircle")
.transition("flyOut").duration(dur)
.delay(function(d,i) { return d.id*del; })
.ease("elastic")
.attr("cx", height/2*0.8 )
.transition("flyIn").duration(dur/3)
.delay(function(d,i) { return steps*del + d.id*del; })
.ease("exp")
.attr("cx", 0)
.call(endall, repeat);
}//repeat
//Function to only run once after the last transition ends
function endall(transition, callback) {
var n = 0;
transition
.each(function() { ++n; })
.each("end", function() { if (!--n) callback.apply(this, arguments); });
}//endall
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment