Skip to content

Instantly share code, notes, and snippets.

@pbogden
Last active September 14, 2018 10:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pbogden/227b95bff3e4aaa723011cf4357c56f6 to your computer and use it in GitHub Desktop.
Save pbogden/227b95bff3e4aaa723011cf4357c56f6 to your computer and use it in GitHub Desktop.
drop-shadow

Drop shadow

Uses several SVG elements.

  • SVG filter
    • SVG container for atomic filter operations.
    • Note: The CSS filter version is experimental (MDN).
    • MDN reference also describes the experimental CSS drop-shadow() function
  • SVG feGaussianBlur
    • SVG filter primitive blurs the input image by the amount specified in stdDeviation, which defines the bell-curve.
  • SVG feOffset
    • SVG filter primitive blurs the input image by the amount specified in stdDeviation, which defines the bell-curve.
  • SVG feMerge
    • Allows filter operations to be applied concurrently instead of sequentially using feMergeNode.
  • SVG feMergeNode
    • feMergeNode takes the result of another filter to be processed by its parent .

Raw SVG in an <img> element

SVG drop shadow used in SVG button

<!DOCTYPE html>
<meta charset="utf-8">
<title>drop shadow buttons</title>
<style>
text {
-webkit-user-select: none; /* webkit (safari, chrome) browsers */
-moz-user-select: none; /* mozilla browsers */
-khtml-user-select: none; /* webkit (konqueror) browsers */
-ms-user-select: none; /* IE10+ */
user-select: none;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width = 960, height = 500;
var padding = 5, radius = 3;
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
var g0 = svg.append('g')
.attr('class', 'button')
.attr('transform', 'translate(' + [width / 4, height / 4] +')')
addButton(g0, 'Hello, world!');
var g1 = svg.append('g')
.attr('class', 'button')
.attr('transform', 'translate(' + [width / 2, height / 2] +')')
addButton(g1, "I'm here too!");
// Add drop shadow to the rect
var rect = g0.select('rect');
defineShadow(g0);
rect.attr('filter', 'url(#dropShadow)')
g1.select('rect').attr('filter', 'url(#dropShadow)')
function toggleShadow() {
var rect = d3.select(this);
rect.attr('filter', function() { return (rect.attr('filter')) ? null : 'url(#dropShadow)'; })
}
function defineShadow(g) {
var defs = g.append('defs')
var shadow = defs.append('filter')
.attr('id', 'dropShadow')
.attr('x', + rect.attr('x') - padding)
.attr('y', + rect.attr('y') - padding)
.attr('width', + rect.attr('width') + 10 * padding)
.attr('height', + rect.attr('height') + 10 * padding)
shadow.append('feGaussianBlur')
.attr('in', 'SourceAlpha')
.attr('stdDeviation', '5')
shadow.append('feOffset')
.attr('dx', '2')
.attr('dy', '4')
var merge = shadow.append('feMerge')
merge.append('feMergeNode')
merge.append('feMergeNode').attr('in', 'SourceGraphic');
}
function addButton(g, label) {
// Button text
var text = g.append('text')
.style('font-size', '24px')
.style('pointer-events', 'none')
.text(label);
// Button based on text dimensions
var bbox = text.node().getBBox();
var rect = g.insert('rect', 'text')
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + 2 * padding)
.attr("height", bbox.height + 2 * padding)
.attr('rx', radius)
.attr('ry', radius)
.style('fill', '#aaa')
.style('stroke', '#000')
.on('click', toggleShadow)
}
</script>
<!DOCTYPE html>
<meta charset="utf-8">
<title>drop shadow</title>
<style>
text {
-webkit-user-select: none; /* webkit (safari, chrome) browsers */
-moz-user-select: none; /* mozilla browsers */
-khtml-user-select: none; /* webkit (konqueror) browsers */
-ms-user-select: none; /* IE10+ */
user-select: none;
}
</style>
<body>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var width = 960, height = 500;
var padding = 5, radius = 3;
var svg = d3.select('body').append('svg')
.attr('width', width)
.attr('height', height)
var g = svg.append('g')
.attr('class', 'button')
.attr('transform', 'translate(' + [width / 4, height / 4] +')')
// Button text
var text = g.append('text')
.style('font-size', '24px')
.style('pointer-events', 'none')
.text('Hello, world!')
// Button based on text dimensions
var bbox = text.node().getBBox();
var rect = g.insert('rect', 'text')
.attr("x", bbox.x - padding)
.attr("y", bbox.y - padding)
.attr("width", bbox.width + 2 * padding)
.attr("height", bbox.height + 2 * padding)
.attr('rx', radius)
.attr('ry', radius)
.style('fill', '#aaa')
.style('stroke', '#000')
.on('click', toggleShadow)
// Add drop shadow to the rect
defineShadow();
rect.attr('filter', 'url(#dropShadow)')
function toggleShadow() {
rect.attr('filter', function() { return (rect.attr('filter')) ? null : 'url(#dropShadow)'; })
}
function defineShadow() {
var defs = g.append('defs')
console.log('rect.attr(x):', rect.attr('x'))
var shadow = defs.append('filter')
.attr('id', 'dropShadow')
.attr('x', + rect.attr('x') - padding)
.attr('y', + rect.attr('y') - padding)
.attr('width', + rect.attr('width') + 10 * padding)
.attr('height', + rect.attr('height') + 10 * padding)
shadow.append('feGaussianBlur')
.attr('in', 'SourceAlpha')
.attr('stdDeviation', '5')
shadow.append('feOffset')
.attr('dx', '2')
.attr('dy', '4')
var merge = shadow.append('feMerge')
merge.append('feMergeNode')
merge.append('feMergeNode').attr('in', 'SourceGraphic');
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment