2015-10-15 88 views
0

这就是我目前使用的。无法获得d3.js data.join和键功能工作时选择线

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

但是,在更新期间,行不会按预期方式移动。我会试着发布一个更好解释的屏幕录像。我当前的实现适用于图中的节点,但出于某种原因,不适用于行。我觉得我在这里错过了一些愚蠢的东西。

的完整代码在here

编辑:

这是目前发生什么screencast。我希望两个节点之间的线路保持在这两个节点之间。

编辑II:

我添加上面一个完整的工作示例,用数据包括作为代码

+0

他们如何移动,你期望什么? –

+0

这[image](http://i.imgur.com/gmndI2F.gif)解释了我想说的。线条移动到新的位置,但与功能中的键不同。那有意义吗? – kdheepak

+0

@Dheepak在_lines上不清楚不会像预期那样移动_你期望什么......在gif行中似乎移动到了正确的位置。 – Cyril

回答

0

的部分问题是,你的关键功能引用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; }); 

并且更新按预期工作。完整演示here

+0

太棒了!有效。令人印象深刻的侦探工作拉尔斯!我很好奇你如何解决这个问题,我只用'console.log(...)'进行调试。任何提示为初学者JavaScript? – kdheepak

+0

那么,在这种情况下,我真的只是注意到你在关键函数中做了什么,以及在数据改变时它是如何改变的。经验我猜:) –