Drag and drop scripts are entirely based around the mouse events. Just as you can capture keyboard events, you can capture mouse events like onMouseDown, onMouseUp, and onMouseMove. For each of these, you can obtain the location of the mouse and use those coordinates to move a layer. This lesson will show step by step how to make one layer draggable. The next lesson will show how to make any number of layers draggable with a generic Drag Object.
Each of onMouseDown, onMouseUp, and onMouseMove are initialized the same way. Here's the set up I like to use:
function init() { // called from BODY onLoad document.onmousedown = mouseDown document.onmousemove = mouseMove document.onmouseup = mouseUp if (ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { } function mouseMove(e) { } function mouseUp(e) { }
The function names can be whatever you want, but I find it easiest to understand by using just mouseDown(e), mouseMove(e), and mouseUp(e).
For Netscape, the "e's" in each function represent the built-in Event object. It is how it will obtain the location of the mouse:
var x = e.pageX var y = e.pageY
IE will ignore the e's because it uses a slightly different system for capturing mouse events. In IE, the window contains a event object which you can access using window.event (which is synonymouse with just event). The window.event object contains the properties x and y which represent the location of where the mouse event occured:
var x = event.x var y = event.y
Revision: Before I did not take into account scrolling in IE, read the following to correct this issue.
To be specific those values reflect where in IE's browser window the mouse event occured - it does not necessarily relect where on the document has been clicked. If you scroll down the window.event.y value isn't in synch with the document, so we have to account for that discrepency ourselves. You add the amount that the document has been scrolled by using document.body.scrollTop.
var x = event.x+document.body.scrollLeft var y = event.y+document.body.scrollTop
You can then put the code for both browsers into one small chunk of code:
if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop}
Those lines can then be inserted into each of the mouse functions:
function mouseDown(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} } function mouseMove(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} } function mouseUp(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} }
Now when any of the events occur we can work with the x and y variables (the current location of the mouse) and do some neat things with them.
In Netscape, problems occur when you click the right mouse button - it interfers with the drag and drop process, so I usually like to do to a check of which mouse button was clicked by using e.which - (1) means that the left button was clicked:
function mouseDown(e) { if ((ns4 && e.which == 1) || ie4) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} } }
Right now we're going to do a very simple action - when someone clicks the mouse, move a layer to the same location as the mouse. First we need to initialize a layer (I'll use the old pointer variable method):
if (ns4) { dragObj = document.squareDiv dragObj.xpos = dragObj.left dragObj.ypos = dragObj.top } if (ie4) { dragObj = squareDiv.style dragObj.xpos = dragObj.pixelLeft dragObj.ypos = dragObj.pixelTop }
For this lesson, the DIV tag will look like this:
<STYLE TYPE="text/css"> <!-- #squareDiv {position:absolute; left:100; top:100; width:50; height:50; clip:rect(0,50,50,0); background-color:blue; layer-background-color:blue;} --> </STYLE> <DIV ID="squareDiv"></DIV>
Then in the mouseDown() function we can use the x and y variables to move the layer to those values:
function mouseDown(e) { if ((ns4 && e.which == 1) || ie4) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} dragObj.xpos = x dragObj.ypos = y dragObj.left = dragObj.xpos dragObj.top = dragObj.ypos } }
Also, just for fun, I'm going to show the location of the mouse in the status bar:
function mouseMove(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} status = "x:"+x+" y:"+y }
View dragdrop1.html to see this example
Unlike mouseDown() and mouseUp(), the mouseMove() function is always active whenever the mouse is moved. But we don't always want to do things when we move the mouse. In the case of drag and drop, we only want to do something after we click something. To have more control over the mouseMove event we can use an active variable like dragActive:
dragActive = false // initially it is not active
Then in the mouseDown() function, instead of moving the layer to the location of the mouse, I'm going to just set the mouseMoveActive variable to 1 (true):
function mouseDown(e) { if ((ns4 && e.which == 1) || ie4) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} dragActive = true } }
Then I'm going to let mouseMove do all the work. I'll make it so that each time the mouse is moved, the layer is going to move to where the mouse is:
function mouseMove(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} status = "x:"+x+" y:"+y if (dragActive) { dragObj.xpos = x dragObj.ypos = y dragObj.left = dragObj.xpos dragObj.top = dragObj.ypos return false } }
I added one extra command - return false. This is very important - it is to avoid a Netscape problem which occurs when you want to put an image in the CSS-layer. If you don't have return false the drag and drop action gets broken.
View dragdrop2.html to see this example
In that last example, there's no way to "drop" the square once we've clicked. To change that I'm going to use mouseUp to set the mouseMoveActive variable to 0 which will disable the mouseMove action:
function mouseUp(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} dragActive = false }
Another thing we can do to make the script better is change how we move the layer in the mouseMove() function. Instead of moving the layer directly to where the layer is, we can change it so that the layer is moved according to where on the layer the mouse was clicked.
So in the mouseDown() function we'll have to capture the difference between where the mouse was clicked and the location of the layer:
function mouseDown(e) { if ((ns4 && e.which == 1) || ie4) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} dragClickX = x-dragObj.xpos dragClickY = y-dragObj.ypos dragActive = true } }
Then the mouseMove() function can be updated to include these values when we move the layer:
function mouseMove(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} if (dragActive) { dragObj.xpos = x-dragClickX dragObj.ypos = y-dragClickY dragObj.left = dragObj.xpos dragObj.top = dragObj.ypos return false } }
View dragdrop3.html to view see example
We're pretty close now. The only fault in the script is that we never determine when to activate the drag and drop sequence. Right now it always drags no matter where on the screen we click. The usual functionality is that you only drag the layer when you've clicked directly on top of it. You can determine if you've clicked on the layer by doing another check in the mouseDown function.
The most common way to approach this is to compare the location of mouse with the location of the layer. You need to obtain each edge of the layer (left, right, top, and bottom). The left and top are easy - dragObj.left and dragObj.top respectively. But for the right and bottom we have to take into consideration the width and height of the layer.
We can easily tack on a few more properties to our pointer variables capture the width and height of the layer.
In Netscape, the width and height are based on the clip width and clip height values:
document.layername.clip.width document.layername.clip.height
In IE, you have to use pixelWidth and pixelHeight
layername.style.pixelWidth layername.style.pixelHeight
So our initialization code can be altered to include these values in the properties w and h:
if (ns4) { dragObj = document.squareDiv dragObj.xpos = dragObj.left dragObj.ypos = dragObj.top dragObj.w = dragObj.clip.width dragObj.h = dragObj.clip.width } if (ie4) { dragObj = squareDiv.style dragObj.xpos = dragObj.pixelLeft dragObj.ypos = dragObj.pixelTop dragObj.w = dragObj.pixelWidth dragObj.h = dragObj.pixelHeight }
So using each of these properties we can set up one big "if" statement to check if the user has clicked within the boundaries of our layer:
if (x>=dragObj.xpos && x<=dragObj.xpos+dragObj.w && y>=dragObj.ypos && y<=dragObj.ypos+dragObj.h) {
This line is inserted into the mouseDown() function to make sure that we activate the drag sequence only when the layer is clicked:
function mouseDown(e) { if ((ns4 && e.which == 1) || ie4) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} if (x>=dragObj.xpos && x<=dragObj.xpos+dragObj.w && y>=dragObj.ypos && y<=dragObj.ypos+dragObj.h) { dragClickX = x-dragObj.xpos dragClickY = y-dragObj.ypos dragActive = true return false } } }
You must put a return false in the onMouseDown when the drag sequence is started. This will avoid problems on the Mac. Since Mac's have one butten, Netscape will pop up a command list when the mouse button is held. By returning false it cancels that event.
// Drag and Drop Script // Copyright 1998 Dan Steinman // Available at the Dynamic Duo (http://www.dansteinman.com/dynduo/) // May 21, 1998. // In order to use this code you must keep this disclaimer ns4 = (document.layers)? true:false ie4 = (document.all)? true:false function init() { if (ns4) { dragObj = document.squareDiv dragObj.xpos = dragObj.left dragObj.ypos = dragObj.top dragObj.w = dragObj.clip.width dragObj.h = dragObj.clip.width } if (ie4) { dragObj = squareDiv.style dragObj.xpos = dragObj.pixelLeft dragObj.ypos = dragObj.pixelTop dragObj.w = dragObj.pixelWidth dragObj.h = dragObj.pixelHeight } dragActive = false document.onmousedown = mouseDown document.onmousemove = mouseMove document.onmouseup = mouseUp if (ns4) document.captureEvents(Event.MOUSEDOWN | Event.MOUSEMOVE | Event.MOUSEUP) } function mouseDown(e) { if ((ns4 && e.which == 1) || ie4) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} if (x>=dragObj.xpos && x<=dragObj.xpos+dragObj.w && y>=dragObj.ypos && y<=dragObj.ypos+dragObj.h) { dragClickX = x-dragObj.xpos dragClickY = y-dragObj.ypos dragActive = true return false } } } function mouseMove(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} if (dragActive) { dragObj.xpos = x-dragClickX dragObj.ypos = y-dragClickY dragObj.left = dragObj.xpos dragObj.top = dragObj.ypos return false } } function mouseUp(e) { if (ns4) {var x=e.pageX; var y=e.pageY} if (ie4) {var x=event.x; var y=event.y+document.body.scrollTop} dragActive = false }
View dragdrop4.html to see the complete drag and drop example
Home | Next Lesson: Drag Object |