Html on mouse drag

Мышь: Drag’n’Drop

Материал на этой странице устарел, поэтому скрыт из оглавления сайта.

Более новая информация по этой теме находится на странице https://learn.javascript.ru/mouse-drag-and-drop.

Drag’n’Drop – это возможность захватить мышью элемент и перенести его. В своё время это было замечательным открытием в области интерфейсов, которое позволило упростить большое количество операций.

Перенос мышкой может заменить целую последовательность кликов. И, самое главное, он упрощает внешний вид интерфейса: функции, реализуемые через Drag’n’Drop, в ином случае потребовали бы дополнительных полей, виджетов и т.п.

Отличия от HTML5 Drag’n’Drop

В современном стандарте HTML5 есть поддержка Drag’n’Drop при помощи специальных событий.

Эти события поддерживаются всеми современными браузерами, и у них есть свои интересные особенности, например, можно перетащить файл в браузер, так что JS получит доступ к его содержимому. Они заслуживают отдельного рассмотрения.

Но в плане именно Drag’n’Drop у них есть существенные ограничения. Например, нельзя организовать перенос «только по горизонтали» или «только по вертикали». Также нельзя ограничить перенос внутри заданной зоны. Есть и другие интерфейсные задачи, которые такими встроенными событиями нереализуемы.

Поэтому здесь мы будем рассматривать Drag’n’Drop при помощи событий мыши.

Рассматриваемые приёмы, вообще говоря, применяются не только в Drag’n’Drop, но и для любых интерфейсных взаимодействий вида «захватить – потянуть – отпустить».

Алгоритм Drag’n’Drop

Основной алгоритм Drag’n’Drop выглядит так:

  1. Отслеживаем нажатие кнопки мыши на переносимом элементе при помощи события mousedown .
  2. При нажатии – подготовить элемент к перемещению.
  3. Далее отслеживаем движение мыши через mousemove и передвигаем переносимый элемент на новые координаты путём смены left/top и position:absolute .
  4. При отпускании кнопки мыши, то есть наступлении события mouseup – остановить перенос элемента и произвести все действия, связанные с окончанием Drag’n’Drop.

В следующем примере эти шаги реализованы для переноса мяча:

var ball = document.getElementById('ball'); ball.onmousedown = function(e) < // 1. отследить нажатие // подготовить к перемещению // 2. разместить на том же месте, но в абсолютных координатах ball.style.position = 'absolute'; moveAt(e); // переместим в body, чтобы мяч был точно не внутри position:relative document.body.appendChild(ball); ball.style.zIndex = 1000; // показывать мяч над другими элементами // передвинуть мяч под координаты курсора // и сдвинуть на половину ширины/высоты для центрирования function moveAt(e) < ball.style.left = e.pageX - ball.offsetWidth / 2 + 'px'; ball.style.top = e.pageY - ball.offsetHeight / 2 + 'px'; >// 3, перемещать по экрану document.onmousemove = function(e) < moveAt(e); >// 4. отследить окончание переноса ball.onmouseup = function() < document.onmousemove = null; ball.onmouseup = null; >>

Если запустить этот код, то мы заметим нечто странное. При начале переноса мяч «раздваивается» и переносится не сам мяч, а его «клон».

Это можно увидеть в действии внутри ифрейма:

Попробуйте перенести мяч мышкой и вы увидите описанное, довольно-таки странное, поведение.

Это потому, что браузер имеет свой собственный Drag’n’Drop, который автоматически запускается и вступает в конфликт с нашим. Это происходит именно для картинок и некоторых других элементов.

ball.ondragstart = function() < return false; >;

Теперь всё будет в порядке.

В действии (внутри ифрейма):

Ещё одна особенность правильного Drag’n’Drop – событие mousemove отслеживается на document , а не на ball .

С первого взгляда кажется, что мышь всегда над мячом и обработчик mousemove можно повесить на сам мяч, а не на документ.

Однако, на самом деле мышь во время переноса не всегда над мячом.

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

Вот почему мы должны отслеживать mousemove на всём document .

Правильное позиционирование

В примерах выше мяч позиционируется в центре под курсором мыши:

self.style.left = e.pageX - ball.offsetWidth / 2 + 'px'; self.style.top = e.pageY - ball.offsetHeight / 2 + 'px';

Если поставить left/top ровно в pageX/pageY , то мячик прилипнет верхним-левым углом к курсору мыши. Будет некрасиво. Поэтому мы сдвигаем его на половину высоты/ширины, чтобы был центром под мышью. Уже лучше.

Но не идеально. В частности, в самом начале переноса, особенно если мячик «взят» за край – он резко «прыгает» центром под курсор мыши.

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

Где захватили, за ту «часть элемента» и переносим:

    Когда человек нажимает на мячик mousedown – курсор сдвинут относительно левого-верхнего угла мяча на расстояние, которое мы обозначим shiftX/shiftY . И нужно при переносе сохранить этот сдвиг. Получить значения shiftX/shiftY легко: достаточно вычесть из координат курсора pageX/pageY левую-верхнюю границу мячика, полученную при помощи функции getCoords. При Drag’n’Drop мы везде используем координаты относительно документа, так как они подходят в большем количестве ситуаций. Конечно же, не проблема перейти к координатам относительно окна, если это понадобится. Достаточно использовать position:fixed , elem.getBoundingClientRect() для определения координат и e.clientX/Y .

// onmousedown shiftX = e.pageX - getCoords(ball).left; shiftY = e.pageY - getCoords(ball).top;
// onmousemove ball.style.left = e.pageX - shiftX + 'px'; ball.style.top = e.pageY - shiftY + 'px';

Итоговый код с правильным позиционированием:

var ball = document.getElementById('ball'); ball.onmousedown = function(e) < var coords = getCoords(ball); var shiftX = e.pageX - coords.left; var shiftY = e.pageY - coords.top; ball.style.position = 'absolute'; document.body.appendChild(ball); moveAt(e); ball.style.zIndex = 1000; // над другими элементами function moveAt(e) < ball.style.left = e.pageX - shiftX + 'px'; ball.style.top = e.pageY - shiftY + 'px'; >document.onmousemove = function(e) < moveAt(e); >; ball.onmouseup = function() < document.onmousemove = null; ball.onmouseup = null; >; > ball.ondragstart = function() < return false; >; function getCoords(elem) < // кроме IE8- var box = elem.getBoundingClientRect(); return < top: box.top + pageYOffset, left: box.left + pageXOffset >; >

В действии (внутри ифрейма):

Различие особенно заметно, если захватить мяч за правый-нижний угол. В предыдущем примере мячик «прыгнет» серединой под курсор, в этом – будет плавно переноситься с текущей позиции.

Итого

Мы рассмотрели «минимальный каркас» Drag’n’Drop .

  1. События ball.mousedown → document.mousemove → ball.mouseup .
  2. Передвижение с учётом изначального сдвига shiftX/shiftY .
  3. Отмена действия браузера по событию dragstart .

На этой основе можно сделать очень многое.

  • При mouseup можно обработать окончание переноса, произвести изменения в данных, если они нужны.
  • Во время самого переноса можно подсвечивать элементы, над которыми проходит элемент.
  • При обработке событий mousedown и mouseup можно использовать делегирование, так что одного обработчика достаточно для управления переносом в зоне с сотнями элементов.

Это и многое другое мы рассмотрим в статье про Drag’n’Drop объектов.

Источник

How TO — Create a Draggable HTML Element

Learn how to create a draggable HTML element with JavaScript and CSS.

Draggable DIV Element

Create a Draggable DIV Element

Step 1) Add HTML:

Example

Step 2) Add CSS:

The only important style is position: absolute , the rest is up to you:

Example

#mydiv <
position: absolute;
z-index: 9;
background-color: #f1f1f1;
border: 1px solid #d3d3d3;
text-align: center;
>

#mydivheader padding: 10px;
cursor: move;
z-index: 10;
background-color: #2196F3;
color: #fff;
>

Step 3) Add JavaScript:

Example

// Make the DIV element draggable:
dragElement(document.getElementById(«mydiv»));

function dragElement(elmnt) var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById(elmnt.id + «header»)) // if present, the header is where you move the DIV from:
document.getElementById(elmnt.id + «header»).onmousedown = dragMouseDown;
> else // otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
>

function dragMouseDown(e) e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
>

function elementDrag(e) e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 — e.clientX;
pos2 = pos4 — e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element’s new position:
elmnt.style.top = (elmnt.offsetTop — pos2) + «px»;
elmnt.style.left = (elmnt.offsetLeft — pos1) + «px»;
>

function closeDragElement() // stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
>
>

Источник

Читайте также:  Java enum and constants
Оцените статью