Question

I'm working on a proof of concept that depicts some circles inside an svg element that move and change colour when i click on the svg element. That all works fine. I also wanted to add a mouseover event which changed the colour of the circle to red for example. That worked too.

However, when i updated the position/colour of the circles (those were random-generated values) the mouseover event had disappeared. I figured it was because d3 replaced the old circles with new ones and i didn't define my mouseover eventlistener in the update function, so i just copied it from the 'initialize' code. But then something weird happened. I got an 'Uncaught TypeError: undefined is not a function' in the console, and the eventlistener didn't work. This is the code:

svg2.on("click", function(){
svg2["color"] = d3.rgb(Math.random()*256,Math.random()*256,Math.random()*256);

var circles = svg2.selectAll("circle");
console.log(circles);
circles.transition()
.duration(500)
.ease("circle")
.style("fill",svg2["color"])
.attr("cx",function(d,i){
  var val = (Math.random()<0.5)?-Math.random()*50:Math.random()*50;
  if(val+d[0]-d[2] >w2 || val+d[0]-d[2]<0) return d[0];
  else return d[0]+val;
})
.attr("cy",function(d,i){
  var val = (Math.random()<0.5)?-Math.random()*50:Math.random()*50;
  if(val+d[1]+d[2] > h2 || val+d[1]-d[2]< 0) return d[1];
  else return d[1]+val;
})
.attr("r",function(d){
return d[2];
})
///////// ERROR CAUSED BELOW //////////////
.on("mouseover",function(){
 d3.select(this).style("fill",svg2.color);   
 });
});

I did nothing wrong i thought, because i did exactly as i did before: i selected all my circles, set their attributes and defined an eventlistener with .on(), but it didn't work.

I was able to solve this by defining a function that does exactly as above and call it at the end of my 'update' code. This is the function:

function updateListeners(circles){
    circles.on("mouseover",function(){
         d3.select(this).style("fill","red");   
    })
    .on("mouseout",function(){
         d3.select(this).style("fill",svg2.color);   
    })
}

So it seems i can update eventlisteners of an object in a called function, but not in the callback function provided with the 'click' event?

Question: Why is that exactly? It's the exact same selection, but why does the 'hard' way work, and the 'easy' way doesn't?

Was it helpful?

Solution

You are adding the event listener after the .transition() in the first case. In the 'hard' case you are assigning the event listener to the selection without a transition. I don't think it works to transition into an event listener.

Try registering the event listener before the call to .transition() and see if that works for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top