Skip to content

Instantly share code, notes, and snippets.

@cpbotha
Last active January 10, 2017 00:49
Show Gist options
  • Save cpbotha/5205319 to your computer and use it in GitHub Desktop.
Save cpbotha/5205319 to your computer and use it in GitHub Desktop.
d3.js breathing drop shadows

Look ma, those drop shadows are breathing!

Your eyes want you to believe that the blocks are hovering up and down, when in fact only the drop shadow is being translated out and in again.

Follow me on https://twitter.com/cpbotha for even more fun, or see my other d3 blocks: http://bl.ocks.org/cpbotha

// d3.js animated drop shadow example
// put together by http://charlbotha.com/
// see http://bl.ocks.org/cpbotha/5205319 for the live action version
// it demonstrates:
// 1. drop shadows with SVG filters
// 2. repeated animation with transition + "end" callback
// 3. the hoving in and out of the page illusion that results from
// manipulating the shadow.
var items = [
{x : 50, y : 10},
{x : 100, y: 170},
{x : 320, y: 70}
];
// we can increase this, everything will scale up with us
var w=960,h=500,
svg=d3.select("#chart")
.append("svg")
.attr("width",w)
.attr("height",h);
// filter chain comes from:
// https://github.com/wbzyl/d3-notes/blob/master/hello-drop-shadow.html
// cpbotha added explanatory comments
// read more about SVG filter effects here: http://www.w3.org/TR/SVG/filters.html
// filters go in defs element
var defs = svg.append("defs");
// create filter with id #drop-shadow
// height=130% so that the shadow is not clipped
var filter = defs.append("filter")
.attr("id", "drop-shadow")
.attr("height", "150%");
// SourceAlpha refers to opacity of graphic that this filter will be applied to
// convolve that with a Gaussian with standard deviation 3 and store result
// in blur
filter.append("feGaussianBlur")
.attr("in", "SourceAlpha")
.attr("stdDeviation", 5)
.attr("result", "blur");
// translate output of Gaussian blur to the right and downwards with 2px
// store result in offsetBlur
var feOffset = filter.append("feOffset")
.attr("in", "blur")
.attr("dx", 5)
.attr("dy", 5)
.attr("result", "offsetBlur");
// overlay original SourceGraphic over translated blurred opacity by using
// feMerge filter. Order of specifying inputs is important!
var feMerge = filter.append("feMerge");
feMerge.append("feMergeNode")
.attr("in", "offsetBlur")
feMerge.append("feMergeNode")
.attr("in", "SourceGraphic");
// for each rendered node, apply #drop-shadow filter
var item = svg.selectAll("rect")
.data(items)
.enter().append("rect")
.attr("width", 170)
.attr("height", 100)
.attr("fill", "steelblue")
.attr("stroke-width", 2)
.style("filter", "url(#drop-shadow)")
.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });
// here's the bit of code that makes the blocks breathe for you
var dest_min = 2, dest_max = 10, dest = dest_min;
// when floater is called:
// 1. it flips the destination
// 2. starts a transition to the new destination
// 3. asks to be called again when the transition reaches it
var floater = function() {
if (dest == dest_min) {
dest = dest_max;
}
else {
dest = dest_min;
}
feOffset.transition()
.duration(600)
.attr("dx", dest)
.attr("dy", dest)
.each("end", floater)
}
// start the whole business
floater()
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>d3 drop shadow example</title>
</head>
<style>
body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
width: 960px;
height: 500px;
position: relative;
}
</style>
<body>
<div id="chart">
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script type="text/javascript" src="breathing_dropshadow.js"></script>
</body>
</html>
@vincentpurcell
Copy link

You just need to change the "in" attribute on "feGaussianBlur" to "SourceGraphic" from "SourceAlpha" and then the shadow will be the fill color set of the source. See example 3: http://www.w3schools.com/graphics/svg_feoffset.asp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment