D3.js v3を使用して両方にバインドされている要素で、click
イベントとdrag
イベントを正常に区別できません。以下のコードの円には、ドラッグ動作とclick
リスナーが割り当てられています。 ここでデモ
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');
});
この例で円をクリックするたびに、drag
イベントとclick
イベントを記録するコンソールが表示されます。ドラッグしても同じ動作をします。最初にdrag
イベントが記録され、mouseup
でclick
イベントが記録されます。
これらのイベントを個別に処理する正しい方法は何ですか?
ユースケースは、ツリーレイアウトでノードクリックおよびノードドラッグ/ドロップを処理する試みです。
欠落している重要な点は、イベントのデフォルトの動作が防止されているかどうかを確認することです。つまり、d3.event.preventDefault()
-d3.event.defaultPrevented
に一致する兄弟があります。 click
ハンドラーでこれをチェックして、ドラッグアクションが実行されているかどうかを確認する必要があります。
この質問 への回答も参照してください。
click
とdragstart
を区別できますが、mousdown
とdragstart
を区別することは困難です。
dragstart
は、ドラッグアクションを開始したとき、つまりmousedown
を実行したときにトリガーされます。これが理由です。 click
の場合、dragstart
はtriggered
になります。 (click
はmousedown
+ mouseup
です)。
そのため、クリックがトリガーされるのを防ぐことができます。 Lars Kotthoffが示唆したように、コードにpreventDefaultを追加する必要があります。ただし、ドラッグスタート関数には入れないでください。
var dragCircle = d3.behavior.drag()
.on('dragstart', function () {
d3.event.sourceEvent.stopPropagation();
d3.event.sourceEvent.preventDefault(); <-- Remove This
console.log('Start Dragging Circle');
})
(クリック機能で)正しい場所に追加し、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');
}
更新バージョン を参照してください。ドラッグすると、click
はトリガーされなくなりました。
クリックしても、dragstart
がトリガーされることに注意してください。 (ただし、drag
は除く)
d3.event.sourceEvent.preventDefault()
は期待どおりに動作しないか、むしろ矛盾します。
この問題に直面し、2つのイベントを区別するために、isDragged
イベント内でブール値onDrag
を使用しました。したがって、この値が設定されている場合、drag
イベントが実行され、そうでない場合はclick
イベントが実行されます。また、オブジェクトの通常のクリックは、dragstart
およびdragend
イベントをトリガーしますが、onDrag
イベントはトリガーしません。