简体   繁体   中英

how to bring the selected node front in d3 js?

I am using the d3 v3 script to visualize the Data. I need to highlight and bring the node front in mousecenter and vice versa in mouseleave. Now I can able to high light the node by increasing height and width of the node.

Can't able to bring the node front. I've tried using CSS like opacity, z-index.

Script

<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>

在此处输入图像描述

JSON Data

{
  "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"
        }
      ]
    }
  ]
}

In the attached screenshot, node "M" is in focus, mouse over on that element. Node highlights by increasing the width and height, same as node should come front, overlapping nodes should go back.

By Fading the other elements also enough, or else re-arrange the node elements to fix the problem.

Awaiting Suggestions? Thanks in Advance.

d3.v4 - d3.v5 - d3.v6

.on('mouseenter', function() {

    d3.select(this).raise()

})

Example

I'm sure you know by now that SVG doesn't have z-index. Instead, it layers the elements based on insertion order. To solve your issue, add the node again so that it's inserted after (and displayed over) everything else.

Here's the JSFiddle with the solution, running with a sample image.

To summarize:

  1. Add an ID to the SVG so that selections are simple and unambiguous:

     vis = d3.select("#visfel_map").append("svg").attr("width", w).attr("height", h).attr("id", "mainSvg");
  2. Add an ID for each node during setup:

     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. Next, add the function to move the desired element to the end of the insertion list. I based it on this block but I'm specifying the ID of the SVG element to avoid confusion.

     d3.selection.prototype.moveToSvgFront = function() { return this.each(function(){ d3.select("#mainSvg").node().appendChild(this); }); };
  4. Finally, update the mouseenter function, using moveToSvgFront. Also invoke your existing nodeTransform function to ensure that the element is positioned correctly:

     .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); ... } })

**Edit: @Keerthivasan Here's a JSFiddle with code to also moves and styles the text. Note that

a. CSS has been added for the new class (focusLabel)

b. The labels have been given an ID related to the node's ID; this is used to access the label in the mouseenter function, which sets the translation based on the node's position and size

c. The original coordinates are reapplied in the mouseleave function.

As already mentioned, drawing order of SVG elements is determined by their order in DOM.

The this.parentNode.appendChild(this) trick works as long as it's performed on the right element. In your case, it's not the <image> but its parent <g> that has to move.

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

Example (with placeholder images)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM