在G元素中选择路径并更改样式 [英] Selecting path within G element and change style

查看:124
本文介绍了在G元素中选择路径并更改样式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

基本上,我试图让所有的路径,除了一个被徘徊在灰色,而被选择的一个保持它的原始颜色。我已经能够把所有其他路径灰色,但我有麻烦的select.this功能,实际访问我想改变风格的路径。看起来我实际上设法下到g组中的路径元素,但我面临在控制台中的错误

Essentially I'm trying to have all the paths except the one being hovered over turn gray, while the one being selected keeps it's original color. I've been able to turn all of the other paths gray, however I'm having trouble with the "select.this" function and actually accessing the path I want to change style. It would appear that I've actually managed to get down to the path element within the g group, however I'm confronted with an error in the console saying

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");

    });

请谢谢!

推荐答案

D3选择是DOM元素数组的数组。 (它们是嵌套数组,因此他们可以实现嵌套的选择,同时保持每个子选择的单独的索引计数和属性。)

D3 selections are arrays of arrays of DOM elements. (They are nested arrays so they can implement nested selections, while keeping separate index counts and properties for each sub-selection.)

所以当你运行一个语句如: / p>

So when you run a statement like:

var selectedArray = d3.select(this);

selectedArray c $ c> [[{SVGGElement}]] 。

The selectedArray is of the structure [[ {SVGGElement} ]]. That much you seem to understand.

,您的 selectedArray 不是刚刚包含一个包含单个DOM元素的数组的数组。也是 是一个 d3.selection 对象,其中包含所有的特殊函数,包括 .style()函数。

But your selectedArray isn't just an array containing an array containing a single DOM element. It is also a d3.selection object, with all the special functions that selections have, including the .style() function.

然而,当你提取下一行中的子数组:

However, when you extract the sub-array in the next line:

var selectGroup = selectedArray[0];

现在你只需要一个包含SVG的普通数组< g& / code>元素节点。它没有d3的特殊功能。最后,当从该数组中提取元素时:

You now just have an ordinary array containing an SVG <g> element node. It has no special functions from d3. And finally, when you extract the element from that array:

var selectedLine = selectGroup[0];

您只需返回DOM元素节点本身。这是与您最初选择的完全相同的对象。该节点具有 .style 属性,但不是 .style()函数。

You just return the DOM element node itself. Which is the exact same object as the this that you originally selected. That node has a .style property, but not a .style() function.

有时,您可以 要从d3选择中提取节点,以便使用属于DOM接口的属性或方法。如果你确实想这样做,上面的方法将工作,或者你可以在一行中访问它

Sometimes, you do want to extract a node from a d3 selection in order to use the properties or methods that are part of the DOM interface. If you did want to do this, the approach above would work, or you could access it all in one line with

var svgNode = d3.select("svg")[0][0];

或者,您可以使用 selection.node()方法,完全相同的东西(抓住第一个巢中的第一个节点在选择):

Or, you could use the selection.node() method which does the exact same thing (grabs the first node in the first nest in the selection):

var svgNode = d3.select("svg").node();

但是,如果要在单个DOM元素上使用d3选择方法,那个元素,然后调用选择的方法。无论选择包含一个元素还是1000,你的代码都是一样的。 (如果你的选择是完全空的,它甚至不会抛出一个错误 - 它不会做任何事情!)如果你想在原始选择的上使用d3方法,你需要使用子选择方法( selection.select() selection.selectAll())。

But, if you want to use d3 selection methods on a single DOM element, you select that element and then call the methods on the selection. It doesn't matter whether the selection contains one element or 1000, your code is just the same. (It won't even throw an error if your selection is completely empty -- it just won't do anything!) If you want to use d3 methods on a child of your original selection, you need to use a subselection method (either 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的 .on()方法,d3将自动将该元素的数据对象作为第一个参数传递给事件处理函数。这意味着您可以简化代码以避免次要函数调用:

By the way, when you add an event handler to an element with d3's selection.on() method, d3 will automatically pass that element's data object as the first parameter to your event handling function. Which means you can simplify your code to avoid the secondary function call:

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} node,而不是d3选择。但是,你现在将你的d3选择与你的DOM方法混合。

To continue with your code: For positioning your text element, you are trying to use the .getTotalLength() and .getPointAtLength() methods of the <path> element. Now, these methods are DOM interface methods, not d3 methods, so you need the actual {SVGPathElement} node, not a d3 selection. However, you're mixing up your d3 selections with your DOM methods currently.

要使用纯Javascript从元素(它是父< g> 元素):

To access the node using pure Javascript from the this element (which is it's parent <g> element):

 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选择:

Alternatively, you can access the <path> element from the d3 selection you created above:

 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

(因为已经是< g> 元素)。

这篇关于在G元素中选择路径并更改样式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆