Подтвердить что ты не робот

D3 Различия между щелчком и перетаскиванием для элемента, который имеет поведение перетаскивания

Я не могу успешно провести различие между событием click и событием drag для элемента, связанного с использованием D3.js v3. Кругу в приведенном ниже коде присваивается поведение перетаскивания, а также прослушиватель 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.

Каков правильный способ обработки этих событий отдельно?
Вариант использования - попытка обработать node -click и node -drag/drop в макете дерева.

4b9b3361

Ответ 1

Недопустимый бит ключа - это проверка того, было ли предотвращено поведение события по умолчанию. То есть, подходящий брат к d3.event.preventDefault() - d3.event.defaultPrevented. Вы должны проверить это в своем обработчике click, чтобы узнать, не происходит ли какое-либо действие перетаскивания.

См. также ответ на этот вопрос.

Ответ 2

Вы можете различать a click и a dragstart, но сложнее провести различие между mousdown и a dragstart.

dragstart будет запущен, когда вы начнете действие перетаскивания, что означает, когда вы выполните mousedown. Вот почему. click, dragstart будет triggered. (a click является mousedown + mouseup).

Значит предотвращение срабатывания клика должно работать. В вашем коде вы должны добавить предупреждение, как указывал Ларс Котхофф. Но не ставьте его в функцию dragstart:

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)