D3 clique et arrête l'événement

Je niche beaucoup d'éléments dans l'élément ag:

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

Cependant, il y a quelques récits que je veux pouvoir organiser des événements de traînée. Le problème est que lorsque vous mettez des éléments dans l'étiquette ag, sa taille se développe pour contenir ces balises. Donc, même si je peux assigner des événements, il n'y a aucun moyen pour lequel ils peuvent être déclenchés car l'événement de la balise g est en quelque sorte plus important même si le rect est sur le dessus.

Existe-t-il une sorte de solution de rechange que vous connaissez?

EDIT: Voici un cas simple complet dans son intégralité. Un rect et un cercle à l'intérieur d'un g. Le g est draggable et le cercle devrait être entraînable aussi, mais ce n'est pas le cas.

 var gDragBehav = d3.behavior.drag() .on('drag', gDragDrag) function gDragDrag(d,i) { dx += d3.event.dx; dy += d3.event.dy; d3.select(this) .attr('x', dx) .attr('y', dy) .attr("transform", "translate(" + dx + "," + dy + ")"); } 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: voici une partie du code

 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) { dx += d3.event.dx; dy += d3.event.dy; d3.select(this) .attr('x', dx) .attr('y', dy) d3.event.stopPropagation(); } var gDragBehav = d3.behavior.drag() .on('dragstart', gDragStart) function gDragDrag(d,i) { dx += d3.event.dx; dy += d3.event.dy; d3.select(this) .attr('x', dx) .attr('y', dy) .attr("transform", "translate(" + dx + "," + dy + ")"); d3.event.stopPropagation(); //Uncaught TypeError: Object #<Object> has no method 'stopPropagation' } 

Un élément SVG <g> n'a pas de taille ou de zone; Il s'agit d'un conteneur transparent pour tous ses descendants et ne peut pas intercepter des événements pour d'autres éléments (sauf si vous ajoutez un auditeur d'événement à déclencher lors de la «phase de capture»).

En tant qu'élément parent, les événements se multiplient; Probablement ce que vous voyez, est-ce que n'importe quel événement que vous utilisez pour déclencher le démarrage par glissement (mousedown?) Sur <rect> est également en plein essor vers <g> et en commençant une traînée simultanée.

Pour résoudre ce problème, vous souhaitez empêcher votre événement de bouillonner. Dans votre gestionnaire d'événement pour le mousedown (ou quoi que ce soit) sur l'ajout <rect> :

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

Sans votre code réel (ou mieux, un étui de test réduit), il est difficile de savoir à coup sûr ou de vous aider davantage.


Modifier Voici une version fonctionnelle de votre exemple simple: http://jsfiddle.net/ZrCQE/2/

Plus précisément, apparemment d3.event n'est pas l'événement lui-même, mais un objet avec une propriété sourceEvent qui fait référence à l'événement réel.

 var dragGroup = d3.behavior.drag() .on('dragstart', function() { console.log('Start Dragging Group'); }).on('drag', function(d, i) { dx += d3.event.dx; dy += 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);​ 

J'ai un problème similaire ( http://jsfiddle.net/j8RZN/1/ ), sauf que la solution de contournement suggérée ne semble pas aider.

 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() {}));