无法获取d3.js数据.选择线路时连接和键功能工作

Unable to get d3.js data.join and key function working when selecting line

本文关键字:连接 工作 功能 线路 选择 获取 d3 js 数据      更新时间:2023-09-26

这是我目前使用的。

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <title>Git commit history</title>
</head>
<body>
<button onclick="f(data0)">Original</button>
<button onclick="f(data1)">Final</button>
    <div id="chart"></div>
<script src='http://d3js.org/d3.v3.min.js'></script>
<script>
var data1 = {"directed": true, "HEAD": "37e1d1e19f1ed57f8635ba4ba48d7a6a16ec52f6", "links": [{"source": 0, "target": 2}, {"source": 2, "target": 1}, {"source": 3, "target": 4}, {"source": 4, "target": 0}, {"source": 4, "target": 5}, {"source": 5, "target": 2}], "multigraph": false, "graph": [], "labels": ["master"], "master": "37e1d1e19f1ed57f8635ba4ba48d7a6a16ec52f6", "nodes": [{"message": "Add barn door", "id": "2b818acb7782772d0b43a0fbfd18320348c66d09", "pos": [182.04, 162.0]}, {"message": "Initial commit", "id": "5d49116ea5679a9eb21225f05dd4874b3a0b5e35", "pos": [371.04, 18.0]}, {"message": "Add animals", "id": "a21fd23c9a9742c93febff279d7f917d457c0f04", "pos": [371.04, 90.0]}, {"message": "Add chickens", "id": "37e1d1e19f1ed57f8635ba4ba48d7a6a16ec52f6", "pos": [371.04, 306.0]}, {"message": "Merge branch 'add-barn-doors'", "id": "f0f204010fe90e377f37c8e466110e49e420ac9e", "pos": [371.04, 234.0]}, {"message": "Remove cow", "id": "009d60bee58372a19e1188368ecfcc3c9ed5c2f1", "pos": [560.04, 162.0]}]}
var data0 = {"directed": true, "HEAD": "f0f204010fe90e377f37c8e466110e49e420ac9e", "links": [{"source": 0, "target": 4}, {"source": 1, "target": 0}, {"source": 1, "target": 2}, {"source": 2, "target": 4}, {"source": 4, "target": 3}], "multigraph": false, "graph": [], "labels": ["master"], "master": "f0f204010fe90e377f37c8e466110e49e420ac9e", "nodes": [{"message": "Add barn door", "id": "2b818acb7782772d0b43a0fbfd18320348c66d09", "pos": [182.04, 162.0]}, {"message": "Merge branch 'add-barn-doors'", "id": "f0f204010fe90e377f37c8e466110e49e420ac9e", "pos": [371.04, 234.0]}, {"message": "Remove cow", "id": "009d60bee58372a19e1188368ecfcc3c9ed5c2f1", "pos": [560.04, 162.0]}, {"message": "Initial commit", "id": "5d49116ea5679a9eb21225f05dd4874b3a0b5e35", "pos": [371.04, 18.0]}, {"message": "Add animals", "id": "a21fd23c9a9742c93febff279d7f917d457c0f04", "pos": [371.04, 90.0]}]}
var w = 1500,
    H = 50,
    fill = d3.scale.category20();
var h = H;
var vis = d3.select("#chart")
  .append("svg:svg");
var f = function(data) {
h = H*1.45*data.nodes.length;
    vis.attr("height", h)
    .attr("width", w);
    h = H*1.45*data.nodes.length;
        vis.attr("height", h);
    var transitiontime = 150;
var PosX = function(d, i, location) { return data.nodes[d[location]].pos[0]; };
var PosY = function(d, i, location) { return h-data.nodes[d[location]].pos[1]; };
var reverseMap = {};
    for(var i=0; i<data.nodes.length; i++){
    var p = data.nodes[i];
    var hash = p.id;
    reverseMap[hash] = p;
    };
    function poslink(d, i){ try{ return data.nodes[d.source].id + "" + data.nodes[d.target].id;} catch(err) {console.log(err); } }

var linkUpdateSelection = vis.selectAll(".link")
    .data(data.links, poslink);
    linkUpdateSelection.exit().remove();
    linkUpdateSelection
    .enter().append("line")          // attach a line
    .attr("class", "link")
    .style("stroke", "black")  // colour the line
    .attr("x1", function(d, i) {return PosX(d, i, "source");}) // x position of the first end of the line
    .attr("y1", function(d, i) {return PosY(d, i, "source");}) // y position of the first end of the line
    .attr("x2", function(d, i) {return PosX(d, i, "target");}) // x position of the second end of the line
    .attr("y2", function(d, i) {return PosY(d, i, "target");})    // y position of the second end of the line
     .style('opacity', 0);
     linkUpdateSelection
    .attr("class", "link")
    .style("stroke", "black")  // colour the line
        .transition()
        .delay(function(d,i) {return i*transitiontime})
    .attr("x1", function(d, i) {return PosX(d, i, "source");}) // x position of the first end of the line
    .attr("y1", function(d, i) {return PosY(d, i, "source");}) // y position of the first end of the line
    .attr("x2", function(d, i) {return PosX(d, i, "target");}) // x position of the second end of the line
    .attr("y2", function(d, i) {return PosY(d, i, "target");})    // y position of the second end of the line
        .style('opacity', 1);
  var nodeUpdateSelection = vis.selectAll("circle.node")
      .data(data.nodes, function(d) {return d.id});
    nodeUpdateSelection.exit().remove();
    nodeUpdateSelection.enter().append("svg:circle")
      .attr("class", "node")
      .attr("cx", function(d, i) { return d.pos[0]; })
      .attr("cy", function(d, i) { return h-d.pos[1]; })
      .attr("r", 0)
      .attr('fill', function(d, i) {if (reverseMap[d.id]==reverseMap[data['HEAD']]){return '#99FF66';} else {return 'red';}} )
      .on('mouseover', function(d,i) {
        d3.select(this).transition()
          .ease('cubic-out')
          .duration('200')
          .attr("r", 15)
      })
      .on('mouseout', function(d,i) {
        d3.select(this).transition()
          .ease('cubic-out')
          .duration('200')
          .attr("r", 10)
      });
    nodeUpdateSelection.transition()
        .delay(function(d,i) {return i*transitiontime})
        .attr("class", "node")
        .attr("cx", function(d, i) { return d.pos[0]; })
        .attr("cy", function(d, i) { return h-d.pos[1]; })
        .attr('fill', function(d, i) {if (reverseMap[d.id]==reverseMap[data['HEAD']]){return '#99FF66';} else {return 'red';}} )
        .attr("r", 10);
    var textUpdateSelection = vis.selectAll("text.message")
        .data(data.nodes, function(d) {return d.id});
    textUpdateSelection.exit().remove();
    textUpdateSelection
    .enter().append("text")
      .text(function(d) { return d.id.substring(0, 6) + " - " + d.message; })
                 .attr("x", function(d) { return 15+d.pos[0]; })
                 .attr("y", function(d) { return h-d.pos[1]+5; })
                 .attr("font-family", "sans-serif")
                 .attr("class", "message")
                 .attr("font-size", "15px")
                 .attr("fill", "blue")
                 .style('fill-opacity', 0);
    textUpdateSelection
      .text(function(d) { return d.id.substring(0, 6) + " - " + d.message; })
                 .transition()
                 .delay(function(d,i) {return i*transitiontime})
                    .style('fill-opacity', 1)
                 .attr("x", function(d) { return 15+d.pos[0]; })
                 .attr("y", function(d) { return h-d.pos[1]+5; })
                 .attr("class", "message")
                 .attr("font-family", "sans-serif")
                 .attr("font-size", "15px")
                 .attr("fill", "blue");

    var labelUpdateSelection = vis.selectAll("text.labels")
        .data(data.labels);
var labelPosX = function(d) { return reverseMap[d].pos[0]; };
var labelPosY = function(d) { return reverseMap[d].pos[1]; };
    labelUpdateSelection.exit().remove();
    labelUpdateSelection.enter().append("text")
      .text(function(d) { return d })
                    .style('fill-opacity', 0)
     .attr("x", function(d, i) { return data[d][0]- 75; })
     .attr("y", function(d, i) { return h-data[d][1] + 5; })
     .attr("class", "labels")
     .attr("font-family", "sans-serif")
     .attr("font-size", "15px");
    labelUpdateSelection
      .text(function(d) { return d })
                 .transition()
                 .delay(function(d,i) {return i*transitiontime})
                    .style('fill-opacity', 1)
     .attr("x", function(d, i) { return labelPosX(data[d]) - 50 ; })
     .attr("y", function(d, i) { return h-labelPosY(data[d]) - 25 + i*5; })
     .attr("class", "labels")
     .attr("font-family", "sans-serif")
     .attr("font-size", "15px");

    }
f(data0)
    </script>
</body>
</html>

但是,在更新期间,行没有按预期移动。为了更好地解释,我将尝试发布一个正在发生的事情的视频。我目前的实现适用于图中的节点,但由于某种原因,不适用于线。我觉得我在这里错过了一些愚蠢的东西。

完整代码在这里

编辑:

这是当前发生的屏幕截图。我希望两个节点之间的线保持在这两个节点之间。

编辑二:

我在上面添加了一个完整的工作示例,其中包含的数据作为代码
的一部分。

问题是您的键函数引用data,它在调用之间变化。一条链路的源节点和目标节点通过索引来引用,同一个索引指向不同的节点,具有不同的数据。也就是说,对于原始数据,索引0可能指向"foo",但对于新数据,相同的索引指向"bar"。

解决这个问题最简单的方法是将索引与链接保存在一种数据改变时不会改变的方式:

data.links.forEach(function(d) {
  d.id = data.nodes[d.source].id + "" + data.nodes[d.target].id;
});

则数据匹配变为

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

,更新按预期工作。完整的演示在这里。