如何根据用户操作修改路径?例如:我有一个由三个点A,B和C组成的路径。当用户在路径上单击路径(现有点以外的其他地方)时,我想在路径上添加一个新点。如何在正确位置将新点插入路径?
在这里您可以找到一个示例
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]
谢谢!以前!
您不能简单地将新节点添加到数组中,必须先确定其位置。这样做的一种方法是计算与所有点的角度。当绝对值相同时,您就会知道自己找到了插入位置。唯一的障碍是,由于行的宽度,它不会完全是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));
在此处完成示例。
链接的数据对象包含源和目标节点数据对象,因此您可以使用该信息将链接分为二,通过新节点连接。
示例代码,假设linkElements
是您的D3选择链接<path>
或<line>
元素,而links
和nodes
是与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元素。