// IgalleryX: Photo Stack Gallery v2 // RimV: trieuduchien@gmail.com package { // flash libs import caurina.transitions.*; import flash.display.*; import flash.events.*; import flash.geom.Matrix; import flash.geom.Rectangle; import flash.net.URLLoader; import flash.net.URLRequest; import flash.net.navigateToURL; import flash.text.*; import flash.utils.Dictionary; import org.papervision3d.*; import org.papervision3d.cameras.*; import org.papervision3d.materials.*; import org.papervision3d.objects.*; import org.papervision3d.scenes.*; //_________________________________________________Main class public class photoStack extends Sprite { //___________________________________________________________3d vars private var scene:MovieScene3D; private var camera:Camera3D; private var container:Sprite; private var camzoom:Number = 5; //__________________________________________________________XML vars private var xmlLoader:URLLoader = new URLLoader(); private var xmlData:XML = new XML(); private var xml_path:String = "images.xml"; // xml_path //__________________________________________________________Gallery Data private var numphot:Number; // Number of photos private var thumb:Array = new Array(); private var capt:Array = new Array(); private var desc:Array = new Array(); private var link:Array = new Array(); private var img:Array = new Array(); // placement params private var startFrom:Number = 0; // Gallery attribute params block, choose your favourite one by uncomment the corresponding block //----------------------------------------------- Original Cover Flow private var angle:Number = 30; private var distX0:Number = 180; private var distX1:Number = 150; private var distY0:Number = 0; private var distY1:Number = 0; private var distZ0:Number = 700; private var distZ1:Number = 90; //---------------------------------------------- Variation 1 /* private var angle:Number = -30; private var distX0:Number = 180; private var distX1:Number = 180; private var distY0:Number = 0; private var distY1:Number = 0; private var distZ0:Number = 300; private var distZ1:Number = 80; */ //---------------------------------------------- Variation 2 /* private var angle:Number = 0; private var distX0:Number = 180; private var distX1:Number = 100; private var distY0:Number = 0; private var distY1:Number = -30; private var distZ0:Number = 300; private var distZ1:Number = 60; */ //---------------------------------------------- Variation 3 /* private var angle:Number = 0; private var distX0:Number = 180; private var distX1:Number = 100; private var distY0:Number = 0; private var distY1:Number = 30; private var distZ0:Number = 300; private var distZ1:Number = 60; */ //---------------------------------------------- Variation 4 /* private var angle:Number = 0; private var distX0:Number = 180; private var distX1:Number = 100; private var distY0:Number = 0; private var distY1:Number = 0; private var distZ0:Number = 300; private var distZ1:Number = 60; */ // Plane infro private var planeDoubleSide:Boolean = false; private var planeSmooth:Boolean = false; private var quality:Number = 2; // Camera Infor private var COB:Object = new Object(); private var camPos:Object = new Object(); private var camHeight:Number = 0; private var camZ:Number = -400; // Alpha, transparency private var Alpha:Number = 1; // Reflection private var reflection:Boolean = true; // turn on/off reflection private var refDist:Number = 268; //Distance from image to its corresponding reflection private var refIn1:Number = 0.4; // Reflection Intensity 1 private var refIn2:Number = 0; // Reflection Intensity 2 private var refDen1:Number = 0; // Reflection Density 1 private var refDen2:Number = 30; // Reflection Density 2 private var refSmooth:Boolean = false; // Smooth Reflection private var refDoubleSide:Boolean = false; // 2 side Reflection // Tweening infor private var time1:Number = 1.5; private var ease1:String = "easeOutQuint"; private var time2:Number = 1.5; private var ease2:String = "easeOutQuint"; private var ctime:Number = 0.5; //caption tweening duration //misc vars private var cID:Number = 0; // Current pressed photo private var pInfor:Dictionary = new Dictionary(); private var pContainer:Dictionary = new Dictionary(); private var dat:Array = new Array(); private var count:Number = 0; private var tloaded:Number = 0; private var state:Boolean = false; // zoom mode private var z0:Number = 2.0; // position when photo moved near camera private var round:Number = 1; // rounds to rotate // roll over, lift up private var lift:Number = 20; private var liftTime:Number = 1; private var liftEase:String = "easeOutQuint"; // holder vars private var holderY:Number = 0; private var hWidth:Number; private var hHeight:Number; // description vars private var desY:Number = 0; // loader object private var cLoader:Loader = new Loader(); private var first:Boolean = true; // scrollbar vars // //Slider limit, these 2 values indicate the range for the scrubber private var sl1:Number = 25; private var sl2:Number = 505; // StyleSheet private var css:StyleSheet = new StyleSheet(); //___________________________________________________Constructor public function photoStack() { // Block Papervison3D trace output Papervision3D.VERBOSE = false; // Initial 3d environment Init(); // Create 3d gallery Create_gallery(); } private function Init():void { // Align , scale Stage to full fill screen stage.align = StageAlign.TOP_LEFT; stage.scaleMode = StageScaleMode.NO_SCALE; // Reposition element if stage is resized stage.addEventListener( Event.RESIZE, rePosition) //Create container Sprite for scene 3d container = new Sprite(); addChild( container ); container.alpha = 0; container.x = stage.stageWidth * 0.5; container.y = stage.stageHeight * 0.5; // Movie Scene 3D scene = new MovieScene3D( container ); // Camera 3D camera = new Camera3D(); camera.z = camZ; camera.zoom = camzoom; // Camera first position camera.y = camHeight; // temporary remove ~ solve z order issue removeChild(holder); removeChild(des); removeChild(iScroller); removeChild(tooltip); // add loader object to holder holder.addChild(cLoader); hWidth = holder.width; hHeight = holder.height; cLoader.contentLoaderInfo.addEventListener(Event.UNLOAD, unLoadOldAsset); // initialize stylesheet InitDescription(); // reposition element des.x = (stage.stageWidth - des.width) * 2.7 ; des.y = container.y - 100; // reposition caption cap.x = (stage.stageWidth - cap.width) * 0.5 ; cap.y = container.y + 600; cap.alpha = 0; // reposition scrollbar iScroller.x = container.x - 327.5 ; iScroller.y = container.y + 600; // reposition holder holder.x = (stage.stageWidth - hWidth) * 0.5 ; holder.y = container.y + 100; // Setup preloader preloaderMain.x = (stage.stageWidth - preloaderMain.width) * 0.5 ; preloaderMain.y = (stage.stageHeight - preloaderMain.height) * 0.5 ; preloaderMain.process.scaleX = 0; iScroller.alpha = 0; } // Start to build gallery private function Create_gallery():void { // Load data from XML XML_Loading(); //Adding events, renderCamera this.addEventListener(Event.ENTER_FRAME, update3D); } //___________________________________________________________Preloading private function preload(e:Event):void { var preloader = e.target; var bar = preloader.process; bar.scaleX += (count / numphot - bar.scaleX) * 0.1; if (bar.scaleX >= 0.95) { bar.scaleX = 1; //Fade out preloader Tweener.addTween( preloader, { alpha:0, time:1, transition:"easeOutExpo", onComplete:function():void { //remove preloader ~ load complete removeChild(preloader) changeTo(startFrom); // fade in screen, scroller, caption, tooltip Tweener.addTween([container, iScroller, cap], {alpha:1, time:2}); state = true; } }); // remove Enterframe event for preloader preloader.removeEventListener(Event.ENTER_FRAME, preload); } } //__________________________________________________________XML load private function XML_Loading():void { xmlLoader.addEventListener(Event.COMPLETE, LoadXML); xmlLoader.load(new URLRequest( xml_path )); } private function LoadXML(e:Event):void { //Extract data xmlData = new XML(e.target.data); ParseData(xmlData); } private function ParseData(dat:XML):void { //Number of photos numphot = dat.photos.photo.length(); startFrom = Math.round(numphot / 2) - 1; // Calculate data Calculate(); // set up scrollbar setupScrollbar(); // Add Enterframe event for preloader preloaderMain.addEventListener(Event.ENTER_FRAME, preload); for (var i:uint = 0; i < numphot; i++) { thumb[i] = dat.photos.photo.thumb.attributes()[i]; capt[i] = dat.photos.photo.caption.attributes()[i]; desc[i] = dat.photos.photo.desc.text()[i]; link[i] = dat.photos.photo.link.attributes()[i]; img[i] = dat.photos.photo.img.attributes()[i]; } Load_thumbnail(); //first caption cap.text = capt[startFrom]; } //Load external assest private function Load_thumbnail():void { for (var i:uint = 0; i 0) ? (xt + 200) : (xt - 200); Tweener.addTween(pl, {x:xt, time:1.5, transition:"easeOutExpo"}); Tweener.addTween(pl.container, {alpha:0, time:1.5, transition:"easeOutExpo"}); // reflection Tweener.addTween(pl.extra.ref, {x:xt, time:1.5, transition:"easeOutExpo"}); Tweener.addTween(pl.extra.ref.container, {alpha:0, time:1.5, transition:"easeOutExpo"}); } } //fade out scrollbar Tweener.addTween(iScroller, { alpha:0, time:1, onComplete:function():void { iScroller.visible = false; } }); // fade out tooltip Tweener.addTween(tooltip, {alpha:0, time:1, onComplete:function():void {tooltip.visible = false}}); e.target.removeEventListener(MouseEvent.MOUSE_MOVE, moveTooltip); // flipping and load external asset var action:Object = { // rotate 180 rotationY: 180 + round * 360, // move near to camera z: z0, time: time2, transition: ease2, // rotate reflection onUpdate: function():void { p.extra.ref.rotationY = p.rotationY; p.extra.ref.z = p.z; }, // load external asset in holder clip once complete rotating onComplete:function():void { loadAsset(); // fade in holder holder.visible = true; Tweener.addTween(holder, {alpha: 1, time: 1}); // simple ease Back tweening ~ customize your own effect here holder.y -= 20; Tweener.addTween(holder, {y: holderY, time: 1, transition:"easeOutBack"}); // fade in description des.visible = true; des.htmlText = desc[index]; Tweener.addTween(des, {alpha: 1, time: 1}); // simple ease Back tweening ~ customize your own effect here des.y += 20; Tweener.addTween(des, {y: desY, time: 1, transition:"easeOutBack"}); } } Tweener.addTween(p, action); } } // go back to navigation mode private function goBackToMain():void { // retrieve current photo var p = scene.getChildByName("plane" + cID); p.container.addEventListener(MouseEvent.ROLL_OVER, RollOver); p.container.addEventListener(MouseEvent.ROLL_OUT, RollOut); p.container.addEventListener(MouseEvent.MOUSE_DOWN, Press); // turn back to origin var action:Object = { // rotate back rotationY: 0, // move to origin z: 0, time: time2, transition: ease2, // rotate reflection onUpdate: function():void { p.extra.ref.rotationY = p.rotationY; p.extra.ref.z = p.z; } } Tweener.addTween(p, action); // fade out external assest and description // fade out holder Tweener.addTween(holder, {alpha: 0, time: 1}); // simple ease Back tweening ~ customize your own effect here Tweener.addTween(holder, { y: holderY - 20, time: 1, transition:"easeOutQuint", onComplete:function():void { holder.visible = false; } }); // fade out description Tweener.addTween(des, { alpha: 0, time: 1}); // simple ease Back tweening ~ customize your own effect here Tweener.addTween(des, { y: desY + 20, time: 1, transition:"easeOutQuint", onComplete:function():void { des.visible = false; } }); // other photos for (var i:uint = 0; i < numphot; i++) { if (i != cID) { var pl = scene.getChildByName("plane" + i); var container:Sprite = pl.container; container.buttonMode = true; // Roll over, roll out, press event container.addEventListener(MouseEvent.ROLL_OVER, RollOver); container.addEventListener(MouseEvent.ROLL_OUT, RollOut); container.addEventListener(MouseEvent.MOUSE_DOWN, Press); // fade out, seperate xt = pl.x; var xt:Number = (pl.x < 0) ? (xt + 200) : (xt - 200); Tweener.addTween(pl, {x:xt, time:1.5, transition:"easeOutExpo"}); Tweener.addTween(pl.container, {alpha:1, time:1.5, transition:"easeOutExpo"}); // reflection Tweener.addTween(pl.extra.ref, {x:xt, time:1.5, transition:"easeOutExpo"}); Tweener.addTween(pl.extra.ref.container, {alpha:1, time:1.5, transition:"easeOutExpo"}); } } //fade in scrollbar iScroller.visible = true; Tweener.addTween(iScroller, {alpha:1, time:1 }); setupMouseWheel(); } //____________________________________________________________ load external asset: SWF or JPG/PNG/GIF private function loadAsset():void { // visible preloader holder.preloaderClip.visible = true; // unload current data cLoader.unload(); if (first) { first = false; // request link var myURL:URLRequest = new URLRequest(img[cID]); cLoader.load(myURL); cLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, Asset_loaded); } } private function unLoadOldAsset(e:Event):void { // request link var myURL:URLRequest = new URLRequest(img[cID]); cLoader.load(myURL); cLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, Asset_loaded); } private function Asset_loaded(e:Event):void { // invisible preloader holder.preloaderClip.visible = false; cLoader.alpha = 0; // reScale if larger than holder reScale(); cLoader.content.x = (hWidth - cLoader.content.width) * 0.5; cLoader.content.y = (hHeight - cLoader.content.height) * 0.5; // fade in Tweener.addTween(cLoader, {alpha:1, time:2}); } private function reScale():void { var ratio = cLoader.content.width / cLoader.content.height; if (cLoader.content.width > hWidth) { cLoader.content.width = hWidth; cLoader.content.height = hWidth / ratio; }; if (cLoader.content.height > hHeight) { cLoader.content.height = hHeight; cLoader.content.width = ratio * hHeight; } } //______________________________________________________ ChangeTo specified photo private function changeTo(id:Number):void { var p = scene.getChildByName("plane" + id); cID = id; // Tween to center var delta:Number = -p.extra.target; for (var i:uint = 0; i < numphot; i++) { var pl = scene.getChildByName("plane" + i); var target:Number = pl.extra.target + delta; pl.extra.target = target; // tween to target position Tweener.addTween(pl,{ x:dat[target].x, y:dat[target].y, z:dat[target].z, rotationY:dat[target].rotationY, time:time1, transition:ease1, onUpdate:updatePos, onUpdateParams: [pl] }); if (reflection) Tweener.addTween(pl.extra.ref, {y: dat[target].y - refDist, time: time1, transition:ease1 } ) } //simple fading tweening caption Tweener.addTween(cap,{ alpha:0, time:ctime, transition:"easeOutQuint", onComplete:function():void { cap.text = capt[id]; Tweener.addTween(cap,{ alpha:1, time:ctime, transition:"easeOutQuint" }) } } ) } // reposition reflection as tweening private function updatePos(p:Cube):void { if (reflection) { var ref:Plane = p.extra.ref; ref.x = p.x; ref.z = p.z; ref.rotationY = p.rotationY; } } // render 3d private function update3D(e:Event):void { scene.renderCamera( camera ); } //__________________________________________ Apply styleSheet in description field private function InitDescription():void { // load external css var req:URLRequest = new URLRequest("css/styles.css"); var loader:URLLoader = new URLLoader(); loader.load(req); loader.addEventListener(Event.COMPLETE, cssLoaded); // Adding text link event addEventListener(TextEvent.LINK, clickText); // reposition des.x = (stage.stageWidth - des.width) * 0.5 ; des.y = container.y + 140; } private function cssLoaded(e:Event):void { css.parseCSS(e.target.data); des.styleSheet = css; } private function clickText(li:TextEvent):void { if (li.text == "BACK") goBackToMain(); else { var myURL:URLRequest = new URLRequest(li.text); navigateToURL(myURL,"blank"); } } //_______________________________________________________________________ Scroll bar private function setupScrollbar():void { // set up mouse wheel interactive setupMouseWheel(); //Calculate scrubber position iScroller.scrubber.x = startFrom / (numphot - 1) * ( sl2 - sl1 ) + sl1; // add event handler to scrubber iScroller.scrubber.buttonMode = true; iScroller.scrubber.addEventListener(MouseEvent.MOUSE_DOWN, scrubberPress); // click on scrollbar iScroller.bar.buttonMode = true; iScroller.bar.addEventListener(MouseEvent.MOUSE_DOWN, barPress); // iLeft, iRight iScroller.iLeft.buttonMode = true; iScroller.iLeft.addEventListener(MouseEvent.MOUSE_DOWN, iLeftPress); iScroller.iRight.buttonMode = true; iScroller.iRight.addEventListener(MouseEvent.MOUSE_DOWN, iRightPress); } // press scrubber private function scrubberPress(e:MouseEvent):void { // check if release stage.addEventListener(MouseEvent.MOUSE_UP, scrubberRelease); // retrieve scrubber var scrub = iScroller.scrubber; scrub.startDrag(false, new Rectangle(sl1, scrub.y, sl2, scrub.y) ); //Calculate data and show the corresponding photo scrub.addEventListener(MouseEvent.MOUSE_MOVE, scrubberMove); } // release scrubber private function scrubberRelease(e:MouseEvent):void { var scrub = iScroller.scrubber; scrub.stopDrag(); scrub.removeEventListener(MouseEvent.MOUSE_MOVE, scrubberMove); stage.removeEventListener(MouseEvent.MOUSE_UP, scrubberRelease); } // move scrubber private function scrubberMove(e:MouseEvent):void { var scrub = iScroller.scrubber; //temp is next id photo, based on the current position of the scrubber var temp:Number = Math.round((scrub.x - sl1) / (sl2 - sl1) * (numphot - 1)); if (temp < numphot) { //Show the corresponding photo changeTo(temp); cID = temp; } } // bar press private function barPress(e:MouseEvent):void { var bar = iScroller.bar; var scrub = iScroller.scrubber; var pos:Number; if (bar.mouseX >= sl2) pos = sl2; else if (bar.mouseX <= sl1) pos = sl1; else pos = bar.mouseX; Tweener.addTween(scrub, {x: pos, time:1}); //temp is next id photo, based on the current position of the scrubber var temp = Math.round((pos - sl1) / (sl2 - sl1) * (numphot-1)); if (temp < numphot) { //Show the corresponding photo changeTo(temp); cID = temp; } } // iLeft press private function iLeftPress(e:MouseEvent):void { //Decrease or move to end current id if (cID == 0) cID = numphot - 1; else --cID; moveScrubber(); changeTo(cID); } // iRight press private function iRightPress(e:MouseEvent):void { //Increase or move back current id if (cID == numphot-1) cID = 0; else ++cID; moveScrubber(); changeTo(cID); } // reposition scrubber private function rePosScrubber(index:Number):void { //Calculate scrubber position var pos:Number = index / (numphot - 1) * ( sl2 - sl1 ) + sl1; Tweener.addTween(iScroller.scrubber, {x: pos, time:1}); } // easing scrubber private function moveScrubber():void { //Calculate current x position var pos:Number = cID / (numphot - 1) * (sl2 - sl1) + sl1; Tweener.addTween(iScroller.scrubber, {x: pos, time:1}); } // mouseWheel events private function setupMouseWheel():void { stage.addEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); } private function removeMouseWheel():void { stage.removeEventListener(MouseEvent.MOUSE_WHEEL, mouseWheelHandler); } // mouseWheel handler private function mouseWheelHandler(e:MouseEvent):void { var num = Math.round(e.delta / 3); cID += num; if (cID == numphot ) cID = 0; else if (cID == -1) cID = numphot - 1; moveScrubber(); changeTo(cID); } // reposition elements when resize private function rePosition(e:Event):void { container.x = stage.stageWidth * 0.5; container.y = stage.stageHeight * 0.5; // reposition description des.x = (stage.stageWidth - des.width) * 2.7 ; des.y = container.y - 100; // reposition caption cap.x = (stage.stageWidth - cap.width) * 0.5 ; cap.y = container.y + 600; // reposition scrollbar iScroller.x = container.x - 327.5 ; iScroller.y = container.y + 600; // reposition holder holder.x = (stage.stageWidth - hWidth) * 0.5 ; holder.y = container.y - 100; preloaderMain.x = (stage.stageWidth - preloaderMain.width) * 0.5 ; preloaderMain.y = (stage.stageHeight - preloaderMain.height) * 0.5 ; } } }