2013-02-04 25 views
10

Ho un grafico a dispersione che viene generato utilizzando D3. I punti (cerchi SVG) del grafico possono essere selezionati facendo clic su di essi e le regioni possono essere selezionate utilizzando un pennello D3.Gestione degli eventi a grana fine con le spazzole D3

Per garantire che le cerchie ottengano l'evento click, è necessario prima creare il pennello in modo che i cerchi si trovino sopra di esso. Sfortunatamente questo significa che non posso trascinare per creare l'estensione del pennello quando il mio cursore si trova su un punto della trama.

C'è un modo per passare il passaggio del mouse e fare clic sugli eventi per le cerchie, ma gestire gli eventi relativi al trascinamento con il pennello?

risposta

13

Può essere realizzato, ma con use of the D3 brush API (vedi nota sotto).

Questo è un esempio http://bl.ocks.org/4747894 dove:

  1. L'elemento brush è dietro circoli
  2. I cerchi rispondere all'evento mousedown. (Può rispondere anche ad altri eventi.)
  3. L'elemento brush si comporta bene anche se il trascinamento inizia da uno dei cerchi.

Alcuni rintracciamento e uno sguardo al D3 source code suggerisce che il extent non è in corso il ripristino correttamente quando un evento mousemove viene sparato da un elemento circle in cima alla spazzola. Che può essere risolto resettando il extent per il pennello nella mousedown listener per gli circle elementi:

 circles.on("mousedown", function (d, i) { 
      // _svg_ is the node on which the brush has been created 
      // x is the x-scale, y is the y-scale 
      var xy = d3.mouse(svg.node()), 
       xInv = x.invert(xy[0]), 
       yInv = y.invert(xy[1]); 

      // Reset brush's extent 
      brush.extent([[xInv, yInv], [xInv, yInv]]); 

      // Do other stuff which we wanted to do in this listener 
     }); 

Nota:As per the API, la selezione del pennello non verrà aggiornata automaticamente a chiamare .extent(values). Semplicemente facendo clic su una cerchia, si ripristinerà lo extent ma non si ridisegnerà la selezione effettuata. La selezione verrà scartata solo quando viene avviata una selezione diversa all'interno di circle o facendo clic all'esterno delle cerchie e della selezione corrente. Questo è il comportamento desiderato, come ho capito dalla domanda. Tuttavia, questo potrebbe infrangere il codice che è stato scritto supponendo che qualunque sia lo extent del pennello sarebbe la selezione visibile sul grafico.

+0

Questo è molto vicino. Idealmente, mi piacerebbe essere in grado di trascinare il pennello dopo che è stato creato, anche se inizio su un cerchio, ma è un enorme passo avanti su come funziona ora! – RichH

+0

Infatti, vedo che il trascinamento di una selezione dall'interno di un '' non è ancora possibile. Penserò a come farlo in modo pulito, anche se sospetto che il passaggio di un evento pulito implichi una patch per d3. –

5

Uso selection.on: http://jsfiddle.net/NH6zD/1

var target, 
    dimensions = {width: 200, height: 200}, 
    svg = d3.select("body").append("svg").attr(dimensions), 
    rect = svg.append("rect").attr(dimensions); // Must be beneath circles 
svg 
    .on("mousedown", function() { 
     target = d3.event.target || d3.event.srcElement; 
     if (target === rect.node()) { 
      /* Brush */ 
     } else { 
      /* Circle */ 
     } 
    }) 
    .on("mousemove", function() { 
     if (!target) return; 
     if (target === svg.rect()) { 
      /* Brush */ 
     } else { 
      var mouse = d3.mouse(svg.node()); 
      target.attr({x: mouse[0], y: mouse[1]}); 
     } 
    }); 
(function(exit) { 
    for (var i in exit) svg.on(exit[i], function() { target = undefined; }); 
})(["mouseout", "mouseup"]); 
Problemi correlati