如何将所选节点置于d3 js前面?

时间:2018-03-06 18:46:47

标签: javascript css html5 d3.js data-driven

我使用d3 v3脚本来显示数据。我需要在mouseleave中突出显示并将节点置于鼠标中心,反之亦然。现在我可以通过增加节点的高度和宽度来高亮点亮节点。

无法将节点带到前面。我尝试过使用像opacity,z-index这样的CSS。

脚本

<script>

    // some colour variables
    var tcBlack = "purple";

    // rest of vars
    var w = 1500,
        h = 800,
        maxNodeSize = 50,
        x_browser = 25,
        y_browser = 25,
        root;

    var vis;
    var force = d3.layout.force(); 

    vis = d3.select("#visfel_map").append("svg").attr("width", w).attr("height", h);


    d3.json(url, function(error,json) {
    if (error) 
        return console.warn(error);
    root = json;
    root.fixed = true;
    root.x = w / 2;
    root.y = h / 4;


            // Build the path
    var defs = vis.insert("svg:defs")
        .data(["end"]);


    defs.enter().append("svg:path")
        .attr("d", "M0,-5L10,0L0,5");

        update();
    });

   function update() {
    var nodes = flatten(root),
        links = d3.layout.tree().links(nodes);

    force.nodes(nodes)
            .links(links)
            .gravity(0.05)
        .charge(-2500)
        .linkDistance(200)
        .friction(0.5)
        .linkStrength(function(l, i) {return 1; })
        .size([w, h])
        .on("tick", tick)
            .start();

    var path = vis.selectAll("path.link")
        .data(links, function(d) { return d.target.id; });

        path.enter().insert("svg:path")
        .attr("class", "link")
        // .attr("marker-end", "url(#end)")
        .style("stroke", "#ff8888");


    // Exit any old paths.
    path.exit().remove();



    // Update the nodes…
    var node = vis.selectAll("g.node")
        .data(nodes, function(d) { return d.id; });


    // Enter any new nodes.
    var nodeEnter = node.enter().append("svg:g")
        .attr("class", "node")
        .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; })
        .on("click", click)
        .call(force.drag);

    // Append a circle
    nodeEnter.append("svg:circle")
        .attr("r", function(d) { return Math.sqrt(d.size) / 10 || 4.5; })
        .style("fill", "#eee");


    // Append images
    var images = nodeEnter.append("svg:image")
            .attr("xlink:href",  function(d) { return d.img;})
            .attr("x", function(d) { return -25;})
            .attr("y", function(d) { return -25;})
            .attr("height", 65)
            .attr("width", 65);

    // make the image grow a little on mouse over and add the text details on click
    var setEvents = images
            .on( 'click', function (d) {
                console.log(d.sub_category_id)
            })
            .on( 'mouseenter', function() {
                var currNode =  d3.select(this);
                currNode.transition()
                .attr("x", function(d) { return -60;})
                .attr("y", function(d) { return -60;})
                .attr("height", 300)
                .attr("width", 300);    

            })
            // set back
            .on( 'mouseleave', function() {
                d3.select(this)
                .transition()
                .attr("x", function(d) { return -25;})
                .attr("y", function(d) { return -25;})
                .attr("height", 65)
                .attr("width", 65);


    });
    // Append name on roll over next to the node as well
    nodeEnter.append("text")
        .attr("class", "nodetext")
        .attr("x", function(d) { return d.children ? 70 : 70; })
        .attr("y", function(d) { return d.children ? 10 : 10; })
        .style("text-anchor", function(d) { return d.children ? "end" : "end"; })
        .attr("fill", tcBlack)
        .text(function(d) { return d.name; });


    // Exit any old nodes.
    node.exit().remove();


    // Re-select for update.
    path = vis.selectAll("path.link");
    node = vis.selectAll("g.node");

    function tick() {


            path.attr("d", function(d) {

            var dx = d.target.x - d.source.x,
                dy = d.target.y - d.source.y,
                dr = Math.sqrt(dx * dx + dy * dy);
                return   "M" + d.source.x + "," 
                    + d.source.y 
                    + "A" + dr + "," 
                    + dr + " 0 0,1 " 
                    + d.target.x + "," 
                    + d.target.y;
        });
            node.attr("transform", nodeTransform);    
        }
    }


    /**
    * Gives the coordinates of the border for keeping the nodes inside a frame
    * http://bl.ocks.org/mbostock/1129492
    */ 
    function nodeTransform(d) {
    d.x =  Math.max(maxNodeSize, Math.min(w - (d.imgwidth/2 || 16), d.x));
        d.y =  Math.max(maxNodeSize, Math.min(h - (d.imgheight/2 || 16), d.y));
        return "translate(" + d.x + "," + d




        .y + ")";
    }

    /**
    * Toggle children on click.
    */ 
    function click(d) {
    if (d.children) {
        d._children = d.children;
        d.children = null;
    } else {
        d.children = d._children;
        d._children = null;
    }

    update();
    }


    /**
    * Returns a list of all nodes under the root.
    */ 
    function flatten(root) {
    var nodes = []; 
    var i = 0;

    function recurse(node) {
        if (node.children) 
        node.children.forEach(recurse);
        if (!node.id) 
        node.id = ++i;
        nodes.push(node);
    }

    recurse(root);
    return nodes;
    } 

</script>

enter image description here

JSON数据

{
  "type": "map",
  "tree_size": "2",
  "map_id": "1",
  "name": "Sounds for Speech",
  "img": "manage/visfel_images/map-1516338051-sounds for speech.png",
  "children": [
    {
      "type": "category",
      "tree_size": "2",
      "category_id": "1",
      "name": "Vowels",
      "img": "manage/visfel_images/category-1516338094-vowel sound.png",
      "children": [
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "1",
          "name": "A",
          "img": "manage/visfel_images/sub-1516338159-A.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "2",
          "name": "E",
          "img": "manage/visfel_images/sub-1516338189-E.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "3",
          "name": "I",
          "img": "manage/visfel_images/sub-1516338212-i.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "4",
          "name": "O",
          "img": "manage/visfel_images/sub-1516338235-O.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "5",
          "name": "U",
          "img": "manage/visfel_images/sub-1516338260-U.png"
        }
      ]
    },
    {
      "type": "category",
      "tree_size": "2",
      "category_id": "2",
      "name": "Consonents",
      "img": "manage/visfel_images/category-1516338121-consonents.png",
      "children": [
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "6",
          "name": "B",
          "img": "manage/visfel_images/sub-1516338304-B.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "7",
          "name": "C",
          "img": "manage/visfel_images/sub-1516338323-C.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "8",
          "name": "D",
          "img": "manage/visfel_images/sub-1516338342-D.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "9",
          "name": "F",
          "img": "manage/visfel_images/sub-1516338362-F.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "10",
          "name": "G",
          "img": "manage/visfel_images/sub-1516338380-G.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "11",
          "name": "H",
          "img": "manage/visfel_images/sub-1516338401-H.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "12",
          "name": "J",
          "img": "manage/visfel_images/sub-1516338427-J.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "13",
          "name": "K",
          "img": "manage/visfel_images/sub-1516338452-K.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "14",
          "name": "L",
          "img": "manage/visfel_images/sub-1516338470-L.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "15",
          "name": "M",
          "img": "manage/visfel_images/sub-1516338489-M.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "16",
          "name": "N",
          "img": "manage/visfel_images/sub-1516338508-N.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "17",
          "name": "P",
          "img": "manage/visfel_images/sub-1516338542-P.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "18",
          "name": "Q",
          "img": "manage/visfel_images/sub-1516338560-Q.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "19",
          "name": "R",
          "img": "manage/visfel_images/sub-1516338579-R.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "20",
          "name": "S",
          "img": "manage/visfel_images/sub-1516338604-S.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "21",
          "name": "T",
          "img": "manage/visfel_images/sub-1516338619-T.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "22",
          "name": "V",
          "img": "manage/visfel_images/sub-1516338635-V.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "23",
          "name": "W",
          "img": "manage/visfel_images/sub-1516338650-W.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "24",
          "name": "X",
          "img": "manage/visfel_images/sub-1516338666-X.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "25",
          "name": "Y",
          "img": "manage/visfel_images/sub-1516338705-Y.png"
        },
        {
          "type": "sub",
          "tree_size": "2",
          "sub_category_id": "26",
          "name": "Z",
          "img": "manage/visfel_images/sub-1516338742-Z.png"
        }
      ]
    }
  ]
}

在随附的屏幕截图中,节点&#34; M&#34;是焦点,鼠标悬停在该元素上。节点通过增加宽度和高度来突出显示,与节点应该在前面相同,重叠的节点应该返回。

通过淡化其他元素,或者重新排列节点元素来解决问题。

等待建议? 在此先感谢。

3 个答案:

答案 0 :(得分:2)

d3.v4 - d3.v5

.on('mouseenter', function() {

    d3.select(this).raise()

})

Example

答案 1 :(得分:1)

我相信你现在知道SVG没有z-index。相反,它根据插入顺序对元素进行分层。要解决您的问题,请再次添加节点,以便在其他所有内容之后插入(并显示在其上)。

这是带有解决方案的JSFiddle,使用示例图像运行。

总结:

  1. 向SVG添加ID,以便选择简单明确:

    vis = d3.select("#visfel_map").append("svg")
    .attr("width", w).attr("height", h).attr("id", "mainSvg");
    
  2. 在设置期间为每个节点添加ID:

    var idStart = "letter_";
    // Append images
    var images = nodeEnter.append("svg:image")
                .attr("xlink:href",   "https://www.freeclipartnow.com/d/39895-1/decorative-letter-A.jpg")
                .attr("id", function(d){return idStart + d.name;})
    

    ...`

  3. 接下来,添加函数以将所需元素移动到插入列表的末尾。我基于this block ,但我指定了SVG元素的ID以避免混淆。

    d3.selection.prototype.moveToSvgFront = function() {  
      return this.each(function(){
       d3.select("#mainSvg").node().appendChild(this);
      });
    };
    
  4. 最后,使用moveToSvgFront更新mouseenter功能。还要调用现有的nodeTransform函数以确保元素正确定位:

    .on( 'mouseenter', function() {
      var currNode =  d3.select(this);
      if(currNode.attr("id").length === idStart.length + 1){ // only run for letters, not for titles (which cause an error in nodeTransform)
        currNode.moveToSvgFront();
        currNode.attr("transform", nodeTransform);
        ...
      }
    })
    
  5. **编辑:@Keerthivasan这里的a JSFiddle代码也可以移动和设置文本样式。注意

    一个。已为新类(focusLabel)添加了CSS

    湾标签已被赋予与节点ID相关的ID;这用于访问mouseenter函数中的标签,该函数根据节点的位置和大小设置转换

    ℃。原始坐标在mouseleave函数中重新应用。

答案 2 :(得分:1)

如前所述,SVG元素的绘制顺序由它们在DOM中的顺序决定。

只要在正确的元素上执行,this.parentNode.appendChild(this)技巧就会起作用。在您的情况下,它不是<image>,而是其父<g>必须移动。

images.on('mouseenter', function() {
    var parent = this.parentNode; // <g>
    parent.parentNode.appendChild(parent);
    var currNode =  d3.select(this);
    //...
})

Example (with placeholder images)