我有一个小程序,它使用RaphaelJS接受一些节点和边缘,就像arborjs和sigmajs一样,来生成树形图。我会使用上述任何一个库,但我正在尝试学习一些JS和图论,我想为什么不自己尝试这样的东西。
节点被迭代并放在纸上,并且给出了一个回调函数,用于悬停并悬停。悬停在悬停时的动画部分可用,但弹出文本显示分配时迭代的最后一个值。
我发现这是因为我需要使用闭包,但是我试图在我找到的几个不同的例子后写一个闭包。
我在JSFiddle上发布了一个示例:link
var jgraph = {
obj_nodes : [],
obj_edges : [],
addNodes : function(obj) {
this.obj_nodes[obj.id] = obj;
},
getNodes : function() {
return this.obj_nodes;
},
addEdges : function(obj) {
this.obj_edges[obj.id] = obj;
},
getEdges : function() {
return this.obj_edges;
},
createGraph : function(paper, obj) {
var point_x, point_y,
source_x, source_y, target_x, target_y, popup;
for (var i = 0; i < obj.nodes.length; i++) {
this.obj_nodes[obj.nodes[i].id] = obj.nodes[i],
point_x = this.obj_nodes[obj.nodes[i].id].x,
point_y = this.obj_nodes[obj.nodes[i].id].y;
popup = jgraph.createPopup(paper, obj.nodes[i].id);
paper.circle(point_x, point_y, 10).attr({
fill : "#e74c3c",
stroke : "none"
}).hover(function() {
this.animate({
fill : "#3498db",
transform : "s1.5"
}, 900, "elastic");
popup.show().toFront();
}, function() {
this.animate({
fill : "#e74c3c",
transform : "s1"
}, 900, "elastic");
popup.hide();
});
}
for (var i = 0; i < obj.edges.length; i++) {
this.obj_edges[obj.edges[i].id] = obj.edges[i];
source_x = this.obj_nodes[obj.edges[i].source].x,
source_y = this.obj_nodes[obj.edges[i].source].y,
target_x = this.obj_nodes[obj.edges[i].target].x,
target_y = this.obj_nodes[obj.edges[i].target].y;
p.path("M " + source_x + " " + source_y + " L " + target_x + " " + target_y).toBack().attr({
stroke : "#e74c3c",
"stroke-width" : 4
});
}
},
createPopup : function(paper, id) {
return paper.text(this.obj_nodes[id].x, this.obj_nodes[id].y - 20, this.obj_nodes[id].label).hide().attr({
"font-size" : "13px"
});
}
};
提前致谢!
答案 0 :(得分:1)
闭包肯定令人抓狂。在这种情况下,问题是您在for循环的上下文中安装悬停处理程序,并且闭包将处理程序对popup
的引用绑定到for循环上下文之外定义的变量。当然,当悬停处理程序触发时,for循环已经完成执行,popup
的值反映了循环处理的最后一个标签。
试试这个 - 你基本上只是在你的for循环中声明一个匿名函数并将popup
的每个值传递给该函数,这使得闭包绑定到该匿名函数的特定调用的值:
popup = jgraph.createPopup(paper, obj.nodes[i].id);
( function( popup )
{
paper.circle(point_x, point_y, 10).attr({
fill : "#e74c3c",
stroke : "none"
}).hover(function() {
this.animate({
fill : "#3498db",
transform : "s1.5"
}, 900, "elastic");
popup.show().toFront();
}, function() {
this.animate({
fill : "#e74c3c",
transform : "s1"
}, 900, "elastic");
popup.hide();
});
} )( popup );
如果我是你,我可能会使用Raphael元素的data方法为每个元素分配标签,然后在每次悬停开始和结束时分别创建和销毁文本元素。这样你就不必担心管理很多不可见的元素了=)
这是你fiddle in working condition的一个分支。