Hello group, I'm trying to accomplish a behaviour where multiple draggables cannot overlap, i.e. you can drag them around freely, but they "snap" to each other's borders so that you cannot place one draggable over another. I've come close to a solution, but it's only 95% what I'd like to have and it seems overly complicated to me.
The solution I've come up with so far is to grab each element already dropped into my droppable, read its offsets and save it as a range. Then, when you drag around one element, it checks for the saved ranges if an overlap occurs on any axis. If yes, it sets the x or y coordinate outside of the not-dragged element's boundaries. Or at least that what it should do. The problem is, I cannot distinguish between if the dragged element should be placed atop/below or left/right of the immobile one. More specifically, I don't know if the direction of the drag is in the X or in the Y-axis. Let me try some obscure ASCII art: Direction bottom -> top: .-----. | fix | '-----' .-----. | ^^^ | '-----' Direction right -> left: .-----. | fix |.-----. '-----'| <<< | '-----' Outcome: .-----. | .-|---. '---|-' | '-----' On both occasions, when the elements finally overlaps the fixed element, its top value AND its left value are inside the "ranges" of the fixed element, without knowing what axis should be limited. Move it to the bottom? Move it to the right? As you can see below, the function to determine wether the element is within the boundaries of another seems clunky and complicated, so I was hoping for a thought provoking impulse on how to solve that last puzlle, or maybe even a new way to approach this with lesser effort. I've fiddled around with Position.overlap and Position.within, but both are deemed deprecated (what is the proper way then now?), and this approach also suffered from the same indistinguishability (did I just write this?). This is my code so far. Stripped and ripped out of its class. ** HTML ** <div id='container'> <div class='dragme'>Item 1</div> <div class='dragme'>Item 2</div> <div class='dragme'>Item 3</div> </div> <div id='target'></div> ** JavaScript ** var container = $('container'); var dropTarget = $('target'); var taken = new Array(); var curEleDims = {}; var dropBorder = 2; var drags = container.select('div.dragme'); drags.each(function(ele) { new Draggable(ele, { revert: 'failure', ghosting: false, onStart: initializeDrag }); }); Droppables.add(container, {accept: 'dragme', onDrop: moveDropped }); // Set options at begin of drag initializeDrag = function(drag) { // If already within dropTarget if (drag.element.parentNode.id == dropTarget.id) { taken = new Array(); // Clear Array // Every element already dropped dropTarget.childElements().each(function(ele) { // Ignore current element (the drag itself) if (drag.element.id !== ele.id) { var dims, oSet, x1, x2, y1, y2; dims = ele.getDimensions(); // Get dimensions oSet = ele.positionedOffset(); // For Range x1 = oSet.left; x2 = oSet.left + dims.width; // Left & Right y1 = oSet.top; y2 = oSet.top + dims.height; // Top & Bottom taken.push([$R(x1, x2, false), $R(y1, y2, false)]); } }); drag.options.snap = snap; // Limit Snap curEleDims = drag.element.getDimensions(); // Dimensions of current element } } // Drop a draggable moveDropped = function(drag, drop) { // Container => drop target if (drag.parentNode.id == container.id && drop.id == dropTarget.id) { // Convert to position: absolute and change offset accordingly // Needed when dropTarget has a border, else drag "jumps" on release drag.absolutize(); var offTotalPar = drop.cumulativeOffset(); var offTotalEle = drag.cumulativeOffset(); // Include 2x 2px border drag.setStyle({ top: offTotalEle.top -offTotalPar.top -dropBorder*2+'px', left: offTotalEle.left-offTotalPar.left-dropBorder*2+'px' }); // Insert to new element on drop drop.insert(drag); } } // Snap within borders of dropTarget and no overlap between elements snap = function(x,y,draggable) { var nx, ny, takenXX, takenYY, curXX, curYY; // Limit to the boundaries of dropTarget only /* // already working [...] */ // Limit taking into account already dropped elements // Ranges for current element curXX = $R(x, x+curEleDims.width, false); // Left & Right curYY = $R(y, y+curEleDims.height, false); // Top & Bottom // Coordinates already occupied? taken.each(function(xyVal) { // For each dropped element var x1, x2, y1, y2; // Ranges for an element already dragged and dropped takenXX = xyVal[0]; // Left & Right takenYY = xyVal[1]; // Top & Bottom x1 = x; // Left x2 = x + curEleDims.width); // Right y1 = y; // Top y2 = y + curEleDims.height; // Bottom // Point of view is the currently dragged element var left_side, right_side, left_top, left_btm, right_top, right_btm; left_side = (takenXX.include(x1) && && ((takenYY.include(y1) && takenYY.include(y2)) || (curYY.include(takenYY.start) && curYY.include(takenYY.end))) ) ? true : false; right_side = (takenXX.include(x2) && ((takenYY.include(y1) && takenYY.include(y2)) || (curYY.include(takenYY.start) && curYY.include(takenYY.end))) ) ? true : false; left_top = (takenYY.include(y1) && (takenXX.include(x1) || (curXX.include(takenXX.start))) ) ? true : false; left_btm = (takenYY.include(y2) && (takenXX.include(x1) || (curXX.include(takenXX.start))) ) ? true : false; right_top = (takenYY.include(y1) && (takenXX.include(x2) || (curXX.include(takenXX.end))) ) ? true : false; right_btm = (takenYY.include(y2) && (takenXX.include(x2) || (curXX.include(takenXX.end))) ) ? true : false; switch (true) { // Place at right end case left_side: x = takenXX.end; break; // Place at left end case right_side: x = takenXX.start-curEleDims.width; break; // Place at bottom (or left?) case left_top: y = takenYY.end; break; // Place at top (or left?) case left_btm: y = takenYY.start-curEleDims.height; break; // Place at bottom (or right?) case right_top: y = takenYY.end; break; // Place at top (or right?) case right_btm: y = takenYY.start-curEleDims.height; break; } if (left_side || right_side || left_top || left_btm || right_top || right_btm) return; // No need to proceed further }); return [x,y]; } --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Prototype & script.aculo.us" group. To post to this group, send email to prototype-scriptaculous@googlegroups.com To unsubscribe from this group, send email to [EMAIL PROTECTED] For more options, visit this group at http://groups.google.com/group/prototype-scriptaculous?hl=en -~----------~----~----~----~------~----~------~--~---