when draging a <div>, how can I detect what I'm moving over?

K

Kevin Blount

I'm playing with dragable <DIV>s, being inspired by google.com/ig,
where you can move items on the page around and have items you move
over change position if necessary.

I have 3 div's setup, one for each dragable item (boxes about
100x150px), inside another div that sets up a border.

my script is instigated by an onMouseOver event and works great for
moving items, setting the opacity, etc. The only trouble is (and I
guess I should have expected this) is that when I'm dragging one div,
the onMouseOver events for the other 2 divs are not initialized. In
retrospect that's probably a good thing, or I'd end up dragging
everything at the same time.

What I'm looking for is an idea where to go next in order to find out
what I'm dragging a div over. I purposely didn't include any code as
I'm really looking for just hints rather than solutions, as this
project is very much a learning excercise for myself, and I've already
cheated enough by downloading dom-drag.js as the base code.

any ideas how I can find out what I'm dragging over? My thoughts were
listeners (though I don't know much about them but they seemed to make
sense here) or not worrying about what I'm over, but more where I am in
the list and then work out if something needs to be move or not (seems
cumbersome and potentially a resource hog while I check mouse movements
and positions while dragging)

any hints and/or tips would be appreciated.
 
T

Thomas 'PointedEars' Lahn

Kevin said:
What I'm looking for is an idea where to go next in order to find out
what I'm dragging a div over. I purposely didn't include any code as
I'm really looking for just hints rather than solutions, as this
project is very much a learning excercise for myself, and I've already
cheated enough by downloading dom-drag.js as the base code.

I really like your attitude :) However, it does not hurt to
read source code of others, instead it helps you to understand
to write it yourself, and probably better.

Look into the `ondragover' event handler for IE:

<http://msdn.microsoft.com/workshop/author/dhtml/reference/events/ondragover.asp>

I don't know if it is supported in the Gecko DOM as well, probably
not as the reference does not mention it. However, there are the
onmouse* event handlers which could be and are probably used for this.

<http://developer.mozilla.org/en/docs/DOM:element#Event_Handlers>


HTH

PointedEars
 
K

Kevin Blount

thanks for the response.. I'll definitely check out the ondragover..
sounds ideal (though no clue exactly what it does yet <g>), and thanks
for the DOM references too.
 
A

Aaron Gray

I really like your attitude :) However, it does not hurt to
read source code of others, instead it helps you to understand
to write it yourself, and probably better.

Its a pritty tough act to follow, very criptic, I've tried three times to
look at it so far.

Anyone got a JavaScript reformatter or pritty printer of any kind ?

I'll have another butchers at it at some point.

Aaron
 
T

Thomas 'PointedEars' Lahn

Aaron Gray wrote:

Please provide proper attribution.
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
Its a pritty tough act to follow, very criptic, I've tried three times to
look at it so far.

Anyone got a JavaScript reformatter or pritty printer of any kind ?

When Pretty Printing is needed, I use the Format feature of the JavaScript
Editor PlugIn for Eclipse from <http://sourceforge.net/projects/jseditor/>.

IIRC Macromedia Dreamweaver MX also includes such a feature and probably
many other JS editors.


PointedEars
 
J

John Talbot

Very good link, this. Plenty of ideas there one can take. I'm still
trying to figure out though how it detects which dropzone you're over.
 
R

RobG

John said:
Very good link, this. Plenty of ideas there one can take. I'm still
trying to figure out though how it detects which dropzone you're over.

When dragging, the position of the cursor is monitored and the
coordinates used to move the element being dragged and to and see if the
cursor is over a drop-zone.

Search for _updateDropZonesHover.

The function loops through all the dropzones and uses
_mousePointInDropZone to determine if the cursor is over a particular
drop zone.

The algorithm is not optimal - if there are lots of drop zones,
performance will degrade significantly. A better algorithm is to load
the drop zones into a btree or (better) a quadtree and just keep track
of the ones the cursor is over.

It may not make any difference for a small number of zones.

The demos at the link do not work properly in IE if it isn't
full-screen. If you are going to manually track what the cursor is
over, you have a lot of work ahead and it will likely only work in a
small subset of browsers.

A small plaything:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">
<html>
<head><title>Drag Drop simple</title>
<meta http-equiv="Content-Type"
content="text/html; charset=ISO-8859-1">
<style type="text/css">
body {margin:0;padding:0;}
..dropZone {width:100px;height:100px;border:2px solid blue;}
#dropZone-01 {position:absolute;top:100px;left:200px;}
#dropZone-02 {border-color:red;}
</style>

<script type="text/javascript">

var DragDrop = ( function() {
var docBody = document.body || document.documentElement;
var dZoneIndex = []; // References to drop zones

function dropZone(el){
this.el = el;
this.coords = getElRect(el);
}

function registerDZ(el){
dZoneIndex[dZoneIndex.length] = new dropZone(el);
}

function getElOffset(el){
var elXY = [0,0];
if (el.offsetParent) {
while (el.offsetParent) {
elXY[0] += el.offsetLeft;
elXY[1] += el.offsetTop;
el = el.offsetParent;
}
} else if (el.x){
elXY[0] = el.x;
elXY[1] = el.y;
}
return elXY;
}

function getElRect(el){
var pos = getElOffset(el);
pos[2] = pos[0] + el.offsetHeight;
pos[3] = pos[1] + el.offsetWidth;
return pos;
}

function cursorPos(e){
var e = e || window.event;
var posXY = [0,0];
if (e.pageX || e.pageY) {
posXY[0] += e.pageX;
posXY[1] += e.pageY;
} else if (e.clientX || e.clientY){
posXY[0] += e.clientX + document.body.scrollLeft;
posXY[1] += e.clientY + document.body.scrollTop;
}
return posXY;
}

function trackCursor(e){
var e = e || window.event;
var posXY = cursorPos(e);
var dz;
for (var i=0, n=dZoneIndex.length; i<n; ++i){
dz = dZoneIndex;
if ( pointInRect(posXY, dz.coords) ) {
dz.el.innerHTML = 'over';
dz.outline && (dz.outline.style.display = '');
} else {
dz.el.innerHTML = 'out';
dz.outline && (dz.outline.style.display = 'none');
}
}
}

function pointInRect(pos, rect){
return (
pos[0] > rect[0] && pos[0] < rect[2]
&& pos[1] > rect[1] && pos[1] < rect[3] );
}

return ({

registerZonesByClassname : function(cName){
var allEls = document.getElementsByTagName('*');
var el, i = allEls.length;
while (i--){
el = allEls;
if (el.className && el.className == cName){
registerDZ(el);
}
}
},

startTrackCursor : function() {
docBody.onmousemove = trackCursor;
},

stopTrackCursor : function() {
if (/\btrackCursor\b/.test(docBody.onmousemove)){
docBody.onmousemove = null;
}
var dz, i=0;
while( (dz = dZoneIndex[i++]) ){
dz.el.innerHTML = '';
}
},

showDropZones : function() {
var dz, i=0;
while( (dz = dZoneIndex[i++]) ){
dz.el.innerHTML += '<br>' + dz.coords;
}
}
});
})();


</script>


</head>

<body onload="
DragDrop.registerZonesByClassname('dropZone');
">
<input type="button" value="Start Track cursor" onclick="
DragDrop.startTrackCursor();
">

<input type="button" value="Stop track cursor" onclick="
DragDrop.stopTrackCursor();
">
<input type="button" value="Show zones" onclick="
DragDrop.showDropZones();
">
<div class="dropZone" id="dropZone-01"></div>
<div class="dropZone" id="dropZone-02"></div>
</body>
</html>
 
K

Kevin Blount

re4:Aaron - thanks for the link to that example. It looks just what I
need to rip apart for clues :)

re4: RobG - and thanks for pointing out the part to look for, and for
the example of mouse tracking
 
K

Kevin Blount

RobG: just to let you know, and anyone else that wants to use this
incredibly useful example, I found a small bug in the code above.

I made some change for testing, putting dropzone 1 directly above
dropzone 2, as you might see in a websites side menu. When the width
and height were the same (100px in your code) this works perfectly, but
if I increased the width to 150px (height still at 100px) then it was
possible to have both dropzones as 'over' when the cursor was hoving
around the top of dropzone 2.

I found the fix in the function below:

function getElRect(el){
var pos = getElOffset(el);
pos[2] = pos[0] + el.offsetHeight;
pos[3] = pos[1] + el.offsetWidth;
return pos;
}

I had to transpose offsetHeight and offsetWidth to get the right
results, i.e.

function getElRect(el){
var pos = getElOffset(el);
pos[2] = pos[0] + el.offsetWidth;
pos[3] = pos[1] + el.offsetHeight;
return pos;
}

I hope you don't mind me pointing this out publically. I personally
found this example to be extremely useful, and would definitely
recommend people come here if they are trying to do what I'm working
on, and figured they should know about this too.

cheers
 
R

RobG

Kevin said:
RobG: just to let you know, and anyone else that wants to use this
incredibly useful example, I found a small bug in the code above.

I made some change for testing, putting dropzone 1 directly above
dropzone 2, as you might see in a websites side menu. When the width
and height were the same (100px in your code) this works perfectly, but
if I increased the width to 150px (height still at 100px) then it was
possible to have both dropzones as 'over' when the cursor was hoving
around the top of dropzone 2.

I found the fix in the function below:

function getElRect(el){
var pos = getElOffset(el);
pos[2] = pos[0] + el.offsetHeight;
pos[3] = pos[1] + el.offsetWidth;
return pos;
}

I had to transpose offsetHeight and offsetWidth to get the right
results, i.e.

function getElRect(el){
var pos = getElOffset(el);
pos[2] = pos[0] + el.offsetWidth;
pos[3] = pos[1] + el.offsetHeight;
return pos;
}

I hope you don't mind me pointing this out publically.

Eeee gad - me, a mistake? Aggghh!! Crikey, *that* has never happened
before!! :=x

I posted it, so I'll happily cop consequences.

I hadn't tested with non-square shapes (but I have now). The use of an
array makes it much more likely that such a mistake would be made, an
object is probably more appropriate (I'm not using any of an array's
specialness) so slap-my-wrist.

An object with named properties would be less prone to such error (but
not foolproof):

function getElRect(el){
var elTL = getElOffset(el);
var elRect = {left:elTL.x, top:elTL.y, bottom:0, right:0};
elRect.right = elRect.left + el.offsetWidth;
elRect.bottom = elRect.top + el.offsetHeight;
return elRect;
}


With appropriate changes to other bits as well.

[...]
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,436
Messages
2,571,696
Members
48,796
Latest member
Greg L.
Top