Generic Drag
See the demo page for the finished version of the code.The Drag Process
The basic drag process consists of three steps: Initialize the drag when the mouse button is first depressed, move the target element as the mouse is moved and, finally, stop the drag when the mouse button is released.
Initializing the Drag
The dragStart()
function is called by the
onmousedown
event handler of some element, as described earlier.
It first determines the target element for the drag.
function dragStart(event, id) { var el; var x, y; // If an element id was given, find it. Otherwise use the element being // clicked on. if (id) dragObj.elNode = document.getElementById(id); else { if (browser.isIE) dragObj.elNode = window.event.srcElement; if (browser.isNS) dragObj.elNode = event.target; // If this is a text node, use its parent element. if (dragObj.elNode.nodeType == 3) dragObj.elNode = dragObj.elNode.parentNode; }
If an id
was given, the script uses
document.getElementById()
to locate the element. Otherwise it uses
the event
object to determine which element the mouse is over and
defaults to it. Either way, the target element is assigned to
dragObj.elNode.
Once special situation must checked for. If the mouse is over text, the
target of the mousedown
event will be a text node, instead of an
element node. Text nodes contain just that, textual data, and have no style
properties, like position. Instead, the appearance and position of the text is
determined by the style properties of the element they belong to.
So if the nodeType
of the event's target node happens to be
TEXT_NODE
(= 3), the script takes its parentNode
instead. The parent of a text node is always the element that contains the
text.
document.ELEMENT_NODE
returns a value of 1. Internet Explorer
does not provide these, so the actual numeric value is used in the script
instead.
The next step is to find the current position of the mouse pointer. These starting pixel coordinates will be used later to compare with the mouse position during the drag.
// Get cursor position with respect to the page. if (browser.isIE) { x = window.event.clientX + document.documentElement.scrollLeft + document.body.scrollLeft; y = window.event.clientY + document.documentElement.scrollTop + document.body.scrollTop; } if (browser.isNS) { x = event.clientX + window.scrollX; y = event.clientY + window.scrollY; }
Note that the event object's clientX
and clientY
values are relative to the viewport of the browser window, not to the page.
Just in case the window should scroll during the drag, we want to get the
cursor position relative to the page itself. So the current scroll offsets are
added.
You can see the difference for yourself by scrolling this page and clicking
anywhere on it. The clientX
and clientY
values are
displayed in the browser status window along with the calculated page offset
values.
document.body
object and the document.documentElement
object. But IE 5 only updates the pair in document.body
while the
pair in document.documentElement
always return zero. IE 6 does
just the opposite.
The above code just adds the scroll offset value from both objects, so it will
get the correct value regardless of version.
Netscape stores the page scroll offset values as properties of the
window
object.
Next, the function finds the target element's current position, using the
numeric portion of its left
and top
style values.
These are saved in dragObj
along with the mouse coordinates.
// Save starting positions of cursor and element. dragObj.cursorStartX = x; dragObj.cursorStartY = y; dragObj.elStartLeft = parseInt(dragObj.elNode.style.left, 10); dragObj.elStartTop = parseInt(dragObj.elNode.style.top, 10); if (isNaN(dragObj.elStartLeft)) dragObj.elStartLeft = 0; if (isNaN(dragObj.elStartTop)) dragObj.elStartTop = 0;
Note here that if left
or top
were not set using
an inline style on the element, the code assumes a value of zero.
To bring the element to the top of the stacking order, the script updates
its zIndex
style, after first incrementing the value of
dragObj.zIndex.
// Update element's z-index. dragObj.elNode.style.zIndex = ++dragObj.zIndex;
The last step is to set up capture of the mousemove
and
mouseup
events on the entire page, assigning the handler functions
dragGo()
and dragStop()
respectively.
// Capture mousemove and mouseup events on the page. if (browser.isIE) { document.attachEvent("onmousemove", dragGo); document.attachEvent("onmouseup", dragStop); window.event.cancelBubble = true; window.event.returnValue = false; } if (browser.isNS) { document.addEventListener("mousemove", dragGo, true); document.addEventListener("mouseup", dragStop, true); event.preventDefault(); }
The script then cancels the current event bubble and any default action. Normally, if you drag the mouse over a page the browser will highlight a section of text or other content. Stopping the event like this prevents that action during the drag.