The following code works on Chromium :
var node = window.d3.selectAll('#L1 > *:nth-child(2)');
var bbox = node.node().getBBox();
console.log(bbox) // {height: 44, width: 44, y: -13, x: 144}
but not with nodejs + jsdom:
"TypeError: Object [ PATH ] has no method 'getBBox' "
M. Bostock pointed out that JSDOM doesn't support getBBox()
What D3js replacement to use to get the bounding box of #L1 > *:nth-child(2)
?
Past efforts lead me there : getBBox()
based fiddle
Digging straight into the element's path data d="..."
should work. An svg line is basically a set of x,y
points. Assuming absolute coordinates without translation nor big bezier curves, which is the case of my D3js-generated svg lines, I'am finding in this data the min and max values for both x
and y
.
To do so, I get the d="..."
svg line or multilines code. For simplicity sake, I rudely removes possible relative jumps such h30
or v20
since I never saw any in my D3js output, then clean out letters (aka svg commands
: M,L,H,V,C,S,Q,T,A,Z), simplify the spaces and line jumps, then split by the remaining spaces. I get a clean arrays of coordinates.
Important to note, my selector directly target a single non-translated path.
var getBBox = function(selector){
var xmin, xmax, ymin, ymax,p;
// clean up path
var t = d3.select(selector).attr("d"); // get svg line's code
console.log(t)
t = t.replace(/[a-z].*/g," ") // remove relative coords, could rather tag it for later processing to absolute!
.replace(/[\sA-Z]+/gi," ").trim().split(" "); // remove letters and simplify spaces.
console.log(t)
for(var i in t){ // set valid initial values
if(t[i].length>1){
p = t[i].split(",");
xmin = xmax = p[0]; ymin = ymax = p[1]; }
}
for(var i in t){ // update xmin,xmax,ymin,ymax
p = t[i].split(",");
if(!p[1]){ p[0]=xmin; p[1] = ymin;} // ignore relative jumps such h20 v-10
xmin = Math.min(xmin, p[0]);
xmax = Math.max(xmax, p[0]);
ymin = Math.min(ymin, p[1]);
ymax = Math.max(ymax, p[1]);
} return [[xmin,ymax],[xmax,ymin]]; // [[left, bottom], [right, top]] as for https://github.com/mbostock/d3/wiki/Geo-Paths#bounds
}
var bb = getBBox("path");
JSfiddle DEMO
For groups of multiple paths, you may want to traverse the svg DOM to loop upon each single path of the group in order to update xmin, ymin, xmax, ymax.
To handle translated elements, adapt further.
Other better approaches may exist. Remember to check if getBBox()
and getBoundingClientRect()
are available in your context, since they are native and very convenient.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With