Jessica Jessica - 2 months ago 8
CSS Question

Move element with mouse starts to snap up and down

I am trying to make a drag on y axis functionality using

mousedown, mousemove
events. The formula is as follows:

var position = e.clientY - getOrigin(myDiv).top;
myDiv.style.transform = 'translate3d(0px, ' + position + 'px, 0px)';

function getOrigin(elm) {
...
return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}


When I drag the element, it snaps up and down really fast. Why is that happening, and how can I fix it?

JSFiddle





var myDiv = document.getElementById('myDiv');

myDiv.addEventListener('mousedown', handleMouseDown);
window.addEventListener('mouseup', handleMouseUp);

function handleMouseDown(e) {
window.addEventListener('mousemove', handleMouseMove);
}

function handleMouseUp(e) {
window.removeEventListener('mousemove', handleMouseMove);
}

function handleMouseMove(e) {
e.preventDefault();
var position = e.clientY - getOrigin(myDiv).top;
myDiv.style.transform = 'translate3d(0px, ' + position + 'px, 0px)';
}


function getOrigin(elm) {
var box = (elm.getBoundingClientRect) ? elm.getBoundingClientRect() : {
top: 0,
left: 0
},
doc = elm && elm.ownerDocument,
body = doc.body,
win = doc.defaultView || doc.parentWindow || window,
docElem = doc.documentElement || body.parentNode,
clientTop = docElem.clientTop || body.clientTop || 0, // border on html or body or both
clientLeft = docElem.clientLeft || body.clientLeft || 0;

return {
left: box.left + (win.pageXOffset || docElem.scrollLeft) - clientLeft,
top: box.top + (win.pageYOffset || docElem.scrollTop) - clientTop
};
}

body {
margin-top: 50px;
padding-top: 50px;
}
#myDiv {
background-color: orange;
width: 200px;
height: 100px;
}

<div id="myDiv"></div>




Answer

Because I couldn't exactly figure out what was causing the problem in OPs question (for an unknown reason box.top was returning 2 different values alternately on each pixel movement in OPs script), I've written a different script that works perfectly fine:

//document.addEventListener('DOMContentLoaded', function(){
	var myDiv = document.getElementById('myDiv');

	myDiv.addEventListener('mousedown', handleMouseDown);
	window.addEventListener('mouseup', handleMouseUp);

	function handleMouseDown(e) {
		window.addEventListener('mousemove', mouseMove.start(this, 'body',e));
	}

	function handleMouseUp(e) {
		window.removeEventListener('mousemove', mouseMove.stop('body'));
	}

	var mouseMove = function(){
		return {
			move: function(elm, posY){
				elm.style.top = posY + "px";
			},
			start: function(elm, container, e){
				e = e || window.event;
				var posY = e.clientY,
					elmTop = elm.style.top,
					elmHeight = parseInt(elm.style.height),
					conHeight = parseInt(document.getElementById(container).style.height);
				elmTop = elmTop.replace('px','');
				var diffY = posY - elmTop;

				document.onmousemove = function(e){
					e = e || window.event;
					var posY = e.clientY,
						Y = posY - diffY;
					if (Y < 0) Y = 0;
					if (Y + elmHeight > conHeight) Y = conHeight - elmHeight;
					mouseMove.move(elm,Y);
				}
			},
			stop : function(container){
				var a = document.createElement('script');
				document.onmousemove = function(){}
			},
		}
	}();
//});
#body {
	margin-top: 50px;
	position: absolute;
}
#myDiv {
	position: absolute;
	background-color: orange;
	width: 200px;
	height: 100px;
}
<div id="body">
  <div id="myDiv"></div>
</div>