基本上我正在尝试将所有路径除了一个悬停在灰色之外的路径,而选择的路径保持原始颜色。我已经能够将所有其他路径变为灰色,但是我遇到了“select.this”功能的问题并且实际上访问了我想要改变样式的路径。看起来我实际上已经设法进入g组中的path元素,但是我在控制台中遇到错误
Uncaught TypeError: Property 'style' of object #<SVGGElement> is not a function
相关代码:
svg.selectAll("g.team")
.on("mouseover",function(){
console.log("I see you!");
var lineName;
var accuracy = 10;
svg.selectAll("path.team.line").style("stroke","#C0C0C0");
//set all to gray
var selectedArray = d3.select(this);
console.log(selectedArray);
var selectGroup = selectedArray[0];
console.log("should be group:"+selectGroup);
var selectedLine = selectGroup[0];;
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);
});
//get position of end of line
var len = d3.select(this).children().node().getTotalLength();
var pos = d3.select(this).node().getPointAtLength(len);
//append text to end of line
svg.append("text")
.attr("id","tooltip")
.attr("x",pos.x-55)
.attr("y",pos.y)
.text(lineName)
.style("font-family","sans-serif")
.style("font-size",13);
this.parentNode.parentNode.appendChild(this.parentNode);
//brings team to front, must select the path's g parent
//to reorder it
})
.on("mouseout",function(){
d3.select("#tooltip").remove();
d3.selectAll("team").selectAll("path")
.transition()
.style("stroke",function(d){
return color(d.name); //return all the colors
});
d3.selectAll("axis").selectAll("line").style("color","black");
});
拜托,谢谢!
答案 0 :(得分:21)
D3选择是DOM元素数组的数组。 (它们是嵌套数组,因此它们可以实现嵌套选择,同时为每个子选择保留单独的索引计数和属性。)
所以当你运行如下语句时:
var selectedArray = d3.select(this);
selectedArray
属于[[ {SVGGElement} ]]
结构。你似乎很明白这一点。
但是您的selectedArray
不是只是包含包含单个DOM元素的数组的数组。它也是 一个d3.selection
对象,包含所有选择的特殊函数,包括.style()
函数。
但是,当您在下一行中提取子数组时:
var selectGroup = selectedArray[0];
您现在只有一个包含SVG <g>
元素节点的普通数组。它没有d3的特殊功能。最后,当您从该数组中提取元素时:
var selectedLine = selectGroup[0];
您只需返回DOM元素节点本身。哪个与您最初选择的this
完全相同的对象。该节点具有.style
属性,但不具有.style()
函数。
有时,做想要从d3选择中提取节点,以便使用属于DOM接口的属性或方法。如果您确实想要这样做,上面的方法可以使用,或者您可以使用
在一行中访问它var svgNode = d3.select("svg")[0][0];
或者,您可以使用完全相同的selection.node()
方法(抓取选择中第一个嵌套中的第一个节点):
var svgNode = d3.select("svg").node();
但是,如果要在单个DOM元素上使用d3选择方法,则选择该元素,然后在选择上调用方法。选择是否包含一个元素无关紧要或1000,你的代码是一样的。 (如果您的选择完全是空的,它甚至不会抛出错误 - 它不会做任何事情!)如果您想在原始选择的子上使用d3方法,则需要使用子选择方法(selection.select()
或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()
元素的.getPointAtLength()
和<path>
方法。现在,这些方法是DOM接口方法,而不是d3方法,因此您需要实际的{SVGPathElement}
节点,而不是d3选择。但是,您现在正在使用DOM方法混合d3选项。
使用来自this
元素的纯Javascript(即它的父<g>
元素)访问节点:
var pathNode = this.children[0]; //assuming the <path> is the first child of <g>
var len = pathNode.getTotalLength();
var pos = pathNode.getPointAtLength( len );
或者,您可以从上面创建的d3选项中访问<path>
元素:
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
(因为this
已经是<g>
元素。)