AjaxPatterns
This is the original book draft version for the Drag-And-Drop Ajax pattern, offered for historical purposes and as an anti-spam measure.
You're probably better off visiting the Live Wiki Version for Drag-And-Drop instead, where you can make changes and see what others have written.

Drag-And-Drop

Drag, Move, Pull, Rearrange

Goal Story

Stuart is purchasing books online. Each time he wants to buy one, he drags the book icon into a shopping cart.

Problem

How can users rearrange objects on the page?

Forces

  • Objects relationships are important and the user's task often involves changing those relationships.

  • Ajax Apps often represent object relationships visually.

  • Rearranging the visual structure from a separate form is messy - trying to map between the form and the visual structure is confusing and error-prone. It's easiest if users can directly manipulate the visual structure.

Solution

Provide a Drag-And-Drop mechanism to let users directly rearrange elements around the page. Drag-and-drop has proven itself as a powerful control mechanism in conventional desktop applications, and is certainly achievable using standard web technologies. The basics are straightforward: the user holds down the mouse button while the mouse hovers over a page element, and the user then moves the mouse with the button still depressed. The element follows the mouse around until the user finally releases it.

Constraints are sometimes applied on the extent of movement. Sometimes, an element can only move in one direction, or within a bounding box. Also, the element might move permanently upon mouse release, or flip back to its original position. Another variable is exactly which part of the element must be dragged. Sometimes, it's better to define a "handle" region, which is the only place where the element can be "picked up" for dragging. The main benefit is that the user can click elsewhere in the region.

Among the applications:

Rearranging lists

This simple task has been ridiculously tedious on the web. Some websites require an entire page reload each time you move an object up and down. Others have implemented the buttons in Javascript, but you still have to click Up or Down repeatedly just to place a single item. Drag-And-Drop is a natural fit - just pick up the list items and drop them where you want them.

Rearranging items in a geometric space

Again, this is a natural application: pick up the objects and drag them where you want them to go.

Operating on a geometric space

For example, dragging a magnifying glass or an eraser through an image.

Building up a collection

For example, dragging products into a shopping cart.

Expressing an action

Perhaps the most famous use of Drag-And-Drop was Apple's original deletion mechanism, where you delete something by dragging it into the trashcan. The basic idea is to visually represent a command as an icon, and let the user drag items into it for processing.

There are a few ways to implement Drag-And-Drop:

  • Reuse an existing library. These are becoming increasingly powerful and portable, and it's likely those available will do the job for you.

  • Leverage built-in Drag-And-Drop. Unfortunately, this isn't much of an option because only Windows IE supports Drag-And-Drop explicitly.

  • Roll your own Drag-And-Drop. Not recommended due to portability issues.

Here are a few Drag-And-Drop libraries, all with good cross-browser support and online demos:

Scriptaculous

Among many other features, Scriptaculous provides a general-purpose, portable, Drag-And-Drop library.

wzDragDrop

A Drag-And-Drop library which also includes resize capability.

DOM-Drag

A lightweight Drag-And-Drop library.

Tim Taylor's Drag-And-Drop Sortable Lists

A library specifically for list manipulation, supporting Drag-And-Drop based reordering.

The basic approach used for Drag-And-Drop is as follows:

  • Event handlers inspect the incoming event to determine the element being dragged.

  • An onmousedown handler saves the starting co-ordinates, sets the zIndex so that the element appears in front during the drag, changes some other style settings to indicate a drag has begun.

  • A mousemove handler inspects the mouse's co-ordinates and moves the element accordingly using positioning style properties (usually left and top). Here's where cross-browser support gets nasty - mouse co-ordinates in the event object are seriously platform-specific.

  • An onmouseup handler restores normal style settings and performs any other cleaning up.

Decisions

What constraints will apply to the drag operation?

You will need to decide in which directions the element can move, and how far it can move. Generally, this should be fairly obvious from the visual representation being manipulated. Often, there is a container where similar objects live inside, and this should be the bounding box for dragging operations.

Real-World Examples

Magnetic Poetry

Magnetic Poetry is a fun application that simulates dragging magnetic tiles around a fridge.

Backbase Portal

The Backbase Portal show various “Portlet”s in a 3-column structure. Users can easily rearrange the portlets to suit their own taste, using a Drag-And-Drop mechanism. Google's portal and Microsoft's Start.com follow a similar approach.

A9 Maps

A9 Maps offers photographs of map locations. A draggable magnifying glass appears on the map, and you can move it to different regions of the map to see what the area looks like in real life.

Code Example [Magnetic Poetry]

Magnetic Poetry uses the DOM-Drag library to support dragging. On initialisation, Drag.init is passed each tile successively. The tiles may only be dragged within the board region, so the container's dimensions are passed in during the initialisation sequence:

    for(i=1; i<=numWords; i++){
      var currentTile = document.getElementById("word_" + i);
      var x1 = parseInt(document.getElementById("board").style.left);
      var x2 =   parseInt(document.getElementById("board").style.width)
               - parseInt(currentTile.style.width) - 6;
      var y1 = parseInt(document.getElementById("board").style.top);
      var y2 =   parseInt(document.getElementById("board").style.height)
               - parseInt(currentTile.style.height) - 6;
      the last 4 args restrict the area that the tile can be dragged in
      Drag.init(currentTile, null, x1, x2, y1, y2);
    }

The initialisation is all you need to support dragging. With the code above, the tiles can now be happily moved around the board space. However, the application does a little more than that: (a) the currently dragged tile is tracked, and (b) an “XMLHttpRequest Call” saves the position once dragging is finished. To that end, onDragStart and onDragEnd handlers are registered on each of the tiles [15]:

    echo 'document.getElementById("word_' . $i . '").onDragStart =
      function(x, y) { dragStart("word_' . $i . '", x, y); };';
    echo 'document.getElementById("word_' . $i . '").onDragEnd =
      function(x, y) { dragEnd("word_' . $i . '", x, y); };';

Alternatives

Separate Editing Interface

The conventional solution has been to provide a visual representation in one region and controls in another. This is often cumbersome and error-prone.

Related Patterns

Drag-And-Drop is often the mechanism used to move “Sprite”s around.

A portal can be personalised by letting the user drag “Portlet”s around.

A “Slider” is a special case of Drag-And-Drop, where the value indicator is dragged along the slider axis.



[15] The Javascript is outputted from a PHP script.

Live Wiki Version for Drag-And-Drop