D3.js - why mouseover and mouse out fired for each

2020-06-01 08:45发布

问题:

I use d3.js to generate a svg circle with a text logo in mid of the circle. Here is the svg result.

<g id="main">
  <circle r="114" fill="#F0E8D0"></circle>
  <text text-anchor="middle">The movie title</text>
</g>

Here is the d3.js

var circles = [{r: innerRadius}];
svg.append("g").attr("id","main");


svg.select("#main").selectAll("circle")
.data(circles).enter()
.append("circle")
.attr("r",function(d){return d.r})
.attr("fill","#F0E8D0");

svg.select("#main").append("text")
.attr("text-anchor", "middle")
.text(function(){ return "The movie title";});

I also want to fire some animations when mouse hover and leave the circle.

svg.select("#main")
.on("mouseover",function(){
  //code for transition
}).on("mouseout",function(){
  //code for transition
})

So the problem is: When mouse moves into the circle, the animation fires as expected, however, when mouse touches the text element, a mouseout event fires (mouse leaving the circle), followed by a mouseover event again (mouse entering the text element), which is not desirable.

It seems that the animation callbacks will be called when mouse touches any child element of the "< g >" tag.

I do not want any animation happen when mouse touches the text element. How can I do it?

回答1:

You can prevent the text element receiving mouse events (and thus a mouseout event triggering when you move the mouse over it) by setting pointer-events to none:

svg.select("#main").append("text")
   .attr("text-anchor", "middle")
   .attr("pointer-events", "none")
   .text(function(){ return "The movie title";});

You probably also want to set the events on the circle and not on the g element:

svg.select("#main").selectAll("circle")
   .data(circles).enter()
   .append("circle")
   .attr("r",function(d){return d.r})
   .attr("fill","#F0E8D0")
   .on("mouseover",function(){
     //code for transition
   })
   .on("mouseout",function(){
     //code for transition
   })


回答2:

An alternate solution is to use mouseenter and mouseleave instead of mouseover and mouseout.

mouseenter is similar to mouseover except that it is not triggered when the pointer (mouse) is moved from one of listener's (circle in this case) descendants' physical space (text in this case) to its own physical space.

Same reasoning for 'mouseleave'

Source: https://developer.mozilla.org/en-US/docs/Web/Events/mouseenter and https://developer.mozilla.org/en-US/docs/Web/Events/mouseleave