使用d3js在路径中间添加顶点

时间:2014-02-06 16:44:09

标签: d3.js

如何根据用户操作修改路径? 例如:我有一个由三个点A,B和C组成的路径。当用户点击路径(除了现有点之外的其他地方)时,我想在该位置添加一个新点到路径。如何将新点插入到正确位置的路径中?

Here you can find an example

var nodes = [[30, 130], [250, 250], [400,130]];

var line = d3.svg.line();

var svg = d3.select("body").append("svg")
        .attr("width", 500)
        .attr("height", 5000);

var path = svg.append("path")
            .datum(nodes)
            .attr("class", "line")
            .call(update);

path.on("click", insertNode);

function update() {
  svg.select("path").attr("d", line);

  var circle = svg.selectAll("circle")
      .data(nodes, function(d) { return d; });
}

function insertNode(data) {
     //create the new node:
   var newNode = [];


   var newNode = d3.mouse(svg.node());
       //find coordinates relative to the plotting region

   nodes.push(newNode); //add to your nodes array


   update();
}

如果单击第一个段(sx - > dx),则会从路径末尾添加一个新段到新节点,因为我在节点数组的末尾添加了新节点。正确的行为是节点[30,130]和[250,250]之间的路径(节点阵列)中的新节点

谢谢! 前!

2 个答案:

答案 0 :(得分:3)

您不能简单地将新节点添加到数组中,您必须先确定其位置。这样做的一种方法是计算所有点的角度。当绝对值相同时,您就知道已经找到了插入位置。唯一的障碍是因为线的宽度,它不会完全是180度,所以你必须考虑到这一点。以下代码尝试此操作并将新节点拼接到数组中。

var idx = 0, prevAngle;
nodes.forEach(function(n, i) {
    var angle = Math.abs(Math.atan((n[1] - newNode[1]) / (n[0] - newNode[0])));
    if(Math.abs(angle - prevAngle) < 0.05) {
        idx = i;
    }
    prevAngle = angle;
});

tmp = nodes.slice(0, idx);
tmp.push(newNode);
nodes = tmp.concat(nodes.slice(idx));

完整示例here

答案 1 :(得分:0)

链接的数据对象包含源节点数据对象和目标节点数据对象,因此您可以使用该信息将链接拆分为两个,通过新节点连接。

示例代码,假设linkElements是您对链接<path><line>元素的d3选择,linksnodes是对应的数据数组force.links()force.nodes()

linkElements.on("click", insertNode);

function insertNode(linkData){ //parameter is the *link's* data object

   //create the new node:
   var newNode = {};

   var clickPoint = d3.mouse(this.parentNode);
       //find coordinates relative to the plotting region

   newNode.x = xScale.invert(clickPoint[0]);
   newNode.y = yScale.invert(clickPoint[1]);
       //convert coordinates to data values

   nodes.push(newNode); //add to your nodes array


   //create a new link for the second half of the old link:
   var newLink = {source:newNode, target:linkData.target};

   links.push(newLink); //add to your links array

   //update the old link to point to the new node:
   linkData.target = newNode;

   update();
}

这当然只更新节点和链接的数据对象,您的update()函数必须更新力布局并创建输入的SVG元素。