Перетаскивание d3 с html-элементами, начальная позиция

1

В нижеприведенном фрагменте у меня есть div, когда я впервые начинаю рисовать div вокруг него, он слегка скачет вправо, заставляя меня думать, что он пересчитывает начальную начальную позицию туда, где находится мышь, а не добавляется в исходное положение.

Я попытался найти другие примеры, используя элементы non-svg, но не смог найти их, и документация для d3-drag не говорит ничего о невозможности правильно перетаскивать элементы, отличные от svg, но не уверена, чего я не вижу.

Здесь код:

var box = d3.select("body").append("div")
    .attr("class", "box")

d3.select(".box").call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended))

function dragstarted(d) {
    d3.select(this).raise().classed("active", true);
}

function dragged(d) {
	console.log(d3.event.x)
    d3.select(this)
        .style("left", d3.event.x + "px")
        .style("top", d3.event.y + "px")
}

function dragended(d, i) {
    d3.select(this).classed("active", false);
}
body {
    padding-top: 25px;
    margin: auto;
    width: 600px;
}

div.box {
    position: relative;
    width: auto;
    padding: 20px 20px 20px 20px;
    margin: 5px 5px 5px 5px;
    background: crimson;
}
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>
Теги:
d3.js

1 ответ

1
Лучший ответ

Это сводится к предмету перетаскивания.

Перетаскивание в вашем примере не знает, каково должно быть относительное сопротивление, это означает, что перетаскивание не влияет на то, где на ящике вы нажимаете (d3.event.x будет в этом случае занимать позицию мыши, независимо от того, где вы нажимаете мыши). Всякий раз, когда вы завершаете перетаскивание, верхний левый угол окна позиционируется в соответствии с событием перетаскивания x, y. Вы можете увидеть эффект этого, если вы инициируете перетаскивание в верхнем левом углу, дрейф хуже, чем если вы инициируете перетаскивание в правом нижнем углу окна.

Давайте воспользуемся функцией объекта перетаскивания по умолчанию в d3-drag:

function subject(d) {
  return d == null ? {x: d3.event.x, y: d3.event.y} : d;
}

В примере вопроса мы не обеспечиваем датум, поэтому d является null и d3.event.x и d3.event.y используются для расчета контрольной точки для сопротивления.

Вместо этого дайте нашему объекту привязку, чтобы мы могли рассчитать относительное перемещение перетаскивания в поле и обновить базу данных, чтобы отразить результаты любых событий перетаскивания.

Обновите добавление поля:

  var box = d3.select("body").append("div")
    .attr("class", "box")
    .datum({x:0,y:0});    // starting position

И обновите функцию перетаскивания:

 function dragged(d) {
    d3.select(this)
        .style("left", (d.x = d3.event.x) + "px")
        .style("top", (d.y = d3.event.y) + "px")
}    

Теперь у нас есть привязка, которая обновляется всякий раз, когда выполняется перетаскивание, и поле позиционируется на основе относительного движения, которое применяется к этой точке привязки:

var box = d3.select("body").append("div")
    .attr("class", "box")
    .datum({x:0,y:0});

d3.select(".box").call(d3.drag()
    .on("start", dragstarted)
    .on("drag", dragged)
    .on("end", dragended))

function dragstarted(d) {
    d3.select(this).raise().classed("active", true);
}

function dragged(d) {
    d3.select(this)
        .style("left", (d.x = d3.event.x) + "px")
        .style("top", (d.y = d3.event.y) + "px")
}

function dragended(d, i) {
    d3.select(this).classed("active", false);
}
body {
   /* padding-top: 25px;
    margin: auto;*/
    width: 600px;
}

div.box {
    position: relative;
    width:40px;
    padding: 20px 20px 20px 20px;
    margin: 5px 5px 5px 5px;
   height: 40px;
    background: crimson;
}
<meta charset="utf-8">
<script src="https://d3js.org/d3.v5.min.js"></script>

Функциональность d3.drag по умолчанию предполагает, что привязка для привязки имеет свойства x и y для позиционирования.


Немного более глубокое объяснение (но для простоты, предполагая, что события перетаскивания состоят только из начала и конца):

Что происходит без объекта перетаскивания, мы имеем (используя здесь значения x):

 d3.event.x = subject.x + mouseUp.x - mouseDown.x

Мышь вниз/вверх, перетащив начало/конец, а mouseUp.x - mouseDown.x являющееся изменением x за время перетаскивания

Без объектных данных это упрощает:

 d3.event.x = mouseUp.x 

поскольку subject.x устанавливается в mouseDown.x когда начинается перетаскивание:

function subject(d) {
  return d == null ? {x: d3.event.x, y: d3.event.y} : d;
}

Но, установив исходную точку на некоторое начальное значение, представляющее верхний левый угол, получим:

 d3.event.x = topLeft.x + mouseUp.x - mouseDown.x

Теперь мы изменили x плюс topLeft.x, именно то, что мы хотим topLeft.x в поле относительно движения мыши.

  • 0
    Большое спасибо и спасибо за отличное объяснение!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню