2012-04-10 12 views
5

sto nidificazione un sacco di elementi all'interno di un elemento g in questo modo:d3 clic e evento di trascinamento nidificazione

<g> 
    <rect></rect> 
    <text></text> 
    ... 
</g> 

Tuttavia, ci sono alcuni rettangoli che voglio essere in grado di avere eventi di trascinamento di loro. Il problema è che quando metti cose all'interno di un tag g, la sua dimensione si espande per contenere quei tag. Quindi, anche se posso assegnare eventi, non è possibile che possano essere attivati ​​perché l'evento del tag g è in qualche modo più importante anche se il rect è in cima.

Esiste una soluzione alternativa di cui voi ragazzi siete a conoscenza?

MODIFICA: qui è a simple complete case nella sua interezza. Un retto e un cerchio all'interno di un g. La g è trascinabile e anche il cerchio dovrebbe essere trascinabile, ma non lo è.

var gDragBehav = d3.behavior.drag() 
    .on('drag', gDragDrag) 

function gDragDrag(d,i) { 
    d.x += d3.event.dx; 
    d.y += d3.event.dy; 
    d3.select(this) 
     .attr('x', d.x) 
     .attr('y', d.y) 
     .attr("transform", "translate(" + d.x + "," + d.y + ")"); 
} 

var circleDragBehav = d3.behavior.drag() 
    .on('drag', circleDragDrag); 

function circleDragDrag(d,i) { 
    console.log('dragging a circle') 
    d.cx += d3.event.dx; 
    d.cy += d3.event.dy; 
    d3.select(this) 
     .attr('cx', d.cx) 
     .attr('cy', d.cy) 
} 

var svg = d3.select('body').append('svg') 

var g = svg.selectAll('g').data([{x: 10, y:10}]) 
    .enter().append('g').call(gDragBehav) 

g.append('rect').attr('width', 100).attr('height', 100) 

g.selectAll('circle').data([{cx: 0, cy:0}]) 
    .enter().append('circle') 
    .attr('cx', function(d) { return d.cx }).attr('cy', function(d) { return d.cy }) 
    .attr('r', 40) 
    .call(circleDragBehav) 

EDIT: Ecco una parte del codice

var group = this.d3svg.selectAll('g' + '.' + this.className) 
    .attr('x', this.drawFuncs['x']) 
    .attr('y', this.drawFuncs['y']) 
    .attr("transform", this.drawFuncs['translate']) 
    .attr('class', this.className) 
    .call(gDragBehav) 
    .on('click', blockClickMenu) 

ports = ['AtomicPort'] 
for (port in ports) { 
    drawPort.call(this, group, ports[port]) 
} 

function drawPort(d3svg, portName, redraw) { 
    d3svg.selectAll('rect.' + portName) 
    .data(function(d) { return d.ports[ portName ] }) 
    .enter().append('rect') 
    .attr('x', this.drawFuncs['x']) 
    .attr('y', this.drawFuncs['y']) 
    .attr('width', this.drawFuncs['width']) 
    .attr('height', this.drawFuncs['height']) 
    .attr('class', portName) 
    .call(portDragBehav) 

    var portDragBehav = d3.behavior.drag() 
    .on('drag', portDragDrag); 

    function portDragDrag(d,i) { 
    d.x += d3.event.dx; 
    d.y += d3.event.dy; 
    d3.select(this) 
     .attr('x', d.x) 
     .attr('y', d.y) 
    d3.event.stopPropagation(); 
    } 

    var gDragBehav = d3.behavior.drag() 
    .on('dragstart', gDragStart) 

    function gDragDrag(d,i) { 
    d.x += d3.event.dx; 
    d.y += d3.event.dy; 
    d3.select(this) 
     .attr('x', d.x) 
     .attr('y', d.y) 
     .attr("transform", "translate(" + d.x + "," + d.y + ")"); 
    d3.event.stopPropagation(); //Uncaught TypeError: Object #<Object> has no method 'stopPropagation' 
    } 

risposta

14

Uno SVG <g> elemento non ha una dimensione o area; è un contenitore trasparente per tutti i suoi discendenti e non può intercettare eventi per altri elementi (a meno che non si aggiunga un listener di eventi da attivare durante la 'fase di acquisizione').

In qualità di elemento padre, gli eventi diventano bolla; probabilmente quello che stai vedendo è che qualunque evento tu stia usando per innescare il trascinamento (mousedown?) su <rect> fa anche ribollire fino allo <g> e iniziare una resistenza simultanea di che.

Per risolvere questo problema, si desidera interrompere il vostro evento da bolle. Nel vostro gestore di eventi per l'mousedown (o altro) sul <rect> aggiuntivo:

function startDrag(evt){ 
    // whatever your code is here 
    evt.stopPropagation(); 
} 

Senza il vostro codice vero e proprio (o, meglio, un banco di prova Pared-down) è difficile sapere con certezza, o aiutare ulteriormente .


Modifica Ecco una versione funzionante del semplice esempio: http://jsfiddle.net/ZrCQE/2/

In particolare, a quanto pare d3.event non è l'evento in sé, ma un oggetto con una proprietà che fa riferimento sourceEvent l'evento reale.

var dragGroup = d3.behavior.drag() 
    .on('dragstart', function() { 
    console.log('Start Dragging Group'); 
    }).on('drag', function(d, i) { 
    d.x += d3.event.dx; 
    d.y += d3.event.dy; 
    d3.select(this).attr("transform", "translate("+d.x+","+d.y+")"); 
    }); 

var dragCircle = d3.behavior.drag() 
    .on('dragstart', function(){ 
    d3.event.sourceEvent.stopPropagation(); 
    console.log('Start Dragging Circle'); 
    }) 
    .on('drag', function(d,i){ 
    d.cx += d3.event.dx; 
    d.cy += d3.event.dy; 
    d3.select(this).attr('cx', d.cx).attr('cy', d.cy) 
    }); 

var svg = d3.select('body').append('svg').attr('viewBox','-50 -50 300 300'); 

var g = svg.selectAll('g').data([{x:10,y:10}]) 
    .enter().append('g').call(dragGroup); 

g.append('rect').attr('width', 100).attr('height', 100); 

g.selectAll('circle').data([{cx: 90,cy:80}]) 
    .enter().append('circle') 
    .attr('cx', function(d){ return d.cx }) 
    .attr('cy', function(d){ return d.cy }) 
    .attr('r', 30) 
    .call(dragCircle);​ 
+0

Allego il comportamento di trascinamento all'elemento g stesso, in modo che tutto il corpo della g si muova. Il problema è che gli elementi all'interno del tag g non venivano affatto chiamati. Non sono sicuro di quale sia il problema, ma non ho un handle sull'evento. Come posso chiamare stopPropagation? – ballaw

+0

@ballaw Questa è una buona informazione (ma attesa). Non cambia la mia risposta. – Phrogz

+0

OK, ma non ho un handle sull'evento. Come posso chiamare stopPropagation? – ballaw

0

Ho un simile tipo di problema (http://jsfiddle.net/j8RZN/1/), ad eccezione della soluzione suggerita non sembra essere aiutare.

userBox.data([userBox]).call(d3.behavior.drag() //makes the box to move 
//titleBox.data([userBox]).call(d3.behavior.drag() //does not make the box move 
.on("dragstart", function() {}) 
.on("drag", function(d, i) { 
console.log('box being dragged'); 
d.attr("transform", "translate(" + (d3.event.x) + "," + (d3.event.y) + ")"); 
}) 
.on("dragend", function() {})); 

circleDrag.call(d3.behavior.drag() 
.on("dragstart", function() {}) 
.on("drag", function(d, i) { 
d3.event.sourceEvent.stopPropagation(); 
console.log('small rectangle being dragged'); 
}) 
.on("dragend", function() {})); 
+1

d3.event.sourceEvent.stopPropagation(); deve andare su "dragStart" e non "trascinare" – Andy

Problemi correlati