2013-05-28 73 views
8

我正在用d3.js構建地圖可視化。我正在爲美國各州和各州繪製填充多邊形。縣的SVG層在狀態層之下。狀態已填充,但填充不透明度設置爲0;填充是必需的(我認爲)捕捉點擊事件。在重疊SVG圖層中處理鼠標事件

我想捕捉州級別的點擊事件,但我想在縣級捕捉鼠標懸停事件。

但是,mouseover事件是由狀態捕獲的,並沒有傳遞給縣。

是否有任何方法將事件向下傳遞給層或以其他方式觸發縣上的鼠標懸停事件?

+0

你有鏈接到你正在使用的例子嗎? –

回答

2

如果您想單擊某個狀態時想要做某些事情,例如更改邊框樣式或形狀的不透明度,則可以使用這樣一個事實,即每個縣屬於一個州,並將各州按州分組,縣裏的'點擊'事件,選擇相應的狀態元素並改變其視覺屬性。這一戰略的樣機:

// 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