Reputation: 3616
I'm attempting to set the filter flood-color
within a D3 visualization based on a property in my data. Currently my filter setup looks like so, and works as expected, setting a red flood-color
:
var defs = vis.append('defs');
var filter = defs.append('filter')
.attr('id', 'drop-shadow')
.attr('height', '130%');
filter.append('feGaussianBlur')
.attr('in', 'SourceAlpha')
.attr('stdDeviation', 3)
.attr('result', 'blur');
filter.append('feOffset')
.attr('in', 'blur')
.attr('result', 'offsetBlur');
filter.append("feFlood")
.attr("in", "offsetBlur")
.attr("flood-color",'red')
.attr("flood-opacity", "1")
.attr("result", "offsetColor");
filter.append("feComposite")
.attr("in", "offsetColor")
.attr("in2", "offsetBlur")
.attr("operator", "in")
.attr("result", "offsetBlur");
var feMerge = filter.append('feMerge');
feMerge.append('feMergeNode')
.attr('in', 'offsetBlur')
feMerge.append('feMergeNode')
.attr('in', 'SourceGraphic');
However, if I change this section to try to set the color based on my data, the data is not defined:
filter.append("feFlood")
.attr("in", "offsetBlur")
.attr("flood-color", function(d) {
if (d.state === 'active') {
return 'blue';
} else if (d.state === 'starter') {
return 'green';
} else if (d.state === 'suspended') {
return 'yellow';
} else if (d.state === 'closed') {
return 'red';
}
})
.attr("flood-opacity", "1")
.attr("result", "offsetColor");
UPDATE: Link to full example: http://blockbuilder.org/MattDionis/7f5375d927698f508a01
Upvotes: 2
Views: 1459
Reputation: 32327
I don't think you should approach the problem by changing the filter color. Filter is commonly used by all nodes so changing the filter color will change in all the nodes.
I would suggest that for each category make a new filter example:
if (d.state === 'active') {
return 'blue';//make blue filter
} else if (d.state === 'starter') {
return 'green';//make green filter
} else if (d.state === 'suspended') {
return 'yellow';//make yellow filter
} else if (d.state === 'closed') {
return 'red';////make red filter
}
I have made a function which will make the filter inside defs
if not present:
function makeFiter(id, color){
//make a filter if filter id not present
if (defs.selectAll("#"+id).empty()){
var filter = defs.append('filter')
.attr('id', id)
.attr('height', '130%');
filter.append('feGaussianBlur')
.attr('in', 'SourceAlpha')
.attr('stdDeviation', 3)
.attr('result', 'blur');
filter.append('feOffset')
.attr('in', 'blur')
.attr('result', 'offsetBlur');
filter.append("feFlood")
.attr("in", "offsetBlur")
.attr("flood-color",color)
.attr("flood-opacity", "1")
.attr("result", "offsetColor");
filter.append("feComposite")
.attr("in", "offsetColor")
.attr("in2", "offsetBlur")
.attr("operator", "in")
.attr("result", "offsetBlur");
var feMerge = filter.append('feMerge');
feMerge.append('feMergeNode')
.attr('in', 'offsetBlur')
feMerge.append('feMergeNode')
.attr('in', 'SourceGraphic');
}
return 'url(#'+id+")";//return the filter id
}
I have made another function to pull the correct filter url depending on the condition.
function getFilter(d){
if (d.state === 'active') {
return makeFiter('drop-shadow-blue','blue');
} else if (d.state === 'starter') {
return makeFiter('drop-shadow-green','green');
} else if (d.state === 'suspended') {
return makeFiter('drop-shadow-yellow','yellow');
} else if (d.state === 'closed') {
return makeFiter('drop-shadow-red','red');
}
}
Now when you create the node call the getFilter method to return the correct filter id based on the condition defined above.
nodeEnter = node.enter().append('svg:g')
.attr('class', 'node')
.attr('transform', function(d) {
return "translate(" + d.x + "," + d.y + ")";
})
.attr('filter', function(d){return getFilter(d);})//get the filter url
So in the DOM your defs
will look something like this with ids:
Working code here.
Upvotes: 3