
Please update your flash player
In this experiment, you can drag the boxes; when you release them the stack will shuffle to accommodate the dropped box.
I have recently been working on building an application in which I wanted to use Photoshop style ‘layers’ which the user could create, drag onto different depths and delete.
The basic idea was for the user to click and drag ‘layers’, and drop them in between others. This would cause the other layers to reposition to accommodate the new layer and to fill the gap which it had left in it’s old position. Get it?
Perhaps I’m just a bit dim, but I was surprised at how many difficulties I encountered when trying to sort the boxes or ‘layers’. I began taking the approach of calculating whether the surrounding layers were above or below, and moving them up or down accordingly; but with this approach I found that deleting layers or adding new ones caused the system to go a bit crazy.
As usual, it was the simple and elegant approach which eventually yielded the solution. I basically handled all of the movement from a single, straightforward array. The array was shuffled based on a nifty little prototype I wrote for extracting and reinserting elements (essentially shuffling without randomness), from which all movement calculations (i.e. the eventual positions of the shuffling boxes) could be made.
Array.prototype.shuffle = function (x, y) { var i:Number = this.slice (x, x + 1); this.splice (x,1); this.splice (y,0,i); };
The shuffle prototype itself could be very useful, as it pulls items out of the array, and by reinserting them; muscles the other elements outwards around it – no complicated calculations needed for determining where the elements go thanks to some really basic build in Flash Actionscript features. Also, by omitting one line of code, the prototype could be used to simply insert items into an array at a particular position (insertAt(value, index) or something along those lines).
I have attached a bare bones example for you, though I assure you, you can do great things with this script. The menu I was working on will probably make an appearance on Soulwire once the program is finished. One example of its usage would be to associate each box with a layer elsewhere; for example a Stack of photos which are depth ‘shuffled’ through the easy manipulation of their affiliated boxes.
You can download the FLA here, but here is the basic commented code. It is simple but works quite well.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 | // Include the Zigo tweening prototypes to make life easier #include "lmc_tween.as" // Create the main holder for the boxes var menu:MovieClip = this.createEmptyMovieClip ("menu", 0); menu._x = menu._y = 20; // Set up our Arrays and counters var boxes:Array = new Array (); var boxCount:Number = 0; var boxGap:Number = 37; /* The core 'SHUFFLE' function This pulls out an array item at a given index and inserts it back into the array at another index. The other array items are consiquently 'pushed' outwards from the element, so our new array reflects the visual appearance we want for the shuffled menu. We can now 'sort' our menu based on this modified array... */ Array.prototype.shuffle = function (x, y) { var i:Number = this.slice (x, x + 1); this.splice (x,1); this.splice (y,0,i); }; // Our sort function function sort () { var count:Number = boxes.length; for (var i = 0; i < count; i++) { // Check which ID is at this point in the array var id:Number = boxes[i]; // Find the corrosponding box var box:MovieClip = eval ("menu.box" + id); // Calculate the position the box should be at var y:Number = i * boxGap; // Alter it's id to it's new position box.id = i; // Tween it there (or just use box._y = y) box.tween ("_y",y,0.8,"easeInOut"); } } // Creating new boxes function addBox () { /* We use getNextHighestDepth() because of the swapDepths() function used when the buttons are pressed. This creates new levels and so could cause problems if we just create boxes at depths based on the length of the boxes array. */ var d:Number = menu.getNextHighestDepth (); var i:Number = boxCount; // We could use Push(), but I want the boxes stacked, with newest on top boxes.unshift (i); // Attach the box var box:MovieClip = menu.attachMovie ("box", "box" + i, d); // Initiate the box box.initBox (i); // Increase the counter boxCount++; // Sort the boxes sort (); } /* This is a simple function which can be called to remove boxes. It splices the array and resorts the stack accordingly. */ function deleteLayer (id) { var box:MovieClip = eval ("menu.box" + boxes[id]); box.removeMovieClip (); boxes.splice (id,1); sort (); } // The box actions MovieClip.prototype.initBox = function (num) { this.id = num; this.name.text = "Box " + num; this.onPress = function () { var top:Number = boxCount + 1; this.swapDepths (top); this.startDrag (); }; this.onRelease = this.onReleaseOutside = function () { this.stopDrag (); // Slide back to the edge this.tween ("_x",0,0.8,"easeInOut"); /* Find the original position, and the new position, based on the location of the draged box in relation to the other boxes. */ var x:Number = this.id; var y:Number = Math.round (this._y / boxGap); // Call our shuffle function based on these calculations boxes.shuffle (x,y); // Sort the boxes based on our shuffled array sort (); }; }; // Add some boxes to test it! for (var i = 0; i < 5; i++) { addBox (); } |
One Response to Dynamic stacking
James Henley
Apr 13th 2007
8:55 am
This is cool! What about side by side boxes as well as virtical, like in a grid?
Leave a Reply