假设我有一个任意的点数组,即
var points = [
//e: terminals
//a: arm
//s: support
{x: 32, y: 256, t: "e"},
{x: 250, y: 256, t: "a"},
{x: 260, y: 256, t: "s"},
{x: 320, y: 256, t: "a"},
{x: 330, y: 256, t: "s"},
{x: 128, y: 256, t: "a"},
{x: 138, y: 256, t: "s"},
{x: 480, y: 256, t: "e"}
];
还有另一个称为线段,它定义了这些点如何设置为一条路径:
var segments = [
{start: 0, support: null, end: 5},
{start: 5, support: 6, end: 1},
{start: 1, support: 2, end: 3},
{start: 3, support: 4, end: 7}
];
手臂点(t:“ a”)始终具有以下t:“ s”支持一个。
通过双击臂点(洋红色),代码必须删除它以及其支撑点(青色)以及重新索引点和线段数组。
例如,如果您要删除{x:128,y:256,t:“ a”}及其对{x:138,y:256,t:“ s”},则重新索引的数组必须为像这样:
var points = [
{x: 32, y: 256, t: "e"},
{x: 250, y: 256, t: "a"},
{x: 260, y: 256, t: "s"},
{x: 320, y: 256, t: "a"},
{x: 330, y: 256, t: "s"},
{x: 480, y: 256, t: "e"}
];
可变段= [
{start: 0, support: null, end: 1},
{start: 1, support: 2, end: 3},
{start: 3, support: 5, end: 5}
];
而且我可以找到一种有效的方法来进行重新索引。附带代码。
var points = [
//e: terminals
//a: arm
//s: support
{x: 32, y: 256, t: "e"},
{x: 250, y: 256, t: "a"},
{x: 260, y: 256, t: "s"},
{x: 320, y: 256, t: "a"},
{x: 330, y: 256, t: "s"},
{x: 128, y: 256, t: "a"},
{x: 138, y: 256, t: "s"},
{x: 480, y: 256, t: "e"}
//the fist and last points are always end ones
];
var segments = [
{start: 0, support: null, end: 5},
{start: 5, support: 6, end: 1},
{start: 1, support: 2, end: 3},
{start: 3, support: 4, end: 7}
];
var svg = d3.select("#container");
var path = svg.append("path")
.attr("d", generatePath())
.attr("stroke", "#000000")
.attr("stroke-width", 2);
var node = svg.selectAll(".node")
.data(getAllPoints())
.enter()
.append("circle")
.attr("class", "node")
.attr("cx", function(d_) { return d_.x; })
.attr("cy", function(d_) { return d_.y; })
.attr("r", 4)
.attr("fill", function(d_){
if(d_.t == "e") { return "#FF0000"; }
else if(d_.t == "s") { return "#00FFFF"; }
return "#FF00FF";
})
.on("dblclick", function(d_){
if(d_.t == "a"){
console.log("have to delete this point and its support")
console.log("and reindex points and segments array")
//if there is only one pair of a/s points
//the solution is straight forward
//while first and last points are always end ones
if(segments.length == 2){
points.splice(d_.id, 2);
points.forEach(function(p_, i_){ p_.id = i_; });
newSegments = [{start: 0, support: null, end: 1}];
}else{
//could find effective solution here
//has to work but it doesn't
//segments.forEach(function(segment_){
//
// if(segment_.end != d_.id){
//
// var start = segment_.start,
// support = segment_.support,
// end = segment_.end;
//
// if(start > d_.id - 2) { start -= 2; }
// if(support > d_.id - 2 && support != null) { support -= 2; }
// if(end > d_.id - 2) { end -= 2; }
//
// newSegments.push({start: start, support: support, end: end})
//
// }
//
// points.splice(d_.id, 2);
// points.forEach(function(p_, i_){ p_.id = i_; });
// segments = newSegments;
}
}
})
function generatePath(){
var out = "";
segments.forEach(function(segment_, i_){
if(i_ == 0) {
//skip support point
out += "M" + points[segment_.start].x + " " + points[segment_.start].y;
out += " L" + points[segment_.end].x + " " + points[segment_.end].y;
}else{
out += " L" + points[segment_.start].x + " " + points[segment_.start].y;
out += " L" + points[segment_.support].x + " " + points[segment_.support].y;
out += " L" + points[segment_.end].x + " " + points[segment_.end].y;
}
})
return out;
}
function getAllPoints(){
var out = [];
points.forEach(function(point_, i_){ out.push(point_); out[out.length - 1].id = i_; });
return out;
}
body { margin: 0; }
#container {
position: absolute;
left: 0; top: 0;
width: 512px;
height: 512px;
background-color: darkgray;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>D3.JS: Points chain</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg id="container" width="512" height="512"></svg>
</body>
</html>
似乎我自己找到了解决方案。
var points = [
//e: terminals
//a: arm
//s: support
{x: 32, y: 256, t: "e"},
{x: 250, y: 256, t: "a"},
{x: 260, y: 256, t: "s"},
{x: 320, y: 256, t: "a"},
{x: 330, y: 256, t: "s"},
{x: 128, y: 256, t: "a"},
{x: 138, y: 256, t: "s"},
{x: 480, y: 256, t: "e"}
//the fist and last points are always end ones
];
var segments = [
{start: 0, support: null, end: 5},
{start: 5, support: 6, end: 1},
{start: 1, support: 2, end: 3},
{start: 3, support: 4, end: 7}
];
var svg = d3.select("#container");
draw();
function draw(){
svg.selectAll("path").remove();
svg.selectAll("circle").remove();
var path = svg.append("path")
.attr("d", generatePath())
.attr("stroke", "#000000")
.attr("stroke-width", 2);
var node = svg.selectAll(".node")
.data(getAllPoints())
.enter()
.append("circle")
.attr("class", "node")
.attr("cx", function(d_) { return d_.x; })
.attr("cy", function(d_) { return d_.y; })
.attr("r", 4)
.attr("fill", function(d_){
if(d_.t == "e") { return "#FF0000"; }
else if(d_.t == "s") { return "#00FFFF"; }
return "#FF00FF";
})
.on("dblclick", function(d_){
if(d_.t == "a"){
if(segments.length == 2){
points.splice(d_.id, 2);
points.forEach(function(p_, i_){ p_.id = i_; });
segments = [{start: 0, support: null, end: 1}];
}else{
var newsegs = [];
for(var i = 0; i < segments.length; i++){
if(segments[i].end == d_.id){
if(i < segments.length - 2){
newsegs.push({
start: segments[i].start,
support: segments[i].support,
end: segments[i + 1].end
});
newsegs.push({
start: segments[i + 2].start,
support: segments[i + 2].support,
end: segments[i + 2].end
});
i += 2; continue;
}else{
newsegs.push({
start: segments[i].start,
support: segments[i].support,
end: segments[i + 1].end
});
i++; continue;
}
}else{
newsegs.push(segments[i]);
}
}
newsegs.forEach(function(segment_){
if(segment_.start >= d_.id) { segment_.start -= 2; }
if(segment_.support >= d_.id) { segment_.support -= 2; }
if(segment_.end >= d_.id) { segment_.end -= 2; }
})
segments = newsegs;
points.splice(d_.id, 2);
points.forEach(function(p_, i_){ p_.id = i_; });
}
console.log(points);
console.log(segments);
draw();
}
})
}
function generatePath(){
var out = "";
segments.forEach(function(segment_, i_){
if(i_ == 0) {
//skip support point
out += "M" + points[segment_.start].x + " " + points[segment_.start].y;
out += " L" + points[segment_.end].x + " " + points[segment_.end].y;
}else{
out += " L" + points[segment_.start].x + " " + points[segment_.start].y;
//out += " L" + points[segment_.support].x + " " + points[segment_.support].y;
out += " L" + points[segment_.end].x + " " + points[segment_.end].y;
}
})
return out;
}
function getAllPoints(){
var out = [];
points.forEach(function(point_, i_){ out.push(point_); out[out.length - 1].id = i_; });
return out;
}
body { margin: 0; }
#container {
position: absolute;
left: 0; top: 0;
width: 512px;
height: 512px;
background-color: darkgray;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>D3.JS: Points chain</title>
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no" />
<script src="https://d3js.org/d3.v4.min.js"></script>
</head>
<body>
<svg id="container" width="512" height="512"></svg>
</body>
</html>