When a path element has instructions like this d="M28,46L28,23L77,23"
to render two orthogonal lines, it works fine with the filter and the drop shadow rendered as expected, but, if the length of one of the lines is shorter than the corresponding dimension of the marker, a problem emerges: the path element, including the marker, start to get clipped by the filter.
I don't understand what's going on exactly, but it seems that the bounding box for the filter, which is a percentage of the path bounding box, collapses to zero height and this somehow clips the referencing path element. As soon as the path bounding box becomes zero, the problem disappears (at least it does in Chrome and Opera...).
Last active
August 29, 2015 14:24
-
-
Save cool-Blue/650894875bae9953e037 to your computer and use it in GitHub Desktop.
svg path clipped by filter element
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<title></title> | |
<style> | |
svg { | |
outline: 1px solid black; | |
} | |
</style> | |
</head> | |
<body> | |
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script> | |
<script> | |
var width = 300, | |
height = 100, | |
constant = 10; | |
var svg = d3.select('body').append('svg') | |
.attr('width', width) | |
.attr('height', height); | |
var defs = svg.append("defs"); | |
var markerW = 8, markerH = 6, | |
marker = defs.append('marker') | |
.attr('id', "triangle") | |
.attr('viewBox', "0 0 10 10") | |
.attr('refX', "0") | |
.attr('refY', 5) | |
.attr('markerUnits', 'strokeWidth') | |
.attr('markerWidth', markerW) | |
.attr('markerHeight', markerH) | |
.attr('orient', 'auto') | |
var path = marker.append('path') | |
.attr('d', "M 0 0 L 10 5 L 0 10 z") | |
// 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": "200%", "width": "200%", x: "-50%", y: "-50%"}) | |
/*.style({opacity: 0.5})*/; | |
// 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", 1) | |
.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", 2) | |
.attr("dy", 2) | |
.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"); | |
var connector = d3.svg.line().interpolate("linear") | |
.x(function (d) { | |
return Math.round(d[0]) | |
}) | |
.y(function (d) { | |
return Math.round(d[1]) | |
}); | |
function linkPath(d) { | |
var x1 = d[0][0], y1 = d[0][1], | |
x2 = d[1][0], y2 = d[1][1]; | |
return connector([[x1, y1], [x1, y2], [x2, y2]]); | |
} | |
var link = svg.selectAll('.link') | |
.data([[[10, 40], [200, 40]]]) | |
.enter() | |
.append('path').attr("class", "link") | |
.attr("stroke-width", "2") | |
.attr('marker-end', 'url(#triangle)') | |
.attr('stroke', 'black') | |
.attr("fill", "none") | |
.style("filter", "url(#drop-shadow)") | |
.attr("d", linkPath) | |
function start() { | |
var t = 3000; | |
link.data([[[10, 60], [200, 40]]]) | |
.transition().delay(t / 3).duration(t).ease("linear") | |
.attr("d", linkPath) | |
.each("end", function () { | |
link.data([[[10, 40], [200, 40]]]) | |
.transition().duration(t).ease("linear") | |
.attr("d", linkPath) | |
.each("end", function () { | |
link.data([[[10, 20], [200, 40]]]) | |
.transition().delay(t / 3).duration(t).ease("linear") | |
.attr("d", linkPath) | |
.each("end", function () { | |
link.data([[[10, 40], [200, 40]]]) | |
.transition().duration(t).ease("linear") | |
.attr("d", linkPath) | |
.each("end", start) | |
}) | |
}) | |
}) | |
} | |
; | |
start(); | |
</script> | |
</body> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment