В нижеприведенном фрагменте у меня есть 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.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
в поле относительно движения мыши.