Вроде получилось, но почему-то не срабатывает последний scrollBy.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title></title>
<style>
html, body { margin: 0; padding: 0; }
#field {
background: url(https://js.cx/drag-heroes/field.png);
width: 800px;
height: 600px;
float: left;
}
.hero {
background: url(https://js.cx/drag-heroes/heroes.png);
width: 130px;
height: 128px;
float: left;
}
#hero1 { background-position: 0 0; }
#hero2 { background-position: 0 -128px; }
#hero3 { background-position: -120px 0; }
#hero4 { background-position: -125px -128px; }
#hero5 { background-position: -248px -128px; }
#hero6 { background-position: -244px 0; }
.draggable { cursor: pointer; }
</style>
</head>
<body>
<h2>Расставьте супергероев по полю.</h2>
<p>Супергерои и мяч -- это элементы с классом "draggable". Сделайте так, чтобы их можно было переносить.</p>
<p>Важно: если супергероя подносят к низу или верху страницы, она должна автоматически прокручиваться. Если страница помещается на вашем экране целиком и не имеет вертикальной прокрутки -- сделайте окно браузера меньше, чтобы протестировать эту возможность.</p>
<p>Да, и ещё: супергерои ни при каких условиях не должны попасть за край экрана.</p>
<div id="field"></div>
<div class="hero draggable" id="hero1"></div>
<div class="hero draggable" id="hero2"></div>
<div class="hero draggable" id="hero3"></div>
<div class="hero draggable" id="hero4"></div>
<div class="hero draggable" id="hero5"></div>
<div class="hero draggable" id="hero6"></div>
<img src="https://js.cx/drag-heroes/ball.png" class="draggable" />
<div style="clear:both"></div>
<script>
var shiftX, shiftY;
document.onmousedown = function(event) {
var target = event.target;
if( !target.classList.contains('draggable') ) return;
shiftX = event.pageX - getCoords(target).left;
shiftY = event.pageY - getCoords(target).top;
target.style.cssFloat = 'none';
target.style.position = 'absolute';
moveAt(target, event);
document.body.appendChild(target);
document.onmousemove = function(event) {
moveAt(target, event);
};
target.onmouseup = function() {
document.onmousemove = this.onmouseup = null;
};
return false;
};
function moveAt(elem, event) {
var left = event.pageX - shiftX,
top = event.pageY - shiftY,
rightEdge = document.documentElement.clientWidth - elem.offsetWidth;
left < 0 && (left = 0);
left > rightEdge && (left = rightEdge);
var docElemBottom = getCoords(document.documentElement).bottom;
var bottomEdge = docElemBottom - elem.offsetHeight;
if(top > document.documentElement.clientHeight - elem.offsetHeight && (top < bottomEdge)) {
var min = Math.min(bottomEdge - top, 10);
scrollBy(0, min);
console.log([top, bottomEdge, min]);
}
if(top > docElemBottom - elem.offsetHeight) {
top = docElemBottom - elem.offsetHeight;
}
elem.style.left = left + 'px';
elem.style.top = top + 'px';
}
function getCoords(elem) {
var box = elem.getBoundingClientRect();
return {
top: box.top + pageYOffset,
left: box.left + pageXOffset,
bottom: box.bottom + pageYOffset
};
}
</script>
</body>
</html>