8

I was looking at the NYTimes interactive on state subsidies this morning and noticed that even when a state is obscured by a dot it is brought forward on hover.

For example the dot covering Massachusetts also partially covers New Hampshire, yet when you when you mouse into the covered part of New Hampshire, New Hampshire is brought forward.

How do you suppose they achieve this? The dots are in front of the state outlines based on their order in the DOM. I thought there might be a second set of state outlines on top of everything, listening for mouseovers that would trigger the underlying shape, but that doesn't seem to be the case.

I need to implement similar functionality in an application I'm working on and am curious about an elegant way with SVG elements.

Thanks.

seliopou
  • 2,896
  • 20
  • 19
Al R.
  • 2,430
  • 4
  • 28
  • 40
  • 3
    This isn't as complicated as it may seem, just give your dots a css property of `pointer-events: none;`. This will stop the mouse knowing they exist, so you can hover over what is behind them – Andy Dec 04 '12 at 15:10
  • Yes. Only thing is that IE doesn't support this css prop. Even IE9. http://stackoverflow.com/questions/5855135/css-pointer-events-property-alternative-for-ie – meetamit Dec 04 '12 at 18:40
  • @meetamit: `pointer-events: none` is supported on SVG elements in IE9. – methodofaction Dec 04 '12 at 21:30

2 Answers2

4

As noted by Andy the circles in that NYT graphic have a CSS pointer-events property of none:

circle {
    pointer-events: none;
}

the bring to front behavior can be achieved in a the mouseover function using this method:

stateShape.on("mouseover",function(){this.parentNode.appendChild(this);})
Community
  • 1
  • 1
Yanofsky
  • 1,806
  • 1
  • 17
  • 15
  • While this works, it's a bit clunky because if your country map is not coming from a background image (like in OP's link), but is the `svg` you're trying to "change", it will show a few frames with the element not being in the front, before putting it to the front. Apparently `JS` needs time to process. It would be great to see an "instant" solution. – Artur Müller Romanov May 16 '22 at 05:39
1

Now you can just use the raise() method:

Example in a function:

highlightSite(site) {
        let selectedSite = d3.selectAll(`[siteName=${site}]`)
        selectedSite.raise()
        selectedSite
            .attr('stroke', 'black')
            .style('opacity', 1)
    }
Jared Wilber
  • 6,038
  • 1
  • 32
  • 35