2

I'm developing some svg animations, and I need to detect mouseover/mouseout events in order to change elements' z-index (i.e. elements' order inside svg). My code works perfectly with Chrome and Firefox, but I ha ve some issues with IE11. In particular, it seems that, hovering on an element, IE11 detects several mouseover events, and not detecting the following mouseout event.

You can find a dummy example of the issue in https://jsfiddle.net/erdmca23/4/

(function() {
  'use strict';

  var data = d3.range(0, 40); // [0, 1, 2, 3, 4 etc]
  console.log('number of items in array: ' + data.length);
  var overcounter = 1;
  var outcounter = 1;

  d3.selection.prototype.moveToFront = function() {
    return this.each(function() {
      d3.select('#log').append('div').text('Over counter ' + overcounter++);
      this.parentNode.appendChild(this);
    });
  };

  d3.selection.prototype.moveToBack = function() {
    return this.each(function() {
      d3.select('#log').append('div').text('Out counter ' + outcounter++);

      var firstChild = this.parentNode.firstChild;
      if (firstChild) {
        this.parentNode.insertBefore(this, firstChild);
      }
    });
  };

  var colour = d3.scale.category10();

  // vars
  var rectWidth = 100;
  var rectHeight = 300;

  var svg = d3.select('#container').append('svg');
  // set width & height in css

  svg.selectAll('rect')
    .data(data)
    .enter()
    .append('rect')
    .attr({
      width: rectWidth,
      height: rectHeight,
      x: function(d, i) {
        // overlap the rects intentionally
        return (rectWidth - 40) * i;
      },
      y: 10
    })
    .style({
      fill: function(d, i) {
        return colour(i);
      },
      stroke: 'none'
    })
    .on('mouseover', function(d) {
      d3.select(this).moveToFront();
    })
    .on('mouseout', function(d) {
      d3.select(this).moveToBack();
    })
})();

Any idea how to fix this?

Thanks

Steven Kalt
  • 1,116
  • 15
  • 25

2 Answers2

1

Apparently when you are using d3.selection, it loses mouse events. See this post - Move active element loses mouseout event in internet explorer

I had to rearrange the way I was appending elements in d3 to accommodate.

Community
  • 1
  • 1
Kate O
  • 11
  • 1
1

My solution is to re-bind the mouseout handler to the element once it has been re-appended:

...
  .on('mouseover', function(d) {
    d3.select(this)
      .moveToFront()
      .on('mouseout', function(d) { // only bind the mouseout handler here
        d3.select(this).moveToBack();
      })
    })
... 

Full jsfiddle here. Note that to test it you're going to need to go to jsfiddle.net/fiddle/show, since JSfiddle won't load on IE.

The culprit is this.parentNode.appendChild(this), as stated by Kate O's linked answer. Re-appending the element breaks IE's association between the re-appended element and state of whether the mouse has entered that element. Re-binding the callback simulates that enter-exit state.

for d3 v4+ users, this problem applies to d3.selection.raise() or .lower(), both of which re-insert the selected element into the DOM.

Steven Kalt
  • 1,116
  • 15
  • 25