自定义拖动元素跳来跳去
Custom drag element jumps around
显然我在鼠标光标和元素偏移量上做了一些数学运算,但我想不出来是什么。为什么元素跳来跳去这么多?目标是能够拖动元素,但我需要它相对于鼠标保持不变(IE 不是 SNAP 到光标)。此外,我实际上希望能够使用父元素进行拖动,如果这有意义的话,如代码中所反映的那样。您可以在父容器上“拖动”以移动目标。
另外,我意识到还有其他问题需要改进(比如拖出页面等),但这个问题的目的是解决来回跳转问题。
let scaleX = 1;
let scaleY = 1;
let skewX = 0;
let skewY = 0;
let translateX = 0;
let translateY = 0;
let isPanning = false;
let $map = $('#map');
let $container = $('#mapCanvas');
function moveMap() {
$("#map").css({
transform: ` matrix(${scaleX}, ${skewX}, ${skewY}, ${scaleY}, ${translateX}, ${translateY})`
});
}
$container.on("mousedown", function(event) {
isPanning = true;
});
$container.on("mouseup", function(event) {
isPanning = false;
});
$container.on("mousemove", function(event) {
if (isPanning) {
translateX = event.pageX + (event.pageX - $map.offset().left) ;
translateY = event.pageY + (event.pageY - $map.offset().top);
moveMap();
}
});
#mapCanvas {
position: absolute;
left: 0;right:0;top:0;bottom:0;
user-select: none;
}
#map {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
border: 1px solid black;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mapCanvas">
<div id="map">DRAG ME</div>
</div>
我确定您首先看过代码片段...如果没有,我们现在就看吧!
那么你的代码有什么问题?
mousemove
是一个 “机关枪” 事件。
它像地狱一样燃烧!因此,在事件触发后,您必须更新全局变量,然后调用 moveMap
函数...同时,mousemove
已经再次触发...完全打乱了计算。一毫秒对于浏览器来说是十分钟(我几乎没有夸大......)
为避免计时问题,只需将事件传递给您的函数即可。或者直接在事件处理程序中使用函数。为什么你仍然需要一个不同的命名函数?
第二件事...您必须知道鼠标相对于可拖动元素的位置,才能获得所需的平滑拖动效果。计算中使用的元素的位置是左上角。但也许鼠标在 "dragStart" 的右下角附近......你必须知道。这只能从 mousedown
事件中扣除。
尽情拖动吧!
let scaleX = 1;
let scaleY = 1;
let skewX = 0;
let skewY = 0;
//let translateX = 0; // No need to be global
//let translateY = 0;
let isPanning = false;
// Additional object to store the mouse "offset" versus the element position
let mouse_vs_element;
let $map = $('#map');
let $container = $('#mapCanvas');
function moveMap(event) {
let translateX = event.pageX - mouse_vs_element.X
let translateY = event.pageY - mouse_vs_element.Y
//console.log(translateX, translateY)
$("#map").css({
transform: ` matrix(${scaleX}, ${skewX}, ${skewY}, ${scaleY}, ${translateX}, ${translateY})`
});
}
$container.on("mousedown", function(event) {
isPanning = true;
// Get the draggable element position at start
let element_pos = event.target.getBoundingClientRect()
// Mouse position relative to that element
mouse_vs_element = {
X: event.pageX - element_pos.left,
Y: event.pageY - element_pos.top
}
});
$container.on("mouseup", function(event) {
isPanning = false;
// Clear that (optionnal in fact, but a good practice)
mouse_vs_element = {}
});
$container.on("mousemove", function(event) {
if (isPanning) {
moveMap(event);
}
});
#mapCanvas {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
user-select: none;
}
#map {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
border: 1px solid black;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mapCanvas">
<div id="map">DRAG ME</div>
</div>
显然我在鼠标光标和元素偏移量上做了一些数学运算,但我想不出来是什么。为什么元素跳来跳去这么多?目标是能够拖动元素,但我需要它相对于鼠标保持不变(IE 不是 SNAP 到光标)。此外,我实际上希望能够使用父元素进行拖动,如果这有意义的话,如代码中所反映的那样。您可以在父容器上“拖动”以移动目标。
另外,我意识到还有其他问题需要改进(比如拖出页面等),但这个问题的目的是解决来回跳转问题。
let scaleX = 1;
let scaleY = 1;
let skewX = 0;
let skewY = 0;
let translateX = 0;
let translateY = 0;
let isPanning = false;
let $map = $('#map');
let $container = $('#mapCanvas');
function moveMap() {
$("#map").css({
transform: ` matrix(${scaleX}, ${skewX}, ${skewY}, ${scaleY}, ${translateX}, ${translateY})`
});
}
$container.on("mousedown", function(event) {
isPanning = true;
});
$container.on("mouseup", function(event) {
isPanning = false;
});
$container.on("mousemove", function(event) {
if (isPanning) {
translateX = event.pageX + (event.pageX - $map.offset().left) ;
translateY = event.pageY + (event.pageY - $map.offset().top);
moveMap();
}
});
#mapCanvas {
position: absolute;
left: 0;right:0;top:0;bottom:0;
user-select: none;
}
#map {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
border: 1px solid black;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mapCanvas">
<div id="map">DRAG ME</div>
</div>
我确定您首先看过代码片段...如果没有,我们现在就看吧!
那么你的代码有什么问题?
mousemove
是一个 “机关枪” 事件。
它像地狱一样燃烧!因此,在事件触发后,您必须更新全局变量,然后调用 moveMap
函数...同时,mousemove
已经再次触发...完全打乱了计算。一毫秒对于浏览器来说是十分钟(我几乎没有夸大......)
为避免计时问题,只需将事件传递给您的函数即可。或者直接在事件处理程序中使用函数。为什么你仍然需要一个不同的命名函数?
第二件事...您必须知道鼠标相对于可拖动元素的位置,才能获得所需的平滑拖动效果。计算中使用的元素的位置是左上角。但也许鼠标在 "dragStart" 的右下角附近......你必须知道。这只能从 mousedown
事件中扣除。
尽情拖动吧!
let scaleX = 1;
let scaleY = 1;
let skewX = 0;
let skewY = 0;
//let translateX = 0; // No need to be global
//let translateY = 0;
let isPanning = false;
// Additional object to store the mouse "offset" versus the element position
let mouse_vs_element;
let $map = $('#map');
let $container = $('#mapCanvas');
function moveMap(event) {
let translateX = event.pageX - mouse_vs_element.X
let translateY = event.pageY - mouse_vs_element.Y
//console.log(translateX, translateY)
$("#map").css({
transform: ` matrix(${scaleX}, ${skewX}, ${skewY}, ${scaleY}, ${translateX}, ${translateY})`
});
}
$container.on("mousedown", function(event) {
isPanning = true;
// Get the draggable element position at start
let element_pos = event.target.getBoundingClientRect()
// Mouse position relative to that element
mouse_vs_element = {
X: event.pageX - element_pos.left,
Y: event.pageY - element_pos.top
}
});
$container.on("mouseup", function(event) {
isPanning = false;
// Clear that (optionnal in fact, but a good practice)
mouse_vs_element = {}
});
$container.on("mousemove", function(event) {
if (isPanning) {
moveMap(event);
}
});
#mapCanvas {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
user-select: none;
}
#map {
width: 100px;
height: 100px;
text-align: center;
line-height: 100px;
border: 1px solid black;
color: black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="mapCanvas">
<div id="map">DRAG ME</div>
</div>