在D3.js中动态创建节点

时间:2014-10-06 18:01:14

标签: javascript jquery svg d3.js

注意:我的第一篇StackOverFlow帖子,请耐心等待。

我的代码目标:

  • 以用户友好的方式将连接图作为输入(我的意思是用户应该能够添加一个节点,比如双击。当用户想要连接两个节点时,他/她可以只选择两个节点,并且应该有一种方式让用户输入两个所选节点之间的距离)。

  • 在成功将图形作为输入之后,我想在图形上执行各种操作,例如,告诉从节点“A”到节点“B”的最短路径是什么。

方法

我决定将D3.js用于此目的。我是JavaScript / jQuery的新手,但我仍然从https://www.dashingd3js.com/table-of-contents学习了D3.js。 我见过人们使用D3.js创建了涉及图形的非常漂亮的项目,但即使在基础知识方面我也很挣扎。

尝试:

我编写了以下代码来连接两个节点:

<!DOCTYPE html>
<html>

<head>
<title>D3 Try</title>
<script type="text/javascript" src="d3.min.js"></script>

</head>

<style>

.node {
    fill: #ccc;
    stroke: #fff;
    stroke-width: 2px;
}

.link {
    stroke: #777;
    stroke-width: 2px;
}

    </style>
<body style="background-color: red">

<h2>Hello world</h2>

<script type="text/javascript">

var height=500,width=960;

// If we leave  out the x and y coordinates of the visualization, d3 selects 
// random positions for the nodes

// nodes are arbitrary objects

var nodes = [ {x: width/3, y: height/2 } , {x: 2*width/3, y: height/2} ];

// Define the array which contains information about the links

var links= [ {source: 0, target: 1}];


// container to hold the visualisation

var svg=d3.select('body').append('svg').attr('width',width).attr('height',height);

// Create force layout object which contains dimensions of the container and 
// the arrays of nodes and links


var force=d3.layout.force().size([width,height]).nodes(nodes).links(links);



// Documentation says that define a function in place of width/2 but fir bhi , how?


force.linkDistance(width/2);



var link=svg.selectAll('.link').data(links).enter().append('line').attr('class','link');

var node=svg.selectAll('.node').data(nodes).enter().append('circle').attr('class','node');



force.on('end',function(){ 




node.attr('r', width/25)
        .attr('cx', function(d) { return d.x; })
        .attr('cy', function(d) { return d.y; });



link.attr('x1', function(d) { return d.source.x; })
        .attr('y1', function(d) { return d.source.y; })
        .attr('x2', function(d) { return d.target.x; })
        .attr('y2', function(d) { return d.target.y; });


});


force.start();








</script>





</body>

</html>

我遇到的问题以及我真正想问的问题:

  1. 上面的代码连接了两个节点,好的,但是如何在用户双击时动态创建这样的节点?这里可以注意到,不仅必须在SVG上绘制节点,而且还要更新nodeslinks阵列。如何动态更新这些硬编码数组,以便将最新信息存储在其中?

  2. 两个节点之间的距离必须由用户输入,此处为常量width/2。我在github上检查了API,他们说定义了一个函数而不是一个常量。我搜索但找不到任何这样的例子。即使我使用D3提供的变量d,它也没用,因为它必须依赖于用户。

  3. 有任何帮助吗?谢谢。

1 个答案:

答案 0 :(得分:0)

要做到这一点,你可以依靠d3 .enter()方法的魔力。这是一个对选择进行操作的数据,并为分配给当前未映射到DOM中的SVG元素的选择的每个数据返回占位符。

这意味着如果您修改数据,则可以将该数据附加到选择中,并对选择中的更改所代表的数据进行任何更改。如果要为数据添加节点,它将如下所示:

//Modify data
nodes.push({x : d3.mouse(svg)[0], y : d3.mouse(svg)[1]});

//Modify data of node selection
node.data(nodes);

//Operate on new nodes
node.enter()
  .append('circle')
  .attr('class','node')
  .attr('r', width/25)
  .attr('cx', function(d) { return d.x; })
  .attr('cy', function(d) { return d.y; });
  .call(force.end);

由于您的前两个数据点在您第一次创建时已经分配了DOM节点,因此只会为新数据点添加新的circle元素。

所有这些都将在mousedownclick的事件处理程序中调用,并以鼠标位置的形式接受用户输入。