Dragging Around the Page

XHTML elements can be repositioned on a page by permitting the user to drag the item. This is the case for the following four items. Each can be dragged to different positions on the page.

This is a Text String
This division is positioned absolute on the page so it can be dragged by the user to other positions.
This division does not have a fixed width or height. When dragged to the left or right, the division adjusts its size to fit within the available space on the page.
Figure 15-1. Dragging page elements.

Draggable items must be positioned items. As in the case for all positioned items, they are positioned absolute inside a container that is positioned relative to maintain the items within the flow of page elements. Coding for the above objects is shown below.

<div style="position:relative; width:550px; height:125px; cursor:hand">

<img src="jsdhtml.gif" style="position:absolute; left:15px; top:10px"
  onmousedown="Move(this)"/>

<span style="position:absolute; left:15px; top:80px; width:150; height:20;
padding:3; background-color:red; color:white; font-weight:bold"
onmousedown="Move(this)">
  This is a Text String
</span>

<div style="position:absolute; left:190px; top:10px; width:170px; 
border-style:solid 1; padding:5; text-align:left; background-color:white" 
onmousedown="Move(this)">
  This division is positioned absolutely on the page so it can be dragged
  by the user to other positions.
</div>

<div style="position:absolute; left:380px; top:10px"
onmousedown="Move(this)">
  This division does not have a fixed width or height. When dragged to the
  left or right, the division adjusts its size to fit within the available
  space on the page.
</div>

</div>
Listing 15-1. Code to position draggable page elements.

All items are give left and top property settings to position them within the containing division. An item is designated for dragging by coding an onmousedown="Move(this)" event handler that calls the Move() function, passing its self reference to the function.

The script contains several variable that are defined globally for reference from two different functions. Variable SelectedItem stores the object reference for the item being dragged; SelectedX and SelectedY store the initial page coordinates of the item being dragged; MouseX and MouseY store the initial coordinates of the mouse cursor when the item is clicked.

<script type="text/javascript">
var SelectedItem;
var SelectedX, SelectedY;
var MouseX, MouseY;

function Move(ClickedItem)
{
  SelectedItem = ClickedItem;
  SelectedX = SelectedItem.style.pixelLeft;
  SelectedY = SelectedItem.style.pixelTop;
  MouseX = event.clientX;
  MouseY = event.clientY;
  document.onmousemove = Drag;
  document.onmouseup = Drop;
}
...
</script>
Listing 15-2. Code to control dragging and dropping of page elements.

Movement of the item around the page is based on changing positions of the mouse cursor as it is moved. In order to move an item, the initial position of the cursor needs to be known as well as the initial position of the item being moved. The item's pixelLeft and pixelTop positions are assigned to variables SelectedX and SelectedY to store the current item position. The cursor's current position within the window is given by event properties event.clientX and event.clientY which are stored in variables MouseX and MouseY.

Cursor Property Description
event.clientX
event.clientY

Coordinates of mouse pointer within the window or frame.
Figure 15-2. Mouse position properties.

Once these initial settings are captured, dragging of the item is put under control of the Drag() function. This function needs to be called repeatedly, whenever the mouse is moved. The mousemove event, therefore, is put under purview of the Web document itself so that any mouse movement across the document is captured. This assignment takes place with the statement,

document.onmousemove = Drag;

appearing at the close of the Move() function. At this point, the document's onmousemove event handler becomes sensitive to mouse movements, calling the Drag() function each time they occur. At the same time, the document is made sensitive to mouseup events with the statement,

document.onmouseup = Drop;

calling the Drop() function to cease moving an item when the mouse button is released.

Note the different syntax used when initiating an event handler within a script. These event handlers must be coded without parentheses (Drag, Drop).

A selected item is dragged by the Drag() function whose coding is shown below.

function Drag()
{
  SelectedItem.style.left = SelectedX + (event.clientX - MouseX);
  SelectedItem.style.top = SelectedY + (event.clientY - MouseY);
  return false;
}
Listing 15-3. Script to drag a page element.

As mentioned, the direction and amount by which the selected item is moved is given by the direction and amount by which the cursor is moved. The difference between the new position of the cursor and its original position when the item was clicked is given by the formulas: (event.clientX - MouseX) and (event.clientY - MouseY). The horizontal mouse distance is then added to the previous horizontal position of the item; the vertical mouse distance is added to the previous vertical position of the item. On screen, the item tracks the position of the cursor. The return false statement is needed to suppress any other associated effects of dragging such as highlighting text on the page.

When the mouse button is released, the document's onmousemove and onmouseup event handlers are released by the Drop() function. Now, mouse movement isn't tracked until another object is selected for dragging.

function Drop()
{
  document.onmousemove = null;
  document.onmouseup = null;
}
Listing 15-4. Script to drop a page element.

The above scripts can be coded on any page to permit dragging of any object on that page. All that is required to activate dragging is, first, to position an item on the page. Position it absolute inside a container that is positioned relative in order to establish the item's initial location on the page. Then assign the event handler onmousedown=Move(this) to the item.