Closures can certainly be maddening. In this case, the problem is that you're installing your hover handlers in the context of the for loop, and the closure ties the handler's reference to popup
to the variable defined outside of the context of the for loop. Naturally, by the time the hover handlers fire, the for loop has finished executing and the value of popup
reflects the last label the loop handled.
Try this instead -- you're basically just declaring an anonymous function inside your for loop and passing each value of popup
into that function, which makes the closure bind to the values of specific calls to that anonymous function:
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 );
If I were you, I would probably assign the label to each element using Raphael elements' data method, and then create and destroy the text elements each time a hover is started and ended respectively. That way you don't need to worry about managing many invisible elements at all =)
Here's a fork of your fiddle in working condition.