as3 Scaling Image Gallery

I remember ~5-6 years ago when I decide to make my first flash components using actionscript only, scaling image slideshow was one of them.
I got lots of feedback, comments and after that I start my freelance flash development carrier.
In fact, the slideshows, galleries are the flash elements that I’m using almost in all flash projects/websites, so I think it might be useful to share some code for scaling image gallery.

It’s more like slimbox, shadowbox js image plugins u can see now-days.
Please comment for any additional features, suggestions and bugs. I’ll try to find a time and take a look.

Example(click to the image for the preview-new window):
scgallery_preview

public properties:
[as]
public var easeType : Function
public var transitionDuration : Number
public var fadeDuration : Number
public function set borderColor(pColor : Number) : void
public function get borderColor() : Number
public function set borderThickness(pThickness : Number) : void
public function get borderThickness() : Number
public function set controlsVOffset(pOffset : Number) : void
public function get controlsVOffset() : Number
public function set boundingRect(pArea : Rectangle) : void
public function set slideshowMode(pMode : Boolean) : void
public function get slideshowMode() : Boolean
[/as]

public methods:
[as]
public function nextImage() : void
public function prevImage() : void
public function loadImage(pIndex : uint = 1) : void
public function hide() : void
public function destroy() : void
public function setData(pData : XMLList) : void
public function loadData(pDataLocation : String) : void
[/as]

events:
[as]
ScGallery.TRANSITION_START
ScGallery.TRANSITION_COMPLETE
ScGallery.TRANSITION_UPDATE
ScGallery.LOAD_START
ScGallery.LOAD_COMPLETE
ScGallery.SLIDESHOW_COMPLETE
ScGallery.ON_HIDE
[/as]

ScGallery.as
[as]
package com.abrahamyan.liquid
{
import flash.events.TimerEvent;
import flash.utils.Timer;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.events.MouseEvent;
import flash.text.TextFieldAutoSize;
import flash.display.Bitmap;
import flash.display.Loader;
import flash.net.URLRequest;
import flash.events.IOErrorEvent;
import flash.events.Event;
import flash.net.URLLoader;
import flash.display.SimpleButton;
import flash.display.MovieClip;
import flash.display.Sprite;

import gs.TweenLite;
import gs.easing.*;
import gs.OverwriteManager;

/**
* @author armen abrahamyan | http://abrahamyan.com | armflash (at) gmail.com
* v 1.00
*/
public class ScGallery extends Sprite
{
public static const TRANSITION_START : String = “transition_start”;
public static const TRANSITION_COMPLETE : String = “transition_complete”;
public static const TRANSITION_UPDATE : String = “transition_update”;
public static const LOAD_START : String = “load_start”;
public static const LOAD_COMPLETE : String = “load_complete”;
public static const SLIDESHOW_COMPLETE : String = “slideshow_complete”;
public static const ON_HIDE : String = “on_hide”;
public static const HOR_BORDER_WIDTH : Number = 15;
public static const TOP_BORDER_WIDTH : Number = 30;
public static const BOTTOM_BORDER_WIDTH : Number = 10;
public static const VERT_ITEM_SPACE : Number = 10;
public var easeType : Function = Strong.easeOut;
public var transitionDuration : Number = 1;
public var fadeDuration : Number = .5;
private var _slideshowMode : Boolean;
private var _slideInterval : Number = 2;
private var _controlsVOffset : Number = 100;
private var _borderThickness : Number = 2;
private var _borderColor : Number = 0xcccccc;
private var _border : MovieClip;
private var _prev_btn : MovieClip;
private var _next_btn : MovieClip;
private var _close_btn : SimpleButton;
private var _info_mc : MovieClip;
private var _holder : MovieClip;
private var _bg : MovieClip;
private var _data : XMLList;
private var _dataLength : uint;
private var _dataLoader : URLLoader;
private var _imageLoader : Loader;
private var _circleLoader : MovieClip;
private var _currentIndex : uint;
private var _image : Bitmap;
private var _onResize : Boolean;
private var _onLoad : Boolean;
private var _areaRect : Rectangle;
private var _updateTimer : Timer;

/**
* @param pArea outer rect area
*/
public function ScGallery(pArea : Rectangle = null)
{
init(pArea);
}
/**
* sets border color
* @param pColor
*/
public function set borderColor(pColor : Number) : void
{
_borderColor = pColor;
var transform : ColorTransform = new ColorTransform();
transform.color = _borderColor;
_border.transform.colorTransform = transform;
}
/**
* returns border color
*/
public function get borderColor() : Number
{
return _borderColor;
}
/**
* set border thickness
* @param pThinkness
*/
public function set borderThickness(pThickness : Number) : void
{
_borderThickness = pThickness;
_border.x = _holder.x – _borderThickness;
_border.y = _holder.y – _borderThickness;
}
/**
* returns border thickness
*/
public function get borderThickness() : Number
{
return _borderThickness;
}
/**
* set vertical offset of controls
* @param pOffset
*/
public function set controlsVOffset(pOffset : Number) : void
{
_controlsVOffset = pOffset;
_next_btn.y = _prev_btn.y = _controlsVOffset;
}
/**
* returns controls vertical offset
*/
public function get controlsVOffset() : Number
{
return _controlsVOffset;
}
/**
* sets outer bounding rect, Scgallery will position itself inside bounding rect (center)
* @param pArea
*/
public function set boundingRect(pArea : Rectangle) : void
{
_areaRect = pArea;
this.x = _areaRect.x + (_areaRect.width – this.width) * .5;
this.y = _areaRect.y + (_areaRect.height – this.height) * .5;
_border.x = _holder.x – _borderThickness;
_border.y = _holder.y – _borderThickness;
_border.width = _holder.width + 2 * _borderThickness;
_border.height = _holder.height + 2 * _borderThickness;
}
/**
* sets slideshow mode
* @param pMode
*
*/
public function set slideshowMode(pMode : Boolean) : void
{
_slideshowMode = pMode;
if(_slideshowMode)
{
if(!(_onLoad || _onResize))
{
nextImage();
}
}
else
{
if(_updateTimer)
{
resetUpdateTimer();
}
}
}
/**
* returns slideshow mode
*/
public function get slideshowMode() : Boolean
{
return _slideshowMode;
}
/**
* start loading next image
*/
public function nextImage() : void
{
if(_currentIndex < _dataLength) { loadImage(++_currentIndex); } } /** * start loading prev image */ public function prevImage() : void { if(_currentIndex > 1)
{
loadImage(–_currentIndex);
}
}
/**
* hides ScGallery
*/
public function hide() : void
{
destroy();
TweenLite.to(this, fadeDuration, {alpha:0, onComplete:onFadeOutComplete});
}
/**
* cleanup/remove listeners, use it before deleteing class instance ref
*/
public function destroy() : void
{
_next_btn.removeEventListener(MouseEvent.CLICK, onControlsClick);
_prev_btn.removeEventListener(MouseEvent.CLICK, onControlsClick);
_close_btn.removeEventListener(MouseEvent.CLICK, onControlsClick);
_holder.removeEventListener(MouseEvent.MOUSE_OVER, onHolderOver);
_holder.removeEventListener(MouseEvent.MOUSE_OUT, onHolderOut);
_holder.removeEventListener(MouseEvent.MOUSE_MOVE, onHolderMove);
if(_updateTimer)
{
resetUpdateTimer();
}
}
/**
* when fade out complete dispatchs ON_HIDE event
*/
private function onFadeOutComplete() : void
{
dispatchEvent(new Event(ON_HIDE));
}
/**
* init
*/
private function init(pArea : Rectangle = null) : void
{

_border = this[‘border_mc’];
_prev_btn = this[‘prev_mc’];
_next_btn = this[‘next_mc’];
_close_btn = this[‘close_btn’];
_info_mc = this[‘info_mc’];
_holder = this[‘holder_mc’];
_bg = this[‘bg_mc’];

if(pArea)
{
boundingRect = pArea;
}
controlsVOffset = _controlsVOffset;
borderColor = _borderColor;
_next_btn.buttonMode = _prev_btn.buttonMode = true;

_info_mc.description_txt.autoSize = TextFieldAutoSize.RIGHT;
_next_btn.addEventListener(MouseEvent.CLICK, onControlsClick);
_prev_btn.addEventListener(MouseEvent.CLICK, onControlsClick);
_close_btn.addEventListener(MouseEvent.CLICK, onControlsClick);
_holder.addEventListener(MouseEvent.MOUSE_OVER, onHolderOver);
_holder.addEventListener(MouseEvent.MOUSE_OUT, onHolderOut);

OverwriteManager.init(OverwriteManager.NONE);
}
/**
* on holde rmouseover
*/
private function onHolderOver(event : MouseEvent) : void
{

if(_onLoad || _onResize)
{
return;
}

_holder.addEventListener(MouseEvent.MOUSE_MOVE, onHolderMove);
}
/**
* on holder mouse out
*/
private function onHolderOut(event : MouseEvent) : void
{
if(_holder.hitTestPoint(stage.mouseX, stage.mouseY, true))
{

return;
}
_next_btn.visible = false;
_prev_btn.visible = false;
_holder.removeEventListener(MouseEvent.MOUSE_MOVE, onHolderMove);
}
/**
* onholder mouse move
*/
private function onHolderMove(event : MouseEvent) : void
{
if(event.localX > _holder.width * .5)
{
if(_currentIndex != _dataLength)
_next_btn.visible = true;
_prev_btn.visible = false;
}
else
{

_next_btn.visible = false;
if(_currentIndex != 1)
_prev_btn.visible = true;
}
}
/**
* enable/disable controls
* @param pEnabled
*/
private function enableControls(pEnabled : Boolean = true) : void
{
_next_btn.mouseEnabled = _prev_btn.mouseEnabled = _close_btn.mouseEnabled = pEnabled;
}
/**
* on controls click
*/
private function onControlsClick(event : MouseEvent) : void
{
switch(event.target)
{
case _next_btn:
slideshowMode = false;
nextImage();
break;
case _prev_btn:
slideshowMode = false;
prevImage();
break;
case _close_btn:
hide();
break;
}
_next_btn.visible = false;
_prev_btn.visible = false;
_holder.removeEventListener(MouseEvent.MOUSE_MOVE, onHolderMove);
}
/**
* set data directly, calls build method automatically
* @param pData
*/
public function setData(pData : XMLList) : void
{
_data = pData;
_dataLength = _data.length();

if(_updateTimer)
{
resetUpdateTimer();
}

build();
}
/**
* loads XML data from url, will use setData after load complete
*/
public function loadData(pDataLocation : String) : void
{
_dataLoader = new URLLoader();
_dataLoader.addEventListener(Event.COMPLETE, onDataLoaded);
_dataLoader.addEventListener(IOErrorEvent.IO_ERROR, onDataLoadError);
_dataLoader.load(new URLRequest(pDataLocation));
}
/**
*
*/
private function onDataLoadError(event : IOErrorEvent) : void
{
trace(“XML load error”);
}
/**
* when data is loaded
*/
private function onDataLoaded(event : Event) : void
{
setData(XML(event.target.data).image);
_dataLoader.removeEventListener(Event.COMPLETE, onDataLoaded);
_dataLoader.removeEventListener(IOErrorEvent.IO_ERROR, onDataLoadError);
_dataLoader = null;
}
/**
* shows simple circle loader animation
*/
private function showCircleLoader() : void
{
_circleLoader = new CircleLoader();
_circleLoader.x = _holder.x + _holder.width * .5;
_circleLoader.y = _holder.y + _holder.height * .5;
addChild(_circleLoader);
}
/**
* hides circle laoder
*/
private function hideCircleLoader() : void
{
if(_circleLoader)
{
removeChild(_circleLoader);
_circleLoader = null;
}
}
/**
* loads first image
*/
private function build() : void
{

if(!_areaRect)
{
_areaRect = new Rectangle(0, 0, 800, 800);
}

loadImage();
}
/**
* loads image with pIndex number
* @param pIndex
*/
public function loadImage(pIndex : uint = 1) : void
{
_currentIndex = pIndex;
showCircleLoader();
enableControls(false);
_onLoad = true;
_info_mc.alpha = 0;
_info_mc.visible = false;
_close_btn.visible = false;
_close_btn.alpha = 0;
_holder.alpha = 0;
_border.alpha = 0;
_next_btn.visible = _prev_btn.visible = false;

_imageLoader = new Loader();
_imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onImageLoaded);
_imageLoader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onImageLoadError);

_imageLoader.load(new URLRequest(_data[_currentIndex – 1].@src.toString()));
dispatchEvent(new Event(LOAD_START));
}
/**
*
*/
private function onImageLoadError(event : IOErrorEvent) : void
{
_imageLoader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onImageLoadError);
trace(“image load error”);
}
/**
* when image is loaded
*/
private function onImageLoaded(event : Event) : void
{
_imageLoader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onImageLoadError);
_imageLoader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onImageLoaded);
if(_holder.numChildren > 0)
_holder.removeChildAt(0);

hideCircleLoader();
_image = _imageLoader.content as Bitmap;
_imageLoader = null;
//
_border.width = _image.width + 2 * _borderThickness;
_border.height = _image.height + 2 * _borderThickness;
_info_mc.y = TOP_BORDER_WIDTH + _image.height + VERT_ITEM_SPACE;
_info_mc.title_txt.width = _image.width;
_info_mc.description_txt.width = _image.width;
_info_mc.count_txt.width = _image.width;
_info_mc.title_txt.text = _data[_currentIndex – 1].title.toString();

_info_mc.description_txt.text = _data[_currentIndex – 1].description.toString();
_info_mc.count_txt.y = _info_mc.description_txt.y + _info_mc.description_txt.textHeight + VERT_ITEM_SPACE;
_info_mc.count_txt.text = “img ” + _currentIndex + ” / ” + _dataLength;
_close_btn.x = HOR_BORDER_WIDTH + _image.width – _close_btn.width;
_next_btn.x = HOR_BORDER_WIDTH + _image.width – _next_btn.width;
dispatchEvent(new Event(LOAD_COMPLETE));
resize();
_onLoad = false;

}
/**
* resize
*/
private function resize() : void
{
_onResize = true;
dispatchEvent(new Event(TRANSITION_START));
TweenLite.to(_bg, transitionDuration, {width:_image.width + 2 * HOR_BORDER_WIDTH, height:_image.height + TOP_BORDER_WIDTH + VERT_ITEM_SPACE + BOTTOM_BORDER_WIDTH + _info_mc.height, ease:easeType, onComplete:onResizeComplete, onUpdate:onResizeUpdate});
}
/**
* resize is in process
*/
private function onResizeUpdate() : void
{
this.x = _areaRect.x + (_areaRect.width – _bg.width) * .5;
this.y = _areaRect.y + (_areaRect.height – _bg.height) * .5;
dispatchEvent(new Event(TRANSITION_UPDATE));
}
/**
* when resize complete
*/
private function onResizeComplete() : void
{
this.x = Math.round(this.x);
this.y = Math.round(this.y);
_holder.addChild(_image);

TweenLite.to(_holder, fadeDuration, {alpha:1, onComplete:onFadeComplete});
TweenLite.to(_border, fadeDuration, { alpha:1});
TweenLite.to(_info_mc, fadeDuration, {autoAlpha:1});
TweenLite.to(_close_btn, fadeDuration, {autoAlpha:1});
_onResize = false;
}
/**
* when fade in complete
*/
private function onFadeComplete() : void
{
enableControls();
dispatchEvent(new Event(TRANSITION_COMPLETE));
if(_slideshowMode)
{
if(_currentIndex == _dataLength )
{
slideshowMode = false;
dispatchEvent(new Event(SLIDESHOW_COMPLETE));
return;
}
_updateTimer = new Timer(_slideInterval * 1000, 1);
_updateTimer.addEventListener(TimerEvent.TIMER_COMPLETE, onSlideTimerComplete);
_updateTimer.start();
}
}
/**
* on slideshow timer complete
*/
private function onSlideTimerComplete(event : TimerEvent) : void
{
resetUpdateTimer();
nextImage();
}
/**
* reset timer
*/
private function resetUpdateTimer() : void
{

_updateTimer.removeEventListener(TimerEvent.TIMER_COMPLETE, onSlideTimerComplete);
_updateTimer = null;
}
}
}

[/as]

how to use:
copy slideshow folder from FLA files library to ur FLA’s library.
copy gs and com folders (with sub folders) to the same directory as ur FLA file, or copy anywhere else and include them in ur FLA files class path.
use xml provided in example as a template to describe data for your Scgallery:
[xml]



title 1
description1


title 2
description 2description 2 description 2description 2description 2description 2description 2description 2description 2 description 2 description 2description 2description 2description 2description 2description 2description 2 end


title 3
description3


title 4
description4


[/xml]

In the FLA file or in your document class call ScGallery as here:
[as]
import flash.geom.Rectangle;
import com.abrahamyan.liquid.ScGallery;
import flash.display.MovieClip;
var _gallery:ScGallery;
_gallery =new ScGallery(new Rectangle(0,0,800,600));
addChild(_gallery);
_gallery.loadData(“xml/data.xml”);
[/as]

Download source files

6 thoughts on “as3 Scaling Image Gallery

  1. F2nd

    Excellent gallery, Armen and something to learn from. I can’t find anything I don’t like, maybe just some design tweaks like semi-transparent navigation arrows, but functionality is just fine.

  2. Jinjaninja

    Awesome post. Made my day much simpler. Your attention to detail with your commenting is superb makes it crystal clear what’s happening when. Keep up the good work.

  3. Everin

    Very nice work Abraham.

    To implement category, draw to buttons (or 1000) and on key frame one:

    /////// remove all //////////

    addEventListener(Event.ENTER_FRAME,myEnterFrame);
    function myEnterFrame(event:Event) {
    if ( _gallery ){
    _gallery.removeEventListener(ScGallery.ON_HIDE, onGalleryHide);
    removeChild(_gallery);
    _gallery =null;
    }
    }
    ////////////// end remove all /////////////////

    /////////////// buttons //////////

    unu_btn.buttonMode = true;
    unu_btn.addEventListener(MouseEvent.CLICK, Load_Gallery);

    function Load_Gallery(event : MouseEvent) : void {

    removeEventListener(Event.ENTER_FRAME,myEnterFrame); // STOP THIS LISTENER
    _gallery =new ScGallery(new Rectangle(0,0,800,600));
    _gallery.addEventListener(ScGallery.ON_HIDE, onGalleryHide);
    addChild(_gallery);
    _gallery.loadData(“xml/portraits.xml”);

    }
    // repetate the code for button two //

    doi_btn.buttonMode = true;
    doi_btn.addEventListener(MouseEvent.CLICK, Load_Gallery2);

    function Load_Gallery2(event : MouseEvent) : void {
    removeEventListener(Event.ENTER_FRAME,myEnterFrame); // STOP THIS LISTENER
    _gallery =new ScGallery(new Rectangle(0,0,800,600));
    _gallery.addEventListener(ScGallery.ON_HIDE, onGalleryHide);
    addChild(_gallery);
    _gallery.loadData(“xml/data.xml”);

    }
    ///////////////////////////////////////////////////////////////

    Duplicate the data.xml and rename it for each buttons, is pretty self explanatory.

    Have a nice day,

  4. alex

    You saved my life with this gallery. Thanks a lot Armen.

    I just need a tiny help. Is it possible to open the gallery in a specific image like having a thumb menu and opening the gal with that selected image? is it???

    Thanks a lot man.

  5. armen

    @alex, I believe “public function loadImage(pIndex : uint = 1) : void” is what u are looking for.

    if that will not help, u can add inside ScGallery.as:
    public var defIndex:Number=1;
    and change inside build() method: loadImage(defIndex);

    When u start gallery u can change that variable:
    _gallery = new ScGallery(new Rectangle(0,0,800,600));
    _gallery.defIndex =3;
    after that gallery will start from 3 th image.
    thx

Leave a Reply

Your email address will not be published. Required fields are marked *