Reputation: 3107
How could I change a shadow opacity partially in svg using filters and d3.js?
Here is what I would like my shadow to look like:
I mean the shadow which is dropped by the rectangle in which written Entity Name
.
Here is what I was able to achieve so far:
var svg = d3.select("#drawRegion")
.append("svg")
.attr("width", "100%")
.attr("height", "100%");
var defs = svg.append("defs");
var filter = defs.append("filter")
.attr("id","coolShadow");
filter.append("feMorphology")
.attr("in", "SourceGraphic")
.attr("result", "upperLayer")
.attr("operator", "dilate")
.attr("radius", "2 2");
filter.append("feMorphology")
.attr("in", "SourceAlpha")
.attr("result", "enlargedAlpha")
.attr("operator", "dilate")
.attr("radius", "3 5");
filter.append("feGaussianBlur")
.attr("in", "enlargedAlpha")
.attr("result", "bluredAlpha")
.attr("stdDeviation", "5");
filter.append("feOffset")
.attr("in", "bluredAlpha")
.attr("result", "lowerLayer")
.attr("dy", "3");
var feMerge = filter.append("feMerge");
feMerge.append("feMergeNode")
.attr("in","lowerLayer");
feMerge.append("feMergeNode")
.attr("in","upperLayer");
svg.append("rect")
.attr("rx", 2)
.attr("ry", 2)
.attr("x", "20%")
.attr("y", "20%")
.attr("width", "60%")
.attr("height", "60%")
.attr("fill", "white")
.style("filter", "url(#coolShadow)");
#drawRegion {
width: 100%;
height: 100%;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
position: relative;
}
<div id="drawRegion">
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
The shadow is almost ready as you can see. The only thing I can not figure out how to achieve - is the increased opacity (right now it is too increased and I would like to lower it, but at the same time preserver the transparencies on the left, top and right borders).
I tried decreasing the overall opacity, but it did not help: the left, top and right borders transparencies decreased as well, while I would like to make the lower border part more transparent and preserve other borders as they are.
I would be grateful for any corrections which would allow me to tackle the issue, or to the entirely different solution.
Upvotes: 4
Views: 733
Reputation: 31705
The best way to achieve what you want to do is to dial back the y radius on the second feMorphology and the y on the feOffset. There are ways to actually reduce opacity selectively, but they'll cause discontinuities in your shadow - which you probably don't want.
(Also you needed to expand your filter region - which I do for you here).
I wonder, though, why you're using a feMorphology to expand the source rectangle? If you want a larger rectangle with slightly rounded corners, you can just draw that directly in SVG - it's going to be more performant. feMorphology is a slow operation.
var svg = d3.select("#drawRegion")
.append("svg")
.attr("width", "100%")
.attr("height", "100%");
var defs = svg.append("defs");
var filter = defs.append("filter")
.attr("id","coolShadow")
.attr("y","-20%")
.attr("height","140%");
filter.append("feMorphology")
.attr("in", "SourceGraphic")
.attr("result", "upperLayer")
.attr("operator", "dilate")
.attr("radius", "2 2");
filter.append("feMorphology")
.attr("in", "SourceAlpha")
.attr("result", "enlargedAlpha")
.attr("operator", "dilate")
.attr("radius", "3 3");
filter.append("feGaussianBlur")
.attr("in", "enlargedAlpha")
.attr("result", "bluredAlpha")
.attr("stdDeviation", "5");
filter.append("feOffset")
.attr("in", "bluredAlpha")
.attr("result", "lowerLayer")
.attr("dy", "2");
var feMerge = filter.append("feMerge");
feMerge.append("feMergeNode")
.attr("in","lowerLayer");
feMerge.append("feMergeNode")
.attr("in","upperLayer");
svg.append("rect")
.attr("rx", 2)
.attr("ry", 2)
.attr("x", "20%")
.attr("y", "20%")
.attr("width", "60%")
.attr("height", "60%")
.attr("fill", "white")
.style("filter", "url(#coolShadow)");
#drawRegion {
width: 100%;
height: 100%;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
position: relative;
}
<div id="drawRegion">
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
Upvotes: 1
Reputation: 61656
You can both play on the opacity
and dy
attributes.
The opacity will globally make the shadow brighter or darker (value between 0 and 1).
The dy
attribute (same goes for dx
) moves the shadow vertically ("moves the light source").
If dy
is 0
, then the shadow is centered on the shape (the light source is just above the shape). If (as in your case), dy
is positive, then the shadow will be translated to the bottom and thus will be more pronounced bellow the shadow's shape.
Here is an example with opacity
at 0.3
:
.style("opacity", 0.3)
and dy
at 0
(you can play with it to adjust it to your style):
.attr("dy", "0")
var svg = d3.select("#drawRegion")
.append("svg")
.attr("width", "100%")
.attr("height", "100%");
var defs = svg.append("defs");
var filter = defs.append("filter")
.attr("id","coolShadow")
.attr("x", "-100%").attr("y", "-100%") //
.attr("width", "300%").attr("height", "300%"); //
filter.append("feMorphology")
.attr("in", "SourceGraphic")
.attr("result", "upperLayer")
.attr("operator", "dilate")
.attr("radius", "2 2");
filter.append("feMorphology")
.attr("in", "SourceAlpha")
.attr("result", "enlargedAlpha")
.attr("operator", "dilate")
.attr("radius", "3 5");
filter.append("feGaussianBlur")
.attr("in", "enlargedAlpha")
.attr("result", "bluredAlpha")
.attr("stdDeviation", "4");
filter.append("feOffset")
.attr("in", "bluredAlpha")
.attr("result", "lowerLayer")
.attr("dy", "0"); //
var feMerge = filter.append("feMerge");
feMerge.append("feMergeNode")
.attr("in","lowerLayer");
feMerge.append("feMergeNode")
.attr("in","upperLayer");
svg.append("rect")
.attr("rx", 2)
.attr("ry", 2)
.attr("x", "20%")
.attr("y", "20%")
.attr("width", "60%")
.attr("height", "60%")
.attr("fill", "white")
.style("filter", "url(#coolShadow)")
.style("opacity", 0.3); //
#drawRegion {
width: 100%;
height: 100%;
display: inline-block;
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
position: relative;
}
<div id="drawRegion">
</div>
<script src="https://d3js.org/d3.v5.min.js"></script>
Notice how I also modified the width/height/position of the applied shadow in order to avoid it being truncated:
var filter = defs.append("filter")
.attr("id", "coolShadow")
.attr("x", "-100%").attr("y", "-100%")
.attr("width", "300%").attr("height", "300%");
Upvotes: 1