以下代码适用于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}
但不是nodejs + jsdom:
"TypeError: Object [ PATH ] has no method 'getBBox' "
微米。 Bostock指出JSDOM doesn't support getBBox()
使用什么D3js来获取#L1 > *:nth-child(2)
的边界框?
过去的努力引导我:getBBox()
基于fiddle
答案 0 :(得分:3)
getBBox
/ getBoundingClientRect
/ getClientRect
在NodeJS + JSDOM中不起作用的原因是计算SVG(或HTML)元素的这些值涉及大量计算。 / p>
首先,必须解析<style>
元素中的所有CSS代码(这已经不是一件容易的事了)。然后必须应用CSS选择器,级联和继承规则以了解元素具有的大小,位置或行宽。即使知道了所有样式属性值,也需要做一些非平凡的数学计算边界框:定义不同的SVG变换函数,这些函数的组合,SVG基元的边界框和贝塞尔曲线。浏览器支持所有这些(他们必须,为了绘制元素),但JSDOM根本不适用于所有这些。
但幸运的是, canvg 是大多数SVG的JavaScript实现,它使用<canvas>
元素绘制图像。它确实支持上述大部分内容,虽然它没有为您提供这些数据的接口,幸运的是它有非常好的(和MIT许可的)代码,所以希望您可以复制和重用它的一部分。截至目前,代码编写在一个文件中,它包含CSS parsing,applying cascading rules,path data parsing,definitions of SVG transforms,applying transformations和{{3 }}。也就是说,几乎所有你需要计算边界框的东西:)然而,它并不支持CSS选择器,而是它bezier curve bounding box calculation。但遗憾的是,据我所知,canvg 不已准备好在NodeJS中运行,您可能需要进行一些调整。
但 can reuse another library 是一个SVG到JS编译器,其中包含canvgc, 能够在NodeJS中运行。所以从这开始就更容易了。
答案 1 :(得分:2)
直接挖掘元素的路径数据d="..."
应该有效。 svg行基本上是一组x,y
点。 假设没有平移的绝对坐标或大贝塞尔曲线,这是我的D3js生成的svg行的情况,我在这个数据中找到x
和{的最小值和最大值{1}}。
为此,我获得y
svg行或多行代码。为了简单起见,我粗略地删除了可能的相对跳跃,例如d="..."
或h30
因为我从未在D3js输出中看到过任何内容,然后清除字母(又名v20
:M,L,H, V,C,S,Q,T,A,Z),简化空间和线跳跃,然后由剩余空间分开。我得到一个干净的坐标数组。
重要的是要注意,我的选择器直接定位单个非翻译路径。
svg commands
对于多个路径的组,您可能希望遍历svg DOM以循环组的每个路径,以便更新xmin,ymin,xmax,ymax。
要处理已翻译的元素,请进一步调整。
可能存在其他更好的方法。请务必检查您的上下文中是否有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");
和getBBox()
,因为它们是原生且非常方便。