2013-05-28 5 views
8

Я строю визуализацию карты с помощью d3.js. Я рисую заполненные полигоны как для штатов США, так и для округов. Уровень SVG для округов находится под слоем для состояний. Состояния заполнены, но заполнение непрозрачности установлено равным 0; заполнение требуется (я думаю), чтобы поймать события щелчка.Обработка событий мыши при перекрытии слоев SVG

Я хочу поймать события кликов на уровне штата, но хочу поймать события mouseover на уровне графства.

Однако событие mouseover захватывается состояниями и не проходит в округах.

Есть ли способ передать событие вниз по слою или иначе вызвать событие mouseover в графстве?

+0

У вас есть ссылка на пример, который вы используете? –

ответ

2

Если вы хотите что-то сделать, когда вы нажимаете состояние, например изменение стиля рамки или непрозрачность фигуры, вы можете использовать тот факт, что каждое графство принадлежит государству и просто группирует графства в состояниях, захватывая событие 'click' в графстве, выберите соответствующий элемент состояния и измените его визуальные атрибуты. Макет этой стратегии:

// 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 d.x; }) 
     .attr('y', function(d) { return d.y; }) 
     .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); 
     }); 

Существует рабочая скрипку здесь: http://jsfiddle.net/pnavarrc/PGTCM/5/. С уважением,

6

Вот функция d3, которая делает то, что вы хотите.

Он передает события на более низкие уровни, временно отключая события указателя на верхнем уровне и вручную вызывая событие мыши на следующем уровне.

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; 
    } 
} 
+0

удивительное решение! – rockTheWorld

+1

Это решение является удивительным и легко адаптируется к другим обстоятельствам, однако элементы, «затененные» самым верхним элементом, не будут иметь стиль с помощью ': hover', я бы тоже хотел это исправить. – luismreis