2014-04-08 17 views
38

Ho un istogramma D3, su cui ho allegato un 'onclick' evento alle barre:Collegamento 'onclick' evento a D3 sfondo grafico

... 
var bar = svg.selectAll(".bar") 
     .data(data) 
     .enter().append("g") 
     .attr("class", "bar") 
     .attr("transform", function(d) { return "translate(" + x(d.x) + "," + y(d.y) + ")"; }) 
     .on('mouseover', tip.show) 
     .on('mouseout', tip.hide) 
     .on('click', function(d,i){ //do stuff }); 
... 

Questo funziona esattamente come previsto. Vorrei anche allegare un evento 'onclick' allo sfondo del grafico (cioè ovunque nel grafico che non è una barra), ma ho problemi con questo. Ho provato allegando l'evento in un paio di modi, ma in ogni caso, questo nuovo evento sembra ignorare il mio bar-click:

Alcuni tentativi:

$("svg:not('.bar')").on("click", function(){ //do stuff }); 

$("g:not('.bar')").on("click", function(){ //do stuff }); 

var svg = d3.select("#histogram_block").append("svg") 
     .attr("width", width + margin.left + margin.right) 
     .attr("height", height + margin.top + margin.bottom) 
     .append("g") 
     .attr("transform", "translate(" + margin.left + "," + margin.top + ")") 
     .on("click", function(d,i){ 
      if (d) { //do stuff} 
      else { //do stuff } 
     }; 

Io parto dal presupposto che c'è un modo per aggiungere il gestore di eventi all'oggetto SVG quando viene inizializzato, ma non conosco il modo corretto per farlo.

+2

Solo un promemoria. '$ (" svg: not ('. bar') ")" significa ottenere tutti i 'svg's che non hanno la classe' bar'. Non significa ottenere la sezione 'svg's al di fuori degli elementi con la classe' bar'. –

risposta

46

L'evento non è in realtà sovrascritto, ma entrambi sono attivati: il gestore onclick per SVG e per la barra. Per evitare ciò, utilizzare il metodo .stopPropagation() (vedere the documentation). Il codice è simile al seguente:

rect.on("click", function() { 
    console.log("rect"); 
    d3.event.stopPropagation(); 
}); 

Complete esempio here. Confrontate con il comportamento con l'interruzione della propagazione dell'evento here.

+0

Grande esempio, grazie. Dovresti aggiungerlo alla risposta poiché è troppo breve. Quindi cosa determina l'ordine degli eventi quando clicco? L'ipotesi qui sembra essere che l'evento click del rettangolo si attiva per primo, ma sarà sempre così? – woemler

+0

Gli eventi "gonfiano" il DOM. Il 'rect' è un figlio di' svg', quindi propaga l'evento a 'svg'. Questo è il motivo per cui '.stopPropagation()' funziona. Quindi sì, il gestore di clic di 'rect's dovrebbe sempre sparare per primo. –

+0

Grazie, ma cosa succederebbe se ci fossero elementi grafici sovrapposti, entrambi figli di SVG? Quale dovrebbe innescare prima il loro evento click? – woemler

2

In questo esempio (riga 246: http://tributary.io/inlet/8361294) Appendo un nuovo retto con larghezza & all'altezza dell'area del grafico totale, quindi allega gli eventi del mouse (o clic).

svg.append("rect") 
     .attr({"class": "overlay" , "width": width , "height": height}) 
     .on({ 
      "mouseover": function() { /* do stuff */ }, 
      "mouseout": function() { /* do stuff */ }, 
      "click": function() { /* do stuff */ }, 
     }); 
+0

Questo non sembra rispondere alla domanda, poiché questo non fa clic sullo sfondo del grafico rispetto all'elemento in primo piano. – rjurney