Handling mouse events when overlapping SVG layers

I am creating a map visualization using d3.js. I draw filled polygons for both the US states and counties. The SVG level for counties is below the state layer. The states are filled, but the opacity filling is set to 0; padding is necessary (I think) to catch click events.

I want to catch click events at the state level, but I want to catch mouseover events at the county level.

However, the mouseover event is captured by states and not passed to the environment.

Is there a way to pass the event down the layer or else fire the mouseover event in the county?

+8
javascript jquery html5 svg
source share
2 answers

Here's a d3 function that does what you want.

It passes events to lower levels, temporarily disabling pointer events at the upper level and manually triggering a mouse event at the next level.

function passThruEvents(g) { g .on('mousemove.passThru', passThru) .on('mousedown.passThru', passThru) ; function passThru(d) { var e = d3.event; var prev = this.style.pointerEvents; this.style.pointerEvents = 'none'; var el = document.elementFromPoint(d3.event.x, d3.event.y); var e2 = document.createEvent('MouseEvent'); e2.initMouseEvent(e.type,e.bubbles,e.cancelable,e.view, e.detail,e.screenX,e.screenY,e.clientX,e.clientY,e.ctrlKey,e.altKey,e.shiftKey,e.metaKey,e.button,e.relatedTarget); el.dispatchEvent(e2); this.style.pointerEvents = prev; } } 
+6
source share

If you want to do something when you click a state, for example, change the frame style or the opacity of a figure, you can use the fact that each county is state owned and simply groups the counties in states, capturing the 'click' event in the county, select the appropriate state item and change its visual attributes. The layout of this strategy:

 // Setup the visualization, assuming that you have a div with id 'chart' var width = 300, height = 300, div = d3.select('#chart'), svg = div.append('svg') .attr('width', width) .attr('height', height); // Array of states, each one containing one or more counties. In this example, // the states are rectangles, but you get the idea var states = [ { width: 300, height: 300, name: 'Fake State', counties: [ {x: 5, y: 5, width: 95, height: 290, fill: '#b4a0a0'}, {x: 100, y: 5, width: 150, height: 290, fill: '#b4c0a0'}, {x: 250, y: 5, width: 45, height: 290, fill: '#a4a0c0'} ] }]; // Create a group for each state, with class state var gstates = svg.selectAll('g.state') .data(states) .enter() .append('g') .classed('state', true); // Add the state background, in this case, a transparent rectangle gstates .append('rect') .classed('state', true) .attr('width', function(d) { return d.width; }) .attr('height', function(d) { return d.height; }) .attr('fill', '#444') .attr('fill-opacity', 0.0); // For each group, add rectangles for each county, binding them to the // county array of each state. gstates.selectAll('rect.county') .data(function(d) { return d.counties; }) .enter() .append('rect') .classed('county', true) .attr('x', function(d) { return dx; }) .attr('y', function(d) { return dy; }) .attr('width', function(d) { return d.width; }) .attr('height', function(d) { return d.height; }) .attr('fill', function(d) { return d.fill; }) .on('mouseover', function() { d3.select(this).attr('fill-opacity', 0.5); }) .on('mouseout', function() { d3.select(this).attr('fill-opacity', 0.9); }) .on('click', function() { // Retrive the parent group of each county, and then select // the shape corresponding to the state and alter its properties // you can also access the state data var parent = d3.select(d3.select(this).node().parentNode), state = parent.select('rect.state'); // Output 'Fake State' console.log(parent[0][0].__data__.name); state.attr('fill-opacity', 1.0); }); 

There is a working fiddle here: http://jsfiddle.net/pnavarrc/PGTCM/5/ . Yours faithfully,

+2
source share

All Articles