d3 вложенность событий при перетаскивании
Я вложил много элементов в элемент ag следующим образом:
<g>
<rect></rect>
<text></text>
...
</g>
Тем не менее, есть некоторые правила, по которым я хочу иметь возможность перетаскивать свои собственные события. Проблема в том, что когда вы помещаете материал в тег ag, его размер увеличивается, чтобы содержать эти теги. Поэтому, хотя я могу назначать события, их нельзя вызвать, потому что событие тега g как-то важнее, даже если над ним находится прямоугольник.
Есть ли какие-то обходные пути, о которых вы, ребята, знаете?
РЕДАКТИРОВАТЬ: Вот простой полный случай в целом. Прямоугольник и круг внутри 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'
}
2 ответа
SVG <g>
элемент не имеет размера или площади; это прозрачный контейнер для всех его потомков, и он не может перехватывать события для других элементов (если вы не добавляете прослушиватель событий, который будет запускаться во время "фазы захвата").
Как родительский элемент, события всплывают до него; вероятно, вы видите, что какое-либо событие, которое вы используете для запуска начала перетаскивания (mousedown?) на <rect>
также пузырится до <g>
и начало одновременного перетаскивания этого.
Чтобы это исправить, вы хотите, чтобы ваше событие не пузырилось. В вашем обработчике событий для mousedown (или что-то еще) на <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);
У меня похожая проблема ( 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() {}));