D3 选择是 DOM 元素数组的数组。 (它们是嵌套数组,因此可以实现嵌套选择,同时为每个子选择保留单独的索引计数和属性。)
因此,当您运行如下语句时:
var selectedArray = d3.select(this);
The selectedArray
是结构体的[[ {SVGGElement} ]]
。看来你就明白这么多了。
But your selectedArray
isn't just一个数组,其中包含一个包含单个 DOM 元素的数组。这是also a d3.selection https://github.com/mbostock/d3/wiki/Selections#wiki-d3_selection对象,具有选择所具有的所有特殊功能,包括.style()
功能。
但是,当您提取下一行中的子数组时:
var selectGroup = selectedArray[0];
您现在只有一个包含 SVG 的普通数组<g>
元素节点。它没有 d3 的特殊功能。最后,当您从该数组中提取元素时:
var selectedLine = selectGroup[0];
您只需返回 DOM 元素节点本身。哪一个是完全一样对象作为this
您最初选择的。该节点有一个.style
财产,但不是.style()
功能。
有时,你do想要从 d3 选择中提取节点,以便使用属于 DOM 接口的属性或方法。如果您确实想这样做,上面的方法可以工作,或者您可以使用以下命令一行访问所有内容
var svgNode = d3.select("svg")[0][0];
或者,您可以使用selection.node()
方法执行完全相同的操作(抓取选择中第一个嵌套中的第一个节点):
var svgNode = d3.select("svg").node();
But, 如果要在单个 DOM 元素上使用 d3 选择方法,请选择该元素,然后调用选择的方法。无论选择包含 1 个元素还是 1000 个元素,您的代码都是相同的。 (如果您的选择完全为空,它甚至不会抛出错误 - 它不会执行任何操作!)如果您想在 a 上使用 d3 方法child您的原始选择,您需要使用子选择方法(或者selection.select()
or selection.selectAll()
).
svg.selectAll("g.team")
.on("mouseover",function(){
var lineName;
svg.selectAll("path.team.line").style("stroke","#C0C0C0");
//set all to gray
var selectedGroup = d3.select(this);
var selectedLine = selectedGroup.select("path.team.line");
//this only selects the (first) path that is a child
//of the selected group
selectedLine.style("color",function(d){ //let active keep color
lineName = abbrDict[d.name]; //full name to be at end of line
return color(d.name);
});
/* ...etc... */
顺便说一句,当您将事件处理程序添加到具有 d3 的元素时selection.on()
方法中,d3 会自动将该元素的数据对象作为第一个参数传递给事件处理函数。这意味着您可以简化代码以避免二次函数调用:
svg.selectAll("g.team")
.on("mouseover",function(d){ //d as a function parameter
var lineName;
svg.selectAll("path.team.line").style("stroke","#C0C0C0");
//set all to gray
var selectedLine = d3.select(this);
selectedLine.style("color", color(d.name) );
//already have the `d` for this element available
lineName = abbrDict[d.name];
/* ...etc... */
要继续您的代码:为了定位您的文本元素,您正在尝试使用.getTotalLength()
and .getPointAtLength()
的方法<path>
元素。现在,这些方法是 DOM 接口方法,而不是 d3 方法,因此您需要实际的{SVGPathElement}
节点,而不是 d3 选择。但是,您当前将 d3 选择与 DOM 方法混合在一起。
使用纯 Javascript 从以下位置访问节点this
元素(这是它的父元素<g>
元素):
var pathNode = this.children[0]; //assuming the <path> is the first child of <g>
var len = pathNode.getTotalLength();
var pos = pathNode.getPointAtLength( len );
或者,您可以访问<path>
来自您上面创建的 d3 选择的元素:
var pathNode = selectedLine.node(); //grab the node from the selection
var len = pathNode.getTotalLength();
var pos = pathNode.getPointAtLength( len );
最后,这一行:
this.parentNode.parentNode.appendChild(this.parentNode);
//brings team to front, must select the path's g parent
//to reorder it
我想应该只是:
this.parentNode.appendChild(this);
//brings team to front, must select the path's g parent
//to reorder it
(since this
is the <g>
元素已经)。