javascript d3 单击并拖动事件嵌套
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10095979/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
d3 click and drag event nesting
提问by ballaw
I am nesting a lot of elements inside of a g element like so:
我在 ag 元素中嵌套了很多元素,如下所示:
<g>
<rect></rect>
<text></text>
...
</g>
However, there are some rects that I want to be able to have drag events of their own. The problem is that when you put stuff inside of a g tag, its size expands to contain those tags. So even though I can assign events there is no way they can be triggered because the g tag's event is somehow more important even though the rect is on top of it.
但是,有一些 rect 我希望能够拥有自己的拖动事件。问题在于,当您将东西放入 ag 标签时,其大小会扩展以包含这些标签。所以即使我可以分配事件,也无法触发它们,因为 g 标签的事件在某种程度上更重要,即使 rect 在它上面。
Is there some sort of workaround that you guys know of?
有没有你们知道的解决方法?
EDIT: Here's a simple complete casein its entirety. A rect and a circle inside a g. The g is draggable and the circle should be draggable too but is not.
编辑:这是一个简单的完整案例。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 )
EDIT: Here's some of the 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) {
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'
}
回答by Phrogz
An SVG <g>
element does not have a size or area; it is a transparent container for all its descendants, and cannot intercept events for other elements (unless you are adding an event listener to be triggered during the 'capture phase').
SVG<g>
元素没有大小或面积;它是其所有后代的透明容器,不能拦截其他元素的事件(除非您添加要在“捕获阶段”期间触发的事件侦听器)。
As a parent element, events bubble up to it; likely what you are seeing is that whatever event you're using to trigger the drag start (mousedown?) on the <rect>
is also bubbling up to the <g>
and starting a concurrent drag of that.
作为父元素,事件冒泡到它;可能你看到的是,不管事件你使用触发拖拽开始上(鼠标按下?)<rect>
也冒泡的<g>
和启动的同时拖动那个。
To fix this, you want to stop your event from bubbling. In your event handler for the mousedown (or whatever) on the <rect>
add:
要解决此问题,您需要阻止事件冒泡。在您的 mousedown(或其他)事件处理程序中<rect>
添加:
function startDrag(evt){
// whatever your code is here
evt.stopPropagation();
}
Without your actual code (or better, a pared-down test case) it's hard to know for sure, or help you further.
如果没有您的实际代码(或者更好的精简测试用例),就很难确定或进一步帮助您。
EditHere's a working version of your simple example: http://jsfiddle.net/ZrCQE/2/
编辑这是您的简单示例的工作版本:http: //jsfiddle.net/ZrCQE/2/
Specifically, apparently d3.event
is not the event itself, but an object with a sourceEvent
property that references the actual event.
具体来说,显然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);?
回答by Andy
I have a similar sort of issue (http://jsfiddle.net/j8RZN/1/), except the suggested workaround does not seem to be helping.
我有类似的问题(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() {}));