我从d3js开始并尝试创建Graph数据结构。
代码如下(对于这么多代码感到遗憾,无法找到解析它的方法以用于演示目的)。 所以这里。
var nodeNumber = 1;
$(document).ready(function() {
var graphContainer = d3.select(".graph-diagram").append("svg").attr("width", 1500).attr("height", 600).attr("class", "graph-container");
//CreateNode(nodeId,nodeLabel,className,nodeType)
var root = CreateNode(nodeNumber, "root", "head", "root");
//creating children initially
CreateChild(nodeNumber, "child", "head", "rightchild", "1");
CreateChild(nodeNumber, "child", "head", "leftchild", "1");
CreateChild(nodeNumber, "child", "head", "leftchild", "1");
//CreateChild("5","child","head","rightchild","1");
//creating edges initially
CreateEdge("1", "2", "label");
CreateEdge("1", "3", "label");
CreateEdge("1", "4", "label");
//CreateEdge("1","5","label");
});
//function to calculate position of new node , can be ignored
function CalculatePosition(nodeType, parentId) {
var positions = {};
var noOfChildren = parseInt($("rect[nodeId=" + parentId + "]").attr('children'));
if (nodeType == "root") {
positions.positionX = parseInt($(".graph-container").attr('width')) / 2;
positions.positionY = parseInt($(".graph-container").attr('height')) / 2;
} else {
if (noOfChildren % 2 == 0) {
if (nodeType == "rightchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) - 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) + 300;
} else if (nodeType == "leftchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) - 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) - 300;
}
} else {
if (nodeType == "rightchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) + 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) + 300;
} else if (nodeType == "leftchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) + 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) - 300;
}
}
}
return positions;
}
//create root node , click function is inside this (executes only one time)
function CreateNode(nodeId, nodeLabel, className, nodeType) {
var node = d3.select("svg").append('g');
var positions = CalculatePosition(nodeType);
node.append("rect")
.attr("x", positions.positionX)
.attr("y", positions.positionY)
.attr("height", 50)
.attr("width", 200)
.attr("rx", 30)
.attr("ry", 30)
.attr("nodeId", nodeId)
.attr("children", "0")
.style("fill", "#f1f1f1")
.style("stroke", "none");
node.append("text")
.attr("x", positions.positionX + 100)
.attr("y", positions.positionY + 30)
.attr("text-anchor", "middle")
.style("font-size", "24px")
.attr('fill', '#444')
.text(nodeLabel);
var addchild = node.append("g");
addchild.append("circle")
.attr("cx", positions.positionX + 170)
.attr("cy", positions.positionY + 25)
.attr("r", 10)
.attr("class", "addchild")
.style("fill", "white")
.style("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 162)
.attr("y1", positions.positionY + 25)
.attr("x2", positions.positionX + 178)
.attr("y2", positions.positionY + 25)
.attr("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 170)
.attr("y1", positions.positionY + 17)
.attr("x2", positions.positionX + 170)
.attr("y2", positions.positionY + 33)
.attr("stroke", "#444")
.style("stroke-width", "2");
//click function that executes only one time. ( for adding in root alone)
addchild.on("click", function() {
$("#child-info").show();
$("#btn-add-child").click(function() {
var parentX = parseInt($("rect[nodeId=1]").attr('x'));
var childType;
if (positions.positionX < parentX) {
childType = "leftchild";
} else {
childType = "rightchild";
}
CreateChild(nodeNumber, $("#child-text").val(), "head", childType, nodeId);
CreateEdge("1", nodeNumber - 1, $("#child-label").val());
$("#child-info").hide();
});
});;
nodeNumber++;
return node;
}
//create children **********click function where the problem might be************
function CreateChild(nodeId, nodeLabel, className, nodeType, parentId) {
var node = d3.select("svg").append('g');
var positions = CalculatePosition(nodeType, parentId);
// create rounded rectangle
node.append("rect")
.attr("x", positions.positionX)
.attr("y", positions.positionY)
.attr("height", 40)
.attr("width", 200)
.attr("rx", 20)
.attr("ry", 20)
.attr("nodeId", nodeId)
.attr("children", "0")
.style("fill", "#f1f1f1")
.style("stroke", "none")
.transition()
.duration(750);
//add text
node.append("text")
.attr("x", positions.positionX + 50)
.attr("y", positions.positionY + 30)
.attr("text-anchor", "middle")
.style("font-size", "24px")
.attr('fill', '#444')
.text(nodeLabel);
//add plus symbol can be ignored
var addchild = node.append("g");
addchild.append("circle")
.attr("cx", positions.positionX + 170)
.attr("cy", positions.positionY + 25)
.attr("r", 10)
.attr("class", "addchild")
.style("fill", "white")
.style("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 162)
.attr("y1", positions.positionY + 25)
.attr("x2", positions.positionX + 178)
.attr("y2", positions.positionY + 25)
.attr("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 170)
.attr("y1", positions.positionY + 17)
.attr("x2", positions.positionX + 170)
.attr("y2", positions.positionY + 33)
.attr("stroke", "#444")
.style("stroke-width", "2");
// **********click function where the problem might be************
addchild.on("click", function() {
$("#child-info").show();
$("#btn-add-child").click(function() {
console.log("nodenumber=" + nodeNumber);
console.log("nodeid=" + nodeId);
var parentX = parseInt($("rect[nodeId=1]").attr('x'));
var childType;
if (positions.positionX < parentX) {
childType = "leftchild";
} else {
childType = "rightchild";
}
CreateChild(nodeNumber, $("#child-text").val(), "head", childType, nodeId);
CreateEdge(nodeId, nodeNumber - 1, $("#child-label").val());
$("#child-info").hide();;
});
});;
var noOfChildren = parseInt($("rect[nodeId=" + parentId + "]").attr('children'));
noOfChildren = noOfChildren + 1;
$("rect[nodeId=" + parentId + "]").attr("children", String(noOfChildren));
nodeNumber++;
}
// function to calculate data for drawing edges , can be ignored
function CalculateEdgeData(nodeId1, nodeId2) {
var node1x = parseInt($("rect[nodeId=" + nodeId1 + "]").attr('x'));
var node1y = parseInt($("rect[nodeId=" + nodeId1 + "]").attr('y'));
var node2x = parseInt($("rect[nodeId=" + nodeId2 + "]").attr('x'));
var node2y = parseInt($("rect[nodeId=" + nodeId2 + "]").attr('y'));
if (node1x < node2x) {
//right
node1x = node1x + 200;
node1y = node1y + 25;
node2y = node2y + 25;
} else {
//left
node1x = node1x;
node1y = node1y + 25;
node2y = node2y + 25;
node2x = node2x + 200;
}
return [{
"x": node1x,
"y": node1y
}, {
"x": node2x,
"y": node2y
}];
}
//function to draw the edge , can be ignored
function CreateEdge(nodeId1, nodeId2, edgeLabel) {
var curveData = CalculateEdgeData(nodeId1, nodeId2);
//diagonal function
var edge = d3.select("svg").append('g');
var diagonal = d3.svg.diagonal()
.source(function(d) {
return {
"x": d[0].y,
"y": d[0].x
};
})
.target(function(d) {
return {
"x": d[1].y,
"y": d[1].x
};
})
.projection(function(d) {
return [d.y, d.x];
});
var curve = edge
.datum(curveData)
.append("path")
.attr("class", "link")
.transition()
.duration("750")
.attr("d", diagonal);
curve
.attr("stroke", "#70dbdb")
.attr("stroke-width", 2)
.attr("fill", "none");
edge.append("text")
.attr("x", parseInt(curveData[0].x) + parseInt(curveData[1].x) / 3)
.attr("y", parseInt(curveData[0].y) + parseInt(curveData[1].y) / 2)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.attr('fill', '#444')
.attr("transform", "translate(-270,-170)")
.text(edgeLabel);
}
&#13;
#child-info {
background: #f1f1f1;
width: 500px;
height: auto;
position: fixed;
padding: 10px;
display: none;
}
#btn-add-child {
background: #444;
color: #fff;
border: none;
z-index: 100;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="child-info">
<input type="text" id="child-text" placeholder="child name">
<input type="text" id="child-label" placeholder="label">
<button id="btn-add-child">add</button>
</div>
<div class="graph-diagram">
</div>
&#13;
我试图在点击按钮时添加新节点。 问题是,当我第一次添加孩子时,我点击一个添加按钮。当我单击另一个添加按钮时,第二次将节点添加到我之前和之前单击的节点。 (第三次单击调用函数),对所有先前的添加执行函数。 我怀疑点击事件的绑定出了问题。我做错了什么?
(请参阅代码段并尝试在不同位置添加节点以了解我的意思)
为了便于查看代码,我评论了部分代码以及可以忽略的那些部分,因为它与上述问题无关。
感谢。
答案 0 :(得分:1)
这是因为每次使用$("#btn-add-child").click(function() {
绑定前都可以取消绑定点击事件时绑定点击事件$("#btn-add-child").off('click');
。请尝试以下代码: -
var nodeNumber = 1;
$(document).ready(function() {
var graphContainer = d3.select(".graph-diagram").append("svg").attr("width", 1500).attr("height", 600).attr("class", "graph-container");
//CreateNode(nodeId,nodeLabel,className,nodeType)
var root = CreateNode(nodeNumber, "root", "head", "root");
//creating children initially
CreateChild(nodeNumber, "child", "head", "rightchild", "1");
CreateChild(nodeNumber, "child", "head", "leftchild", "1");
CreateChild(nodeNumber, "child", "head", "leftchild", "1");
//CreateChild("5","child","head","rightchild","1");
//creating edges initially
CreateEdge("1", "2", "label");
CreateEdge("1", "3", "label");
CreateEdge("1", "4", "label");
//CreateEdge("1","5","label");
});
//function to calculate position of new node , can be ignored
function CalculatePosition(nodeType, parentId) {
var positions = {};
var noOfChildren = parseInt($("rect[nodeId=" + parentId + "]").attr('children'));
if (nodeType == "root") {
positions.positionX = parseInt($(".graph-container").attr('width')) / 2;
positions.positionY = parseInt($(".graph-container").attr('height')) / 2;
} else {
if (noOfChildren % 2 == 0) {
if (nodeType == "rightchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) - 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) + 300;
} else if (nodeType == "leftchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) - 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) - 300;
}
} else {
if (nodeType == "rightchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) + 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) + 300;
} else if (nodeType == "leftchild") {
positions.positionY = parseInt($("rect[nodeId=" + parentId + "]").attr('y')) + 100;
positions.positionX = parseInt($("rect[nodeId=" + parentId + "]").attr('x')) - 300;
}
}
}
return positions;
}
//create root node , click function is inside this (executes only one time)
function CreateNode(nodeId, nodeLabel, className, nodeType) {
var node = d3.select("svg").append('g');
var positions = CalculatePosition(nodeType);
node.append("rect")
.attr("x", positions.positionX)
.attr("y", positions.positionY)
.attr("height", 50)
.attr("width", 200)
.attr("rx", 30)
.attr("ry", 30)
.attr("nodeId", nodeId)
.attr("children", "0")
.style("fill", "#f1f1f1")
.style("stroke", "none");
node.append("text")
.attr("x", positions.positionX + 100)
.attr("y", positions.positionY + 30)
.attr("text-anchor", "middle")
.style("font-size", "24px")
.attr('fill', '#444')
.text(nodeLabel);
var addchild = node.append("g");
addchild.append("circle")
.attr("cx", positions.positionX + 170)
.attr("cy", positions.positionY + 25)
.attr("r", 10)
.attr("class", "addchild")
.style("fill", "white")
.style("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 162)
.attr("y1", positions.positionY + 25)
.attr("x2", positions.positionX + 178)
.attr("y2", positions.positionY + 25)
.attr("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 170)
.attr("y1", positions.positionY + 17)
.attr("x2", positions.positionX + 170)
.attr("y2", positions.positionY + 33)
.attr("stroke", "#444")
.style("stroke-width", "2");
//click function that executes only one time. ( for adding in root alone)
addchild.on("click", function() {
$("#child-info").show();
$("#btn-add-child").off('click');
$("#btn-add-child").on('click',function() {
var parentX = parseInt($("rect[nodeId=1]").attr('x'));
var childType;
if (positions.positionX < parentX) {
childType = "leftchild";
} else {
childType = "rightchild";
}
CreateChild(nodeNumber, $("#child-text").val(), "head", childType, nodeId);
CreateEdge("1", nodeNumber - 1, $("#child-label").val());
$("#child-info").hide();
});
});;
nodeNumber++;
return node;
}
//create children **********click function where the problem might be************
function CreateChild(nodeId, nodeLabel, className, nodeType, parentId) {
var node = d3.select("svg").append('g');
var positions = CalculatePosition(nodeType, parentId);
// create rounded rectangle
node.append("rect")
.attr("x", positions.positionX)
.attr("y", positions.positionY)
.attr("height", 40)
.attr("width", 200)
.attr("rx", 20)
.attr("ry", 20)
.attr("nodeId", nodeId)
.attr("children", "0")
.style("fill", "#f1f1f1")
.style("stroke", "none")
.transition()
.duration(750);
//add text
node.append("text")
.attr("x", positions.positionX + 50)
.attr("y", positions.positionY + 30)
.attr("text-anchor", "middle")
.style("font-size", "24px")
.attr('fill', '#444')
.text(nodeLabel);
//add plus symbol can be ignored
var addchild = node.append("g");
addchild.append("circle")
.attr("cx", positions.positionX + 170)
.attr("cy", positions.positionY + 25)
.attr("r", 10)
.attr("class", "addchild")
.style("fill", "white")
.style("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 162)
.attr("y1", positions.positionY + 25)
.attr("x2", positions.positionX + 178)
.attr("y2", positions.positionY + 25)
.attr("stroke", "#444")
.style("stroke-width", "2");
addchild.append("line")
.attr("x1", positions.positionX + 170)
.attr("y1", positions.positionY + 17)
.attr("x2", positions.positionX + 170)
.attr("y2", positions.positionY + 33)
.attr("stroke", "#444")
.style("stroke-width", "2");
// **********click function where the problem might be************
addchild.on("click", function() {
$("#child-info").show();
$("#btn-add-child").off('click');
$("#btn-add-child").on('click',function() {
console.log("nodenumber=" + nodeNumber);
console.log("nodeid=" + nodeId);
var parentX = parseInt($("rect[nodeId=1]").attr('x'));
var childType;
if (positions.positionX < parentX) {
childType = "leftchild";
} else {
childType = "rightchild";
}
CreateChild(nodeNumber, $("#child-text").val(), "head", childType, nodeId);
CreateEdge(nodeId, nodeNumber - 1, $("#child-label").val());
$("#child-info").hide();;
});
});;
var noOfChildren = parseInt($("rect[nodeId=" + parentId + "]").attr('children'));
noOfChildren = noOfChildren + 1;
$("rect[nodeId=" + parentId + "]").attr("children", String(noOfChildren));
nodeNumber++;
}
// function to calculate data for drawing edges , can be ignored
function CalculateEdgeData(nodeId1, nodeId2) {
var node1x = parseInt($("rect[nodeId=" + nodeId1 + "]").attr('x'));
var node1y = parseInt($("rect[nodeId=" + nodeId1 + "]").attr('y'));
var node2x = parseInt($("rect[nodeId=" + nodeId2 + "]").attr('x'));
var node2y = parseInt($("rect[nodeId=" + nodeId2 + "]").attr('y'));
if (node1x < node2x) {
//right
node1x = node1x + 200;
node1y = node1y + 25;
node2y = node2y + 25;
} else {
//left
node1x = node1x;
node1y = node1y + 25;
node2y = node2y + 25;
node2x = node2x + 200;
}
return [{
"x": node1x,
"y": node1y
}, {
"x": node2x,
"y": node2y
}];
}
//function to draw the edge , can be ignored
function CreateEdge(nodeId1, nodeId2, edgeLabel) {
var curveData = CalculateEdgeData(nodeId1, nodeId2);
//diagonal function
var edge = d3.select("svg").append('g');
var diagonal = d3.svg.diagonal()
.source(function(d) {
return {
"x": d[0].y,
"y": d[0].x
};
})
.target(function(d) {
return {
"x": d[1].y,
"y": d[1].x
};
})
.projection(function(d) {
return [d.y, d.x];
});
var curve = edge
.datum(curveData)
.append("path")
.attr("class", "link")
.transition()
.duration("750")
.attr("d", diagonal);
curve
.attr("stroke", "#70dbdb")
.attr("stroke-width", 2)
.attr("fill", "none");
edge.append("text")
.attr("x", parseInt(curveData[0].x) + parseInt(curveData[1].x) / 3)
.attr("y", parseInt(curveData[0].y) + parseInt(curveData[1].y) / 2)
.attr("text-anchor", "middle")
.style("font-size", "18px")
.attr('fill', '#444')
.attr("transform", "translate(-270,-170)")
.text(edgeLabel);
}
&#13;
#child-info {
background: #f1f1f1;
width: 500px;
height: auto;
position: fixed;
padding: 10px;
display: none;
}
#btn-add-child {
background: #444;
color: #fff;
border: none;
z-index: 100;
}
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.4.11/d3.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="child-info">
<input type="text" id="child-text" placeholder="child name">
<input type="text" id="child-label" placeholder="label">
<button id="btn-add-child">add</button>
</div>
<div class="graph-diagram">
</div>
&#13;