05/06/07

Permalink 07:24:29 pm, by robertc Email , 723 words, 4418 views   English (UK)
Categories: Web Design Share on reddit Share on digg Share on del.icio.us Share on ma.gnolia.com Share on StumbleUpon

Scriptaculous Draggable and Z-index

I was building a prototype today using the Scriptaculous Draggable object. It was a fairly simple idea, a set of 'items' along the top of the page which could be dragged onto a selection of timeslots below, the idea being that by dragging the item to the timeslot you are 'booking' the item for that timeslot. Obviously in the real application this would have to link back to a database and do all sorts of complex stuff, but for now I just wanted to mockup how the UI would work.

I started off aiming to get the basic functionality working and not worrying too much about design. The Scriptaculous stuff is easy to use, I set up my items and timeslots as div elements and gave them a class name, then in my initialisation function used getElementsByClassName to get an array of elements to which I could apply the behaviour:

var els = $('available').getElementsByClassName('cat');
for (var i=0; i<els.length; i++) {
    new Draggable(els[i],{revert: true});
}

The droppable bit was a bit more complicated as I added event handler functions for onHover and onDrop:

var els = $('times').getElementsByClassName('slot');
for (var i=0; i<els.length; i++) {
    Droppables.add(els[i],{accept: 'cat', onDrop: catchDrop, onHover: showCatch } );
}

My catchDrop handler inserts an item into the booking slot, or increments the number of that item if one or more is already booked, though initially I just popped up an alert to confirm everything worked as expected. The showCatch handler changes the background colour of the element when a draggable is moved over it. I tried using Effect.Highlight initially, but it didn't interact well with the drag and drop stuff - if you tried to add an item to the bottom booking slot, all of the slots above became highlighted as well. So I settled for changing the background colour and used a brute force approach of removing the background colour from all the other elements before applying to the current one. Here is what I'd got so far.

With the basic functionality working I set about styling the page with CSS. I envisaged a 'toolbar' of items across the top with an 'Outlook style' collection of timeslots below. Since, in the actual application, there could be any number of items, I made the toolbar a fixed height and width and set it to scroll along the x axis:

#available {
    width: 100%;
    height: 64px;
    overflow-x: scroll;
    overflow-y: hidden;
}

This had an unfortunate side effect, however. Now when I dragged my items down onto the booking slots they were hidden behind the slots, and this looked a bit stupid. I did some experimenting with z-index for the various elements involved, but didn't have much joy - I got it sort of working in IE but that 'solution' hid all the booking slots in Firefox, so I resorted to Google. The first thing I learned was that Scriptaculous sets the z-index of the draggable element to 1000 - so clearly that shouldn't be the problem. Next, I wondered if the float: left I'd applied to the draggable elements somehow interfered with the the z-index, which led me to an article, with an excellent example, on the Mozilla developer site. This was useful information, and clearly floating does have some effect but it looked like it wasn't what was causing my problem. Finally I came across a CSS-d wiki article on z-index stacking context. Although I'm sure I haven't fully understood the article yet, this seemed to be the problem - the draggable elements were now in a different stacking context to the droppable elements, and this is why my z-index experiments weren't working. This got me to the root of the problem - if it worked fine before any CSS was involved, then something in my CSS was messing with the stacking context. Commenting the rules out one by one soon revealed the culprit - overflow-x creates a new stacking context (or at least, has an equivalent effect) in Firefox, whereas it seems IE's broken z-index handling was what allowed me to end up with something which worked there.

Rather than delve even deeper into the mysteries of z-index I chickened out and did the page without the overflow, it's only a mockup after all (which is also why it's only been tested in Firefox and IE7, before anyone starts complaining :) )

Technorati tags for this post:

Trackback address for this post:

http://www.boogdesign.com/b2evo/th1srv/trackback.php/193

Comments, Trackbacks, Pingbacks:

Comment from: Henry [Visitor] Email
This link to z-index stacking context stated that making the element positioned absolute has a nice effect. So to get the draggable dragging outside the overflow div, I made these 2 changes in dragdrop.js:

1) After "startDrag: function(event) {", add "this.element.style.position = 'absolute'; "

2) After "finishDrag: function(event, success) {", add "this.element.style.position = 'static'; "

Thanks for your article.
PermalinkPermalink 04/09/07 @ 09:20
Comment from: Anon [Visitor] Email
I assume you never found a solution to this?
PermalinkPermalink 13/05/08 @ 17:47
Comment from: robertc [Member] Email · http://www.boogdesign.com/
I've not gone back to it yet, though that may be happening in the next few weeks. Did you try Henry's solution?

Rob
PermalinkPermalink 14/05/08 @ 00:41
Comment from: John R [Visitor] Email · http://www.maxpower.plus.com
I've tried Henry's mod. It works - but has side effects which render it useless. In my case - it doesn't put the draggables in the right place once complete.

I tested in FF3 Beta 5
PermalinkPermalink 27/05/08 @ 14:37
Comment from: Andy [Visitor] Email · http://householder-yogi.net
Here's a possible solution (note - if you're manually cloning the dragged element to copy it into your Droppable, you'll need to set position:'relative' on the cloned element otherwise it will have position:'absolute').


new Draggable(asanaId,{revert:true
,onStart: function(drgObj,mouseEvent){
drgObj.element.style.position='absolute'
}
,onEnd: function(drgObj,mouseEvent) {
drgObj.element.style.position='relative'
}
});
PermalinkPermalink 06/07/08 @ 07:39
Comment from: Andy [Visitor] Email · http://householder-yogi.net
On addition - offset must be zeroed because of the position change to absolute...

,onStart: function(drgObj,mouseEvent){
drgObj.element.setStyle({'position':'absolute',width:'30%'})
drgObj.offset=[0,0]
}
PermalinkPermalink 06/07/08 @ 08:41

Leave a comment:

Your email address will not be displayed on this site.
Your URL will be displayed.

Allowed XHTML tags: <p, ul, ol, li, dl, dt, dd, address, blockquote, ins, del, span, bdo, br, em, strong, dfn, code, samp, kdb, var, cite, abbr, acronym, q, sub, sup, tt, i, b, big, small>
(Line breaks become <br />)
(Set cookies for name, email and url)
(Allow users to contact you through a message form (your email will NOT be displayed.))

Hot Topics

    Popular

    boogdesign posts

    Longer posts on standards based web design, portable web development and Linux, intermingled with some stuff on my other nerd interests.

    Search

    Syndicate this blog XML

    • RSS 0.92 Posts RSS 0.92 Comments
    • RSS 1.0 Posts RSS 1.0 Comments
    • RSS 2.0 Posts RSS 2.0 Comments
    • Atom Posts Atom Comments
    What is RSS?

    License info

    Creative Commons License
    This work is licensed under a Creative Commons Attribution-Share Alike 2.5 License.

    powered by
    b2evolution

    get hCard