JS通过迭代分配回调

时间:2014-02-13 18:43:57

标签: javascript raphael

我有一个小程序,它使用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"
    });
}
};

提前致谢!

1 个答案:

答案 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的一个分支。