2012-04-10 83 views
5

我嵌套了很多元素的g組件的內部,像這樣:D3單擊並拖動事件築巢

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

不過,也有一些rects,我希望能夠擁有自己的拖動事件。問題是,當你把東西放在一個g標籤中時,它的大小會擴大以包含這些標籤。所以,儘管我可以分配事件,但它們不能被觸發,因爲g標籤的事件在某種程度上更重要,即使它是最重要的事件。

是否有某種解決方法,你們知道嗎?

編輯:這是a simple complete case的全部內容。 g中的矩形和圓形。 g是可拖動的,圓也應該可拖動,但不是。

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) 

編輯:這裏的一些代碼

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

回答

14

的SVG <g>元件不具有尺寸或面積的;它是所有後代的透明容器,並且不能攔截其他元素的事件(除非添加要在「捕獲階段」觸發的事件偵聽器)。

作爲父元素,事件冒泡到它;很可能你看到的是,無論你用什麼事件來觸發<rect>上的拖拽開始(mousedown?),也會冒泡到<g>,並開始併發拖動

要解決這個問題,你想停止冒泡事件。在對<rect>添加鼠標按下(或其他)事件處理程序:

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

沒有你的實際代碼(或更好,削減的測試用例),很難確切知道,或進一步幫助您。


編輯這是你簡單的例子,一個工作版本:http://jsfiddle.net/ZrCQE/2/

具體來說,顯然d3.event不是事件本身,而是用sourceEvent屬性,引用實際事件的對象。

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

我將拖動行爲附加到g元素本身,以便g的所有內容都會移動。問題在於g標籤內部的元素根本沒有被調用。 我不確定你是什麼問題,但我沒有處理事件。我怎樣才能打電話給stopPropagation? – ballaw 2012-04-11 19:34:53

+0

@ballaw這是很好的(但預期)信息。它不會改變我的答案。 – Phrogz 2012-04-11 19:35:22

+0

好的,但我對這個事件沒有把握。我怎樣才能打電話給stopPropagation? – ballaw 2012-04-11 19:37:40

0

我也有類似問題的排序(http://jsfiddle.net/j8RZN/1/),除了建議的解決辦法似乎並不被幫助。

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();需要繼續'dragStart'而不是'拖動' – Andy 2013-08-07 05:49:39