Clippath doesn't work when dynamic id's are generated - d3.js

I have implemented a bar chart with brush (D3.js V3). I have applied clip-path which is working fine for a hard-coded value (#clip).
But when I tried doing it with dynamic id its not working. when I click on a button which opens a model-box the height of bars is also clipped.
Image with model popup
Thanks in advance.
svg.append("defs")
.append("clipPath")
// .attr("id", container)
.attr("id", "clip")
.append("rect")
.attr("x", 0)
.attr("y", 0)
.attr("width", width)
.attr("height", height);
var dev = '# '+ container ;
main.append("g")
.attr('clip-path', 'url(#clip)')// this is hard coded id
//.attr('clip-path', "url("+ dev +")")// this is dynamic id
.attr("class", "bars")

Related

tspan is always hidden on FF

I have a d3 code jsfiddle. Upper text here is visible in all browser except FF.
Here is the complete code:
var data = [2000, 400];
var chart = d3.select("#container").append("svg")
.attr("class", "chart")
.attr("width", 800) // bar has a fixed width
.attr("height", 300)
.style("padding-top", "20px")
var x = d3.scale.linear()
.domain([0, d3.max(data)])
.range([10, 100]);
chart.selectAll("rect")
.data(data)
.enter()
.append("rect")
.attr("y", 18)
.attr("x", 10)
.attr("width", function(d){
return x(d) - 10
})
.attr("height", 10)
var text = [0];
var data = ['Upper text here']
chart.selectAll("text")
.data(text)
.enter()
.append("text")
.attr("x",x)
.attr("dy", ".25em")
.append('tspan')
.text('Upper text here')
.attr('x', x)
.attr("y", function(_, i) {
return i === 1 ? 42 : -9;
})
.attr('dy', '.35em')
Not sure, whats the mistake here.
In SVG 1.1 the overflow property on <svg> elements defaults to hidden.
In SVG 2 it is proposed that it default to visible.
It seems like Chrome has implemented this proposed SVG 2 change but Firefox probably won't.
You really should draw inside the SVG canvas and not depend on overflow visible as it has a pretty big performance hit since the browser can no longer assume that the maximum SVG canvas bounds are the outer SVG element's height and width.
If you really must draw outside the bounds then simply set overflow explicitly to get consistent cross-browser behaviour e.g.
var chart = d3.select("#container").append("svg")
.attr("class", "chart")
.attr("width", 800) // bar has a fixed width
.attr("height", 300)
.attr("overflow", "visible")
.style("padding-top", "20px")

D3 Programmatic defs pattern fill for svg shapes

I wanted to create a circular crop an image to use in conjunction with a svg circle, and decided on filling the svg circle with a pattern. I have it working for the single case:
defs.append("svg:pattern")
.attr("id", "story1")
.attr("width", 200)
.attr("height", 100)
.attr("patternUnits", "userSpaceOnUse")
.append("svg:image")
.attr("xlink:href", 'ml-image4.png')
.attr("width", 200)
.attr("height", 100)
.attr('x',0)
.attr('y',0);
var circle1 = svg.append("circle")
.attr("cx", 100)
.attr("cy", 50)
.attr("r", 40)
.style("fill", "#fff")
.style("fill", "url(#story1)")
.style('stroke','#000')
.style('stroke-width', 5);
Then I got all gung-ho and tried to adapt for a programmatic implementation, but it didn't pan out so well. I'm hoping there is a way to do it, because my end goal is to have an application that uses many pictures as patterns. It will be like a little gallery where each svg circle is spaced out across the page using .attr('x', function(d,i) { return 100+i*200})) and each circle referencing a different pattern. The pattern id is a data member, so I was trying to do this: .style('fill',function(d) {return "url(#"+d.id+")"; }). I'm not exactly sure why it didn't work; to my eyes it seems functional-ish. I did get the error:
Uncaught DOMException: Failed to execute 'querySelectorAll' on
'Element': 'svg:pattern' is not a valid selector.
Here is my adaptation for programmatic def patterns and a quick look at my data:
var data = [
{'id':'story1', 'Title':'Title1', 'Date':'03/10/2017','Icon':'Icon1.png', 'Link':'www.link1.com/'},
{'id':'story2', 'Title':'Title2', 'Date':'12/15/2017','Icon':'Icon2.png', 'Link':'www.link2.com/'}
];
var defs = svg.append('svg:defs');
defs.selectAll(null)
.data(data)
.enter()
.append('svg:pattern')
.attr('id',function(d) {return d.id; })
.attr('width', 200)
.attr('height', 100)
.attr('patternUnits', 'userSpaceOnUse')
.append('svg:image')
.attr('xlink:href', function(d) {return d.Icon})
.attr('width', 200)
.attr('height', 100)
.attr('x',0)
.attr('y',0);
svg.selectAll('circle')
.data(data)
.enter()
.append('circle')
.attr('cx', function(d,i) {return 100+i*200})
.attr('cy', 50)
.attr('r',40)
.style('fill',function(d) {return "url(#"+d.id+")"; })
.style('stroke','#000')
.style('stroke-width',3);
Question
Judging by the error, my adaptation seems to be flawed. What can I tweak to get programmatic patterns for svg circles here? In my humble opinion, my approach isn't all that different from the simple case at the very beginning of the post (1 pattern 1 circle), all I was trying to do was scale it up so I can use d3.selectAll() using my data.

d3.js adding polygon inside rectangle

How to add polygon inside rectangle?, below is the code i have but it is not showing polygon inside rectangle. could you please help me.
var svgContainer = d3.select("body").append("svg")
var rectangle = svgContainer.append("rect")
.style("stroke", "black")
.style("fill", "none")
.attr("x", 50)
.attr("y", 50)
.attr("width", 100)
.attr("height", 100);
var cir = rectangle.append("polygon") // attach a polygon
.style("stroke", "black") // colour the line
.style("fill", "none") // remove any fill colour
.attr("points", "30,50,100,150,100,150"); // x,y points
You are making the polygon with in the rect DOM which is incorrect
You should be attaching the polygon to the svg
So it should be
svgContainer.append("polygon")
corrected code below:
var svgContainer = d3.select("body").append("svg")
var rectangle = svgContainer.append("rect")
.style("stroke", "black")
.style("fill", "none")
.attr("x", 50)
.attr("y", 50)
.attr("width", 100)
.attr("height", 100);
var cir = svgContainer.append("polygon") // attach a polygon to the svg
.style("stroke", "black") // colour the line
.style("fill", "none") // remove any fill colour
.attr("points", "30,50,100,150,100,150"); // x,y points
Working fiddle here
To make the polygon appear within the rectangle you will need to provide the polygon points/coordinates accordingly.
Just by making the polygon within the rect DOM element will not make it show withing the rectangle.
Hope this clears your concern.

D3: How delete shape on click event?

I currently have a world map that on the click event on one of the countries in my map will add a rectangle on the same place with a different color. The problem with the code I have is that clicking the countries will result in rectangles being added in the svg(on every click a rectangle is added on top of the other) because I am appending them. What I'd like to do is delete the previous added rectangle when one of the countries is clicked and then adding the next one.
I was thinking about using .remove() but I'm not sure if that is the right way and I'm not sure how to implement it in the code.
Any help or suggestion are greatly appreciated!
Thanks in advance!
the code I have
.on("click",clicked)
function clicked(d,i) {
if(d.properties.name === "Mexico") {
var rectGroup = svg.append("g");
var rectGreen = rectGroup.append("rect")
.attr("width", 100)
.attr("height", 100)
.attr("fill", "green")
.attr("transform", "translate(50, 0)");
}else {
var rectGroup = svg.append("g");
var rectBlue = rectGroup.append("rect")
.attr("width", 100)
.attr("height", 100)
.attr("fill", "blue")
.attr("transform", "translate(50, 0)");
}
}
you can do something like
var creation=Date.now();
var rectBlue = rectGroup.append("rect")
.attr("width", 100)
.attr("height", 100)
.attr("fill", "blue")
.attr("transform", "translate(50, 0)")
.attr('id','rect_'+creation)
.attr('onclick',"removeRect('rect_"+creation+"')")
;
and then have a function
function removeRect(id){
d3.selectAll('g #'+id).remove();
}

Cannot get d3 svg tutorial to work in jsfiddle

I'm trying to follow a d3 tutorial and I've created a JSFiddle for the following code
var dataset = [1,2,3,4,5];
var sampleSVG = d3.select("#viz")
.append("svg")
.attr("width", 400)
.attr("height", 75);
sampleSVG.selectAll("circle")
.data(dataset)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "red")
.attr("height", 40)
.attr("width", 75)
.attr("x", function(d, i){return i*80})
.attr("y", 20);
However, I see the generated circles in the svg but I can't see them on the screen. Can anyone see what I'm missing?
Here is a FIDDLE:
var dataset = [1,2,3,4,5];
sampleSVG.selectAll("circle")
.data(dataset)
.enter().append("circle")
.style("stroke", "gray")
.style("fill", "red")
.attr("cx", function(d, i){return (i + 1 ) *60})
.attr("cy", 30)
.attr("r", 20);
I just focused on the main parts that needed change. You can study the differences. Basically, you had the wrong attributes for a circle (x and y, instead of cx and cy) and was missing the radius attribute. Finally, height and width are not circle attributes.

Resources