Je ne parviens pas à faire la distinction entre l'événement click
et l'événement drag
sur un élément lié à l'utilisation de D3.js v3. Le cercle dans le code ci-dessous se voit attribuer un comportement de glisser et un écouteur click
. Démo ici
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();
d3.event.sourceEvent.preventDefault();
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)
.on('click', function () {
console.log('clicked circle');
});
Chaque fois que je clique sur le cercle de l'exemple, la console enregistre l'événement drag
ainsi que l'événement click
. J'obtiens également le même comportement lors du glissement. D'abord, l'événement drag
est enregistré et, le mouseup
, l'événement click
est enregistré.
Quelle est la bonne façon de gérer ces événements séparément?
Le cas d'utilisation est une tentative de gestion d'un clic de noeud et d'un glisser-déposer de noeud dans une structure arborescente.
Le bit clé qui manque est la vérification si le comportement par défaut d'un événement a été empêché. C'est-à-dire qu'il y a un frère correspondant à d3.event.preventDefault()
- d3.event.defaultPrevented
. Vous devez vérifier cela dans votre gestionnaire click
pour voir si une action de glissement est en cours.
Voir aussi la réponse à cette question .
Vous pouvez différencier une click
et une dragstart
, mais il est plus difficile de faire la différence entre mousdown
et dragstart
.
dragstart
sera déclenché lorsque vous commencerez votre action glisser, ce qui signifie que vous ferez votre mousedown
. C'est pourquoi. chaque fois que vous click
, dragstart
sera triggered
. (une click
est une mousedown
+ mouseup
).
Donc, empêcher le clic d'être déclenché devrait fonctionner. Dans votre code, vous devez ajouter le preventDefault comme l'a laissé entendre Lars Kotthoff. Mais ne le mettez pas dans la fonction dragstart:
var dragCircle = d3.behavior.drag()
.on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault(); <-- Remove This
console.log('Start Dragging Circle');
})
Et ajoutez-le au bon endroit (dans la fonction click) et écrivez-le correctement avec d3 (d3.event .defaultPrevented)
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)
.on('click', click);
function click(d) {
if (d3.event.defaultPrevented) return; <-- Add d3.event.defaultPrevented
console.log('clicked');
}
Voir la version mise à jour . Désormais, lorsque vous faites glisser, la variable click
n'est plus déclenchée.
Gardez à l'esprit que lorsque vous cliquez sur, la dragstart
est toujours déclenchée. (mais pas drag
)