Are simultaneous mouseover and mousemove events possible?

Discussion in 'Javascript' started by JB, Mar 17, 2006.

  1. JB

    JB Guest

    I am struggling to figure out a way to allow one element
    to be dragged, but still capture 'mouseover' events on
    other elements.

    I've created a simple example to demonstrate what I mean:
    http://gerromorpha.cs.uoregon.edu/moveAndOver.html
    (The above link is only meant for Windows/Firefox.)

    It's not much code, but it's probably too much to paste here.
    The gist of it is, when a user clicks on element #1, I attach
    the mousemove event to element #1. That event remains
    attached until the user un-clicks (mouseup). During the time
    the user is dragging element #1, however, element #2 doesn't
    register the mouseover events it should.

    Any ideas on how to get around this? If I should be approaching
    this in a completely different way I would appreciate some
    alternatives. Any response, for that matter, will be greatly
    appreciated.
     
    JB, Mar 17, 2006
    #1
    1. Advertising

  2. JB

    Martyr2 Guest

    You know, I was working on this very thing a couple weeks ago to
    implement classic drag and drop. Luckily for you I have explored this
    issue extensively and can save you hours of researching by telling you
    what I found out.

    The short of it all, you can't. Both IE and FF just don't allow it
    right now. What you do need is a collusion function which will tell you
    when one item (the item you are dragging) has collided (is over)
    another element. When the two elements collide, you can call a function
    which will give you the same effect as mouseover on the second element.

    I got this off a guy here on the forums, and even though it is a bit
    unreadable, it works like a charm and allows me to do the drag and drop
    I need.

    hitTest = function(o, l){
    function getOffset(o){
    for(var r = {l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth,
    b: o.offsetHeight};
    o = o.offsetParent; r.l += o.offsetLeft, r.t +=
    o.offsetTop);


    return r.r += r.l, r.b += r.t, r;
    }
    for(var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j
    ? l = [l] : l).length; i;
    b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r :
    b.l <= a.r))
    && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) &&
    (r[r.length] = l));
    return j ? !!r.length : r;
    };

    Use: hitTest(obj1,obj2)
    Description: Returns true and false if the reference to obj1 and obj2
    overlap or "collided".

    You would put this in your mousemove event within an if statement. If
    it is true, call the function you want to call as if it was in a
    mouseover of the second element.

    Good luck! :)
     
    Martyr2, Mar 18, 2006
    #2
    1. Advertising

  3. JB

    VK Guest

    JB wrote:
    > I am struggling to figure out a way to allow one element
    > to be dragged, but still capture 'mouseover' events on
    > other elements.
    >
    > I've created a simple example to demonstrate what I mean:
    > http://gerromorpha.cs.uoregon.edu/moveAndOver.html
    > (The above link is only meant for Windows/Firefox.)


    In addition to the previous answer:

    It should be clear that the problem is *not* that mouse events are not
    reaching div2. Events are going Russian hills (down to bottom and up to
    high) in Firefox and Bubble way (from the bottom to high) in IE, and
    nothing is changed while dragging. As your current drag script is
    vulnerable to the "drag off the body" trick, you can see it yourself
    (and would be nice to fix it in the release of course). Start dragging
    div1 to the menu bar until it stops. Release button an return mouse to
    the screen. div1 is still in dragging mode but doesn't move (you may
    need to repeat this by changing the return path for the mouse to get
    this). Now if you move your mouse over div2, the mouseover event will
    be properly captured.

    So the problem is not in event capturing, but in the fact that while
    dragging the mouse is not over div2 - it is over div1. div1 is over
    div2 - that's true, but there is no handler like onDiv1Over to capture
    :)

    So you need to use coords rectangle check as suggested for FF and
    others. For IE it is enough to use the native
    document.elementFromPoint(x,y) method.
     
    VK, Mar 18, 2006
    #3
  4. JB

    JB Guest

    Wow. That is some serious abuse of for-loops.
    It does seem to mostly work. I have translated
    it into more readable code and I will post it here
    for future reference.

    I am not sure I understand exactly what's going on,
    but I think if obj2 (in my translated code) is a single
    object, it's converted into a single-element array.
    Otherwise, if the user passed an array of objects,
    hitTest() detect collisions with all the elements in
    that array. I have tried sending the function an
    array of objects but I couldn't get it to work.

    hitTest = function(obj1, obj2){
    function getOffset(obj){
    var objBounds = {
    objLeft: obj.offsetLeft,
    objTop: obj.offsetTop,
    objRight: obj.offsetWidth,
    objBottom: obj.offsetHeight
    };

    for( ; obj = obj.offsetParent; )
    {
    objBounds.objLeft += obj.offsetLeft;
    objBounds.objTop += obj.offsetTop;
    }

    objBounds.objRight += objBounds.objLeft
    objBounds.objBottom += objBounds.objTop

    return objBounds;
    }

    var obj2Bounds
    var collisionArray = [];
    var obj1Bounds = getOffset(obj1);

    // My guess:
    // If obj2 is a single object, convert it to a single
    // element array. Now that obj2 is definitely an
    // array, set i to the length of that array
    var j = isNaN(obj2.length);
    var i = (j ? obj2 = [obj2] : obj2).length

    for(; i; )
    {
    obj2Bounds = getOffset(obj2[--i])

    if ( (obj1Bounds.objLeft == obj2Bounds.objLeft ||
    (obj1Bounds.objLeft > obj2Bounds.objLeft ?
    obj1Bounds.objLeft <= obj2Bounds.objRight :
    obj2Bounds.objLeft <= obj1Bounds.objRight))
    && (obj1Bounds.objTop == obj2Bounds.objTop ||
    (obj1Bounds.objTop > obj2Bounds.objTop ?
    obj1Bounds.objTop <= obj2Bounds.objBottom :
    obj2Bounds.objTop <= obj1Bounds.objBottom)))
    {
    collisionArray[collisionArray.length] = obj2;
    }
    }

    // My guess:
    // if obj2 is a single object and it collides with obj1,
    // collisionArray.length == 1 so !!collisionArray.length == true
    // if obj2 is an array of objects, return an array of
    // the subset of obj2 objects with which obj1 collidess
    return j ? !!collisionArray.length : collisionArray;
    };


    Thanks for your post, you saved me a lot of pain.



    Martyr2 wrote:
    > You know, I was working on this very thing a couple weeks ago to
    > implement classic drag and drop. Luckily for you I have explored this
    > issue extensively and can save you hours of researching by telling you
    > what I found out.
    >
    > The short of it all, you can't. Both IE and FF just don't allow it
    > right now. What you do need is a collusion function which will tell you
    > when one item (the item you are dragging) has collided (is over)
    > another element. When the two elements collide, you can call a function
    > which will give you the same effect as mouseover on the second element.
    >
    > I got this off a guy here on the forums, and even though it is a bit
    > unreadable, it works like a charm and allows me to do the drag and drop
    > I need.
    >
    > hitTest = function(o, l){
    > function getOffset(o){
    > for(var r = {l: o.offsetLeft, t: o.offsetTop, r: o.offsetWidth,
    > b: o.offsetHeight};
    > o = o.offsetParent; r.l += o.offsetLeft, r.t +=
    > o.offsetTop);
    >
    >
    > return r.r += r.l, r.b += r.t, r;
    > }
    > for(var b, s, r = [], a = getOffset(o), j = isNaN(l.length), i = (j
    > ? l = [l] : l).length; i;
    > b = getOffset(l[--i]), (a.l == b.l || (a.l > b.l ? a.l <= b.r :
    > b.l <= a.r))
    > && (a.t == b.t || (a.t > b.t ? a.t <= b.b : b.t <= a.b)) &&
    > (r[r.length] = l));
    > return j ? !!r.length : r;
    > };
    >
    > Use: hitTest(obj1,obj2)
    > Description: Returns true and false if the reference to obj1 and obj2
    > overlap or "collided".
    >
    > You would put this in your mousemove event within an if statement. If
    > it is true, call the function you want to call as if it was in a
    > mouseover of the second element.
    >
    > Good luck! :)
     
    JB, Mar 19, 2006
    #4
  5. JB

    JB Guest

    > So the problem is not in event capturing, but in the fact that while
    > dragging the mouse is not over div2 - it is over div1. div1 is over
    > div2 - that's true, but there is no handler like onDiv1Over to capture


    That makes perfect sense. I feel stupid for not thinking of that.

    Thanks for your reply.
     
    JB, Mar 19, 2006
    #5
  6. JB

    RobG Guest

    JB said on 20/03/2006 7:24 AM AEST:
    > Wow. That is some serious abuse of for-loops.
    > It does seem to mostly work. I have translated
    > it into more readable code and I will post it here
    > for future reference.


    I've done a similar thing by creating a object that contains 'drop
    zones'. As you drag one element, you see if it's over a drop zone. By
    storing the co-ords of each drop-zone (and updating them if/when they
    move) the algorithm for seeing if the dragged element is 'over' a drop
    zone is much faster than finding the co-ords from scratch every time.

    If you have a lot of drop zones, give them a key based on their
    co-ordinates. Then keep the keys in an array and use either a btree or
    quadtree search to find 'hits'. That will allow you to keep track of
    hundreds of drop zones without too much processing overhead.


    [...]


    --
    Rob
     
    RobG, Mar 20, 2006
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. George Ter-Saakov
    Replies:
    0
    Views:
    956
    George Ter-Saakov
    Jun 24, 2003
  2. Microsoft Newsserver
    Replies:
    7
    Views:
    1,423
    swati agrawal
    Nov 19, 2008
  3. clarket

    JavaScript MouseOver events and Anchors

    clarket, Jun 2, 2005, in forum: Javascript
    Replies:
    2
    Views:
    108
    Michael Winter
    Jun 2, 2005
  4. Jakub Åukomski

    mousemove for overlapping divs

    Jakub Åukomski, Jun 12, 2006, in forum: Javascript
    Replies:
    2
    Views:
    117
    Jakub Åukomski
    Jun 13, 2006
  5. Robert
    Replies:
    0
    Views:
    122
    Robert
    May 8, 2007
Loading...

Share This Page