2012-04-10 15 views
5

ja gniazdowania wiele elementów wewnątrz elementu g tak:d3 kliknij i wydarzenie przeciągnij gniazdowania

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

Jednak istnieją pewne rects że chcą mieć możliwość zdarzenia przeciągnij własnych. Problem polega na tym, że kiedy umieszczasz materiał wewnątrz tagu g, jego rozmiar rozszerza się, by zawierał te tagi. Mimo, że mogę przypisać zdarzenia, nie ma możliwości ich uruchomienia, ponieważ wydarzenie z tagiem g jest jakoś ważniejsze, nawet jeśli rect jest na nim.

Czy istnieje sposób obejścia tego problemu?

EDYCJA: Oto a simple complete case w całości. Prostokąt i okrąg wewnątrz g. G jest przeciągalne, a kółko powinno być przeciągane, ale nie jest.

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: Oto niektóre z kodu

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' 
    } 

Odpowiedz

14

SVG <g> element nie mają rozmiar lub strefy; jest przezroczystym kontenerem dla wszystkich jego potomków i nie może przechwytywać zdarzeń dla innych elementów (chyba że dodajesz detektor zdarzeń, który ma być wyzwalany podczas "fazy przechwytywania").

Jako element nadrzędny, zdarzenia bańki do niego; Prawdopodobnie to, co widzisz, jest takie, że jakiekolwiek zdarzenie, którego używasz do wywoływania początku przeciągania (mousedown?) na <rect>, również przepełnia się do <g> i rozpoczyna równoczesne przeciągnięcie , które to jest.

Aby to naprawić, nie chcesz, aby wydarzenie było przepuszczane. W swojej obsługi zdarzeń dla mousedown (lub cokolwiek) na <rect> dodają:

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

Bez rzeczywistego kodu (albo lepiej, test case porównaniu do dołu) to trudno wiedzieć na pewno, czy pomóc dalej .


Edit Oto wersja robocza swoim prostym przykładzie: http://jsfiddle.net/ZrCQE/2/

Konkretnie, najwyraźniej d3.event nie jest samo wydarzenie, ale obiekt z właściwością sourceEvent która odwołuje się do konkretnego wydarzenia.

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

Przywiązuję zachowanie drag do samego elementu g, aby wszystko w ciele g mogło się poruszać. Problem polega na tym, że elementy wewnątrz znacznika g nie były w ogóle wywoływane. Nie jestem pewien, co to za problem, ale nie mam do czynienia z wydarzeniem. Jak mogę nazwać stopPropagation? – ballaw

+0

@ballaw To dobra (ale oczekiwana) informacja. To nie zmienia mojej odpowiedzi. – Phrogz

+0

OK, ale nie mam żadnego kontaktu z wydarzeniem. Jak mogę nazwać stopPropagation? – ballaw

0

Mam podobny rodzaj emisji (http://jsfiddle.net/j8RZN/1/), z wyjątkiem sugerowane obejście nie wydaje się pomagać.

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(); musi iść dalej "dragStart", a nie "przeciągnij" – Andy

Powiązane problemy