【问题标题】:how to bring the selected node front in d3 js?如何在 d3 js 中将选定的节点放在前面?
【发布时间】:2018-08-14 17:31:57
【问题描述】:

我正在使用d3 v3 脚本来可视化数据。我需要在mousecenter 中突出显示并将节点放在前面,反之亦然在mouseleave 中。现在我可以通过增加节点的高度和宽度来突出显示节点。

无法将节点放在前面。我尝试过使用不透明度、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>

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

在随附的屏幕截图中,节点“M”处于焦点位置,将鼠标悬停在该元素上。通过增加宽度和高度来突出显示节点,与节点应该在前面一样,重叠的节点应该在后面。

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

等待建议? 提前致谢。

【问题讨论】:

  • 您可以使用 d3 控制定位(“绝对”、“相对”等)或 z 索引属性。也许从那里开始。
  • @RyanMorton 已经尝试过了。不工作。
  • v4 有一个 selection.raise() 方法可以做到这一点。不幸的是 v3 没有,但 selection.order 可能会这样做。
  • 请提供您在 var url 中使用的数据,以便我们可以复制问题。

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


【解决方案1】:

d3.v4 - d3.v5 - d3.v6

.on('mouseenter', function() {

    d3.select(this).raise()

})

Example

【讨论】:

  • 是的.. 对。但是我们可以在 v4-v5 中创建相同的节点映射?
  • 是的,你可以
  • 感谢您的回复,如果可能的话,您能否举例说明我的问题。我仍然无法实现该解决方案。
【解决方案2】:

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

this.parentNode.appendChild(this) 技巧只要在正确的元素上执行即可。在您的情况下,必须移动的不是 &lt;image&gt;,而是其父 &lt;g&gt;

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

Example (with placeholder images)

【讨论】:

  • 但是,当图像出现在前面时,附加文本不显示.. 任何将文本附加到图像下方的线索
  • @Keerthivasan 您是否也在使用来自@silentstone 的代码?他的版本从&lt;g&gt; 中删除了图像,并将其放在主要&lt;svg&gt; 元素的末尾。可能是文字隐藏在图片下的原因。
  • 任何线索,当鼠标悬停在图像下方时出现文本。
【解决方案3】:

我相信您现在知道 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);
        ...
      }
    })
    

**编辑:@Keerthivasan 这是a JSFiddle,其中包含用于移动和设置文本样式的代码。请注意,

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

b.标签已被赋予与节点 ID 相关的 ID; this 用于访问 mouseenter 函数中的标签,该函数根据节点的位置和大小设置平移

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

【讨论】:

  • 感谢您的努力。图像出现在前面时效果很好..当图像出现在前面时附加文本不显示..有任何线索可以在图像下方附加文本吗??
  • 答案中添加了一个新的 JSFiddle。如果您希望标签背景具有完全不透明度,您可能需要添加一个矩形
  • 更新代码后。旧路径无法替换。一些节点位置更改为静态。检查您的 JSFiddle 本身。
猜你喜欢
  • 2012-08-05
  • 1970-01-01
  • 1970-01-01
  • 2021-01-25
  • 1970-01-01
  • 1970-01-01
  • 2019-08-08
  • 2019-05-07
  • 2012-03-17
相关资源
最近更新 更多