2014-10-22 28 views
0

我尝试通过d3js的方式可视化网络图 - 加载它,以json文件的形式,使用简单的视图功能 - 拖动节点,缩放整个图形和全景。前两个功能工作正常,但全景...如果我平移整个图表(特别是当我慢慢地做) - 所有的图片都在晃动。节点拖动足够平滑。d3js节点和线拖动,缩放工作正常,但是当平移所有图 - 正在摇晃

这里是我的代码:

<html> 
    <title>dynamic JSON Data</title> 
<body id="posts-show"> 



    <header class="post title"> 

</header> 

    <style scoped></style> 
    <style> 
svg { 
    vertical-align: middle; 
    background: rgba(255,255,255, 0.2); 
    box-shadow: inset 0 0 3px 0px #CECECE; 
} 

svg circle { 
     fill: #AFF; 
     stroke: steelblue; 
     stroke-width: 2px; 
    cursor: pointer; 
} 


svg line { 
    stroke-width: 2px; 
    stroke: #79A32B; 
    fill: transparent; 
    cursor: pointer; 
} 

text { 
    font: 10px sans-serif; 
    pointer-events: none; 
} 


svg circle:active { 
    stroke: #45D3C7; 
     fill: #AAA; 
} 
.action-button { 
    border-radius: 2px; 
    border: 1px solid #19380D; 
    padding: 3px 12px; 
    background-color: rgba(175, 209, 183, 0.6); 
} 

.action-button:active { 
    box-shadow: inset 0 0 3px 0px #868686; 
} 

.action-button.destroy { 
    border: 1px solid #863636; 
    background-color: rgba(197, 86, 86, 0.6); 
} 


</style> 
<script src="d3.js" type="text/javascript"></script> 
<script> 
var xFn = function(d) { return d.x } 
var yFn = function(d) { return d.y } 
</script> 
<div id="demo" style="text-align: center;"> 
</div> 
<script> 


d3.json("Graph_source.json", function(json) { 

var zoom = d3.behavior.zoom() 
    .scaleExtent([-5, 20]) 
    .on("zoom", zoomed); 

function zoomed() { 
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 
}; 

function dragstarted(d) { 
    d3.event.sourceEvent.stopPropagation(); 
    d3.select(this).classed("dragging", true); 
}; 

function dragended(d) { 
    d3.select(this).classed("dragging", false); 
}; 


    var canvas_size = json['canvas']; 
    var nodes_list = json['nodes']; 
    var links_list = json['edges']; 
    var width = canvas_size[0].width; 
    var height = canvas_size[0].height; 

var drag2 = d3.behavior.drag() 
    .origin(function(d) { return d; }) 
    .on("dragstart", dragstarted) 
    .on('drag', function (d,i) { 
     g.attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y); 
    console.log(d.id + ";" + d.x + ";" + d.y + ";") 
    }) 
    .on("dragend", dragended); 

var svg = d3.select("#demo").append("svg") 
    .attr("width", width) 
    .attr("height", height) 


var g = svg.append("g") 
    .attr("transform", "translate(" + 0 + "," + 0 + ")") 
    .call(zoom) 
    .call(drag2); 

var rect = g.append("rect") 
    .attr("class", "background") 
    .attr("width", width) 
    .attr("height", height) 
    .style("fill", "none") 
    .style("pointer-events", "all"); 



    /* Define the data for the circles */ 
    var nodes = g.selectAll("g") 
     .data(nodes_list) 


    /* Define the data for the lines */ 
    var links = g.selectAll("link").data(links_list) 


/* var xScale = d3.scale.linear() 
    .range([50, 750]) 
    .domain(d3.extent(nodes_list, xFn)); 

    var yScale = d3.scale.linear() 
    .range([50, 550]) 
    .domain(d3.extent(nodes_list, yFn));*/ 



var drag = d3.behavior.drag() 
    .origin(function(d) { return d; }) 
    .on("dragstart", dragstarted) 
    .on('drag', function (d,i) { 
     d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y); 
    console.log(d.id + ";" + d.x + ";" + d.y + ";") 
     d3.select(this).attr("transform", function (d, i) { 
      return "translate(" + [d.x,d.y] + ")"; 

     }) 
    links 
     .attr("x1", function(d) { return get_node_x(d.source); }) 
     .attr("y1", function(d) { return get_node_y(d.source); }) 
     .attr("x2", function(d) { return get_node_x(d.target); }) 
     .attr("y2", function(d) { return get_node_y(d.target); }); 

    }) 
    .on("dragend", dragended); 




function get_node_x(search_key) 
{ 

    for (var i = 0; i < nodes_list.length; i++) 
    { 
     if(search_key.localeCompare(nodes_list[i].id) == 0) 
      { 
      return nodes_list[i].x; 
      } 
    } 

}; 


function get_node_y(search_key) 
{ 

    for (var i = 0; i < nodes_list.length; i++) 
    { 
     if(search_key.localeCompare(nodes_list[i].id) == 0) 
      { 
      return nodes_list[i].y; 
      } 
    } 

}; 



    links.enter() 
     .append("line") 
     .attr("class", "link") 
     .attr("x1", function(d) { return get_node_x(d.source); }) 
     .attr("y1", function(d) { return get_node_y(d.source); }) 
     .attr("x2", function(d) { return get_node_x(d.target); }) 
     .attr("y2", function(d) { return get_node_y(d.target); }); 



    /*Create and place the "blocks" containing the circle and the text */ 
    var elemEnter = nodes.enter() 
     .append("g") 
     .attr("transform", function(d){return "translate("+ d.x +","+ d.y +")"}) 
    .on("mouseover", function(d) {  
     console.log(d.id + ";" + d.x + ";" + d.x + ";" + d3.event.dx + ";" + d.y + ";" + d.y + ";" + d3.event.dy + ";") 
    }) 
    .call(drag); 




    /*Create the circle for each block */ 
    var circle = elemEnter.append("circle") 
     .attr("r", 10) 




    /* Create the text for each block */ 
    elemEnter.append("text") 
     .attr("text-anchor", "middle") 
     .text(function(d){return d.label}); 



    console.log(json); 
    console.log(svg); 


}); 






</script> 
</body> 
</html> 

和,源文件Graph_source.json:作为含元素

{ 
"canvas":[ 
    {"width": 721, "height": 352} 
    ], 
    "nodes":[ 
    {"id": "MPLS-BH-01", "label": "MPLS-BH-01" , "Host_IP": "10.158.20.3" , "size": "10.0" , "r": "153" , "g": "153" , "b": "153" , "x": 396 , "y": 60 }, 
    {"id": "MPLS-BH-02", "label": "BH-02" , "Host_IP": "10.158.20.6" , "size": "10.0" , "r": "153" , "g": "153" , "b": "153" , "x": 192 , "y": 292 }, 
    {"id": "MPLS-BH-03", "label": "BH-03" , "Host_IP": "10.158.20.4" , "size": "10.0" , "r": "153" , "g": "153" , "b": "153" , "x": 601 , "y": 93 }, 
    {"id": "MPLS-BH-04", "label": "BH-04" , "Host_IP": "10.158.20.5" , "size": "10.0" , "r": "153" , "g": "153" , "b": "153" , "x": 333 , "y": 291 }, 
    {"id": "MPLS-BH-05", "label": "BH-05" , "Host_IP": "10.158.20.1" , "size": "10.0" , "r": "153" , "g": "153" , "b": "153" , "x": 121 , "y": 191 }, 
    {"id": "MPLS-BH-06", "label": "BH-06" , "Host_IP": "10.158.20.2" , "size": "10.0" , "r": "153" , "g": "153" , "b": "153" , "x": 241 , "y": 67 } 
    ], 
"edges":[ 
    {"source": "MPLS-BH-02", "target": "MPLS-BH-04", "weight": "1.0" , "Host_A": "MPLS-BH-02" , "Interface_A": "GigabitEthernet1/2/0" , "Host_B": "MPLS-BH-04" , "Interface_B": "GigabitEthernet1/2/1" , "BW": "100" }, 
    {"source": "MPLS-BH-03", "target": "MPLS-BH-04", "weight": "1.0" , "Host_A": "MPLS-BH-03" , "Interface_A": "GigabitEthernet1/2/1" , "Host_B": "MPLS-BH-04" , "Interface_B": "GigabitEthernet1/2/0" , "BW": "100" }, 
    {"source": "MPLS-BH-05", "target": "MPLS-BH-06", "weight": "1.0" , "Host_A": "MPLS-BH-05" , "Interface_A": "GigabitEthernet2/0/0" , "Host_B": "MPLS-BH-06" , "Interface_B": "GigabitEthernet2/0/0" , "BW": "100" } 
    ] 

} 
+0

顶级g组件不需要drag2因为变焦也提供了一个拖放功能。但是,我还没有弄清楚它为什么会抖动。在我自己的项目中,我有同样的问题,所以需要找出原因。 Plunker:http://plnkr.co/edit/DMZQuEzUjPEazlQOAYjG?p=preview – bedouger 2015-05-05 15:01:17

回答

1

呼叫变焦,但实际上变换所包含的组元素。

var gContainer = svg.append("g"); 
    .attr("transform", "translate(" + 0 + "," + 0 + ")") 
    .call(zoom) 

var g = gContainer.append("g") 


// the following stays the same 
function zoomed() { 
    g.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 
}; 
0

我花了大约两天的时间来解决摇动问题。请参阅Plunker。 http://plnkr.co/edit/D6JU88?p=preview

<html> 
    <title>dynamic JSON Data</title> 
<body id="posts-show"> 

    <header class="post title"> 

</header> 

    <style scoped></style> 
    <style> 
svg { 
    vertical-align: middle; 
    background: rgba(255,255,255, 0.2); 
    box-shadow: inset 0 0 3px 0px #CECECE; 
} 

svg circle { 
     fill: #AFF; 
     stroke: steelblue; 
     stroke-width: 2px; 
    cursor: pointer; 
} 


svg line { 
    stroke-width: 2px; 
    stroke: #79A32B; 
    fill: transparent; 
    cursor: pointer; 
} 

text { 
    font: 10px sans-serif; 
    pointer-events: none; 
} 


svg circle:active { 
    stroke: #45D3C7; 
     fill: #AAA; 
} 
.action-button { 
    border-radius: 2px; 
    border: 1px solid #19380D; 
    padding: 3px 12px; 
    background-color: rgba(175, 209, 183, 0.6); 
} 

.action-button:active { 
    box-shadow: inset 0 0 3px 0px #868686; 
} 

.action-button.destroy { 
    border: 1px solid #863636; 
    background-color: rgba(197, 86, 86, 0.6); 
} 


</style> 
    <script src="http://d3js.org/d3.v3.js"></script> 
<script> 
    var xFn = function(d) { return d.x } 
    var yFn = function(d) { return d.y } 
</script> 
<div id="demo" style="text-align: center;"> 
</div> 
<script> 


d3.json("Graph_source.json", function(json) { 

    var canvas_size = json['canvas']; 
    var nodes_list = json['nodes']; 
    var links_list = json['edges']; 
    var width = canvas_size[0].width; 
    var height = canvas_size[0].height; 

    var zoom = d3.behavior.zoom() 
     .scaleExtent([-5, 20]) 
     .size([width,height]) 
     .on("zoom", zoomed); 

    function zoomed() { 
    container.attr("transform", "translate(" + d3.event.translate + ")scale(" + d3.event.scale + ")"); 
    }; 

    function dragstarted(d) { 
    d3.event.sourceEvent.stopPropagation(); 
    // d3.select(this).classed("dragging", true); 
    }; 

    function dragended(d) { 
    // d3.select(this).classed("dragging", false); 
    }; 

var svg = d3.select("body").append("svg") 
    .attr("width", width) 
    .attr("height", height) 
    .append("g") 
    .attr("transform", "translate(" + 0 + "," + 0 + ")") 
    .call(zoom); 

var rect = svg.append("rect") 
    .attr("width", width) 
    .attr("height", height) 
    .style("fill", "none") 
    .style("pointer-events", "all"); 

var container = svg.append("g"); 



     /* Define the data for the circles */ 
     var nodes = container.selectAll("g") 
      .data(nodes_list) 


     /* Define the data for the lines */ 
     var links = container.selectAll("link").data(links_list) 


    /* var xScale = d3.scale.linear() 
     .range([50, 750]) 
     .domain(d3.extent(nodes_list, xFn)); 

    var yScale = d3.scale.linear() 
     .range([50, 550]) 
     .domain(d3.extent(nodes_list, yFn));*/ 



    var drag = d3.behavior.drag() 
     .origin(function(d) { return d; }) 
     .on("dragstart", dragstarted) 
     .on('drag', function (d,i) { 
      d3.select(this).attr("cx", d.x = d3.event.x).attr("cy", d.y = d3.event.y); 
      console.log(d.id + ";" + d.x + ";" + d.y + ";") 
      d3.select(this).attr("transform", function (d, i) { 
       return "translate(" + [d.x,d.y] + ")"; 

      }) 
      links 
       .attr("x1", function(d) { return get_node_x(d.source); }) 
       .attr("y1", function(d) { return get_node_y(d.source); }) 
       .attr("x2", function(d) { return get_node_x(d.target); }) 
       .attr("y2", function(d) { return get_node_y(d.target); }); 

     }) 
     .on("dragend", dragended); 


    function get_node_x(search_key) 
    { 

     for (var i = 0; i < nodes_list.length; i++) 
     { 
      if(search_key.localeCompare(nodes_list[i].id) == 0) 
       { 
       return nodes_list[i].x; 
       } 
     } 

    }; 


    function get_node_y(search_key) 
    { 

     for (var i = 0; i < nodes_list.length; i++) 
     { 
      if(search_key.localeCompare(nodes_list[i].id) == 0) 
       { 
       return nodes_list[i].y; 
       } 
     } 

    }; 

     links.enter() 
      .append("line") 
      .attr("class", "link") 
      .attr("x1", function(d) { return get_node_x(d.source); }) 
      .attr("y1", function(d) { return get_node_y(d.source); }) 
      .attr("x2", function(d) { return get_node_x(d.target); }) 
      .attr("y2", function(d) { return get_node_y(d.target); }); 



     /*Create and place the "blocks" containing the circle and the text */ 
     var elemEnter = nodes.enter() 
      .append("g") 
      .attr("transform", function(d){return "translate("+ d.x +","+ d.y +")"}) 
      .on("mouseover", function(d) {  
       console.log(d.id + ";" + d.x + ";" + d.x + ";" + d3.event.dx + ";" + d.y + ";" + d.y + ";" + d3.event.dy + ";") 
      }) 
      .call(drag); 




     /*Create the circle for each block */ 
     var circle = elemEnter.append("circle") 
      .attr("r", 10) 




     /* Create the text for each block */ 
     elemEnter.append("text") 
      .attr("text-anchor", "middle") 
      .text(function(d){return d.label}); 



    console.log(json); 
    console.log(svg); 


    } 
); 

</script> 
</body> 
</html>