|
Just to prove JavaScript can do many things beyond what you've learned so far, here is a final example. Although desktop operating systems support drag-and-drop actions (for example, moving a file into the trash can), web pages have traditionally lacked this feature. Using JavaScript and the DOM, you can unobtrusively create objects that the user can pick up, drag, and drop.
Did you Know?
This is a simple implementation of drag-and-drop. Full-featured dragging and dropping leads to a very complex script. Fortunately, you can use JavaScript libraries such as Script.aculo.us to add drag-and-drop to your pages without any scripting. See Hour 8, "Using Built-in Functions and Libraries," for more details.
The HTML document for this example exists mainly to define four draggable objects with <div> tags. Listing 24.1 shows the complete HTML document.
Listing 24.1. The HTML Document for the Drag-and-Drop Example
<html>
<head>
<title>Drag and Drop</title>
<link rel="stylesheet" type="text/css" href="dragdrop.css">
<script language="javascript" type="text/javascript"
src="dragdrop.js">
</script>
</head>
<body>
<h1>Drag and Drop in JavaScript</h1>
<div class="drag" id="drag1">
<h3>Box #1</h3>
<p>Click one of these boxes and hold the
mouse button down to move it to a new location.</p>
</div>
<div class="drag" id="drag2">
<h3>Box #2</h3>
<p>This is another box you can drag and drop.</p>
</div>
<div class="drag" id="drag3">
<h3>Box #3</h3>
<p>This is yet another box you can drag and drop.</p>
</div>
<div class="drag" id="drag4">
<h3>Box #4</h3>
<p>This is the fourth and final draggable box.</p>
</div>
</body>
</html>
|
Each of the <div> tags with the class="drag" attribute will be a draggable object. The document also includes a <script> tag to attach a script and a <link> tag for a style sheet.
The style sheet sets up the four positionable objects with an initial position as well as a distinctive border. Listing 24.2 shows the CSS file for this example.
Listing 24.2. The CSS File for the Drag-and-Drop Example
.drag {
position: absolute;
width: 150px;
border: 2px solid black;
border-top: 20px solid black;
top: 100px;
padding: 5px;
}
#drag1 { left: 20px; }
#drag2 { left: 190px; }
#drag3 { left: 360px; }
#drag4 { left: 530px; }
|
The position: absolute rule makes the elements positionable. The top property sets the vertical position of all four elements, and the left property is set for each one to space them across the page. The width and border properties make the <div> elements look like boxes, and the border-top property creates a thick top border for dragging.
Save this file as dragdrop.css in the same folder as the HTML document. If you load the HTML document into a browser at this point, you can see the styled boxes, but they won't be movable until you add the script. Figure 24.1 shows this example before adding the script.
Because drag-and-drop isn't built in to the DOM, your script will have to do it the hard way. When the user clicks on an element, an onmousedown event handler will begin dragging the object. After that starts, an onmousemove event handler will update the object's position, and onmousedown will "drop" the object.
One tricky part is determining the mouse position in the onmousemove event handler. This is stored as a property of the event object, but Netscape and Firefox use the pageX and pageY properties, whereas Internet Explorer uses the clientX and clientY properties. A series of if statements finds the x and y values, regardless of the browser:
if (!e) var e = window.event;
if (e.pageX) {
x = e.pageX;
y = e.pageY;
} else if (e.clientX) {
x = e.clientX;
y = e.clientY;
} else return;
By the Way
See Hour 9, "Responding to Events," for more information on event handlers and the event object.
One more issue: Objects are positioned based on their top-left corner, but you can click anywhere on the object with the mouse. This will result in a "jump" effect when you pick up an object. The solution is to calculate an offset between the mouse position and the object's position:
dx = x - obj.offsetLeft;
dy = y - obj.offsetTop;
When the object is moved, these offsets will be subtracted from the mouse position. This way, the object is anchored to the mouse pointer wherever you click it, and does not jump to a new position.
Now all you need is the JavaScript file to add the drag-and-drop feature to the document. Listing 24.3 shows the complete script.
Listing 24.3. The JavaScript File for the Drag-and-Drop Example
// global variables
var obj,x,y,dx,dy;
// set up draggable elements
function Setup() {
// exit if the browser doesn't support the DOM
if (!document.getElementsByTagName) return;
divs = document.getElementsByTagName("DIV");
for (i=0; i<divs.length; i++) {
if (divs[i].className != "drag") continue;
// set event handler for each div with class="drag"
divs[i].onmousedown = Drag;
}
}
function Drag(e) {
// Start dragging an object
if (!e) var e = window.event;
// which object was clicked?
obj = (e.target) ? e.target: e.srcElement;
obj.style.borderColor="red";
// calculate object offsets from mouse position
dx = x - obj.offsetLeft;
dy = y - obj.offsetTop;
}
function Move(e) {
// track mouse movements
if (!e) var e = window.event;
if (e.pageX) {
x = e.pageX;
y = e.pageY;
} else if (e.clientX) {
x = e.clientX;
y = e.clientY;
} else return;
if (obj) {
obj.style.left = x - dx;
obj.style.top = y - dy;
}
}
function Drop() {
// let go!
if (!obj) return;
obj.style.borderColor="black";
obj = false;
}
// Detect mouse movement
document.onmousemove = Move;
// drop current object on mouse up
document.onmouseup = Drop;
// Set up when the page loads
window.onload = Setup;
|
Here's a rundown of how this script works:
The first line declares five global variables: obj to keep track of the current object being dragged, x and y for the mouse position, and dx and dy for the object's offset from the mouse position. The Setup() function runs when the page loads. This function uses getElementsByTagName to find all of the <div> elements in the page. For each one with the class="drag" attribute, it sets up an onmousedown event handler to call the Drag() function. The Drag() function sets obj to the correct object, sets the object's border color to red to indicate it's being dragged, and calculates the dx and dy offsets. The Move() function is where the action happens. After calculating the mouse pointer's x and y position, it sets the object's left and top properties to move it to follow the mouse. The Drop() function ends the process by setting the object's border color back to black, and then setting obj to false, so mouse movements won't move any object. The final lines set some global event handlers: onmousemove to call the Move() function, onmouseup to call the Drop() function, and onload to call Setup().
Save this file as dragdrop.js. To try the example, make sure you have all three files in the same folder: the HTML document, the CSS file (dragdrop.css), and the JavaScript file (dragdrop.js). Load the HTML document into a browser. Figure 24.2 shows the example after all four objects have been dragged to new positions.
|