Jump to content
Search Community

Image thumb scroller with GreenSock Loader to point to swf instead of jpg [Attacmnts]

ngrinchenko test
Moderator Tag

Recommended Posts

I hope it is not too much over my head as I would like to make it work. Some time ago I recieved help in constracting an interactive image thumb scroller using greensock features.

My biggest problem at the moment is that I can not figure out how to change the code so the thumbs would bring up the swf files and not jpg files. In other words my small thumbnails are small jpg files (as they were intended to be), but my bigger visuals (the ones which are being brought by clicking on the small thumbnails) I would like to change to an swf file (as it contains its separate animation and additional set of buttons)

Here is the original code I am trying to modify:

package {
import com.greensock.TweenLite;
import com.greensock.events.LoaderEvent;
import com.greensock.loading.ImageLoader;
import com.greensock.loading.LoaderMax;
import com.greensock.loading.XMLLoader;
import com.greensock.plugins.AutoAlphaPlugin;
import com.greensock.plugins.ColorTransformPlugin;
import com.greensock.plugins.GlowFilterPlugin;
import com.greensock.plugins.TweenPlugin;

import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;


public class SlideshowExample extends MovieClip {
private static const _THUMB_WIDTH:Number = 100;
private static const _THUMB_HEIGHT:Number = 64;
private static const _IMAGE_WIDTH:Number = 550;
private static const _IMAGE_HEIGHT:Number = 355;
private static const _THUMB_GAP:Number = 4;
private static const _SCROLL_SPEED:Number = 12;
private static const _SCROLL_AREA:Number = 150;

private var _progressBar:MovieClip;
private var _arrowLeft:MovieClip;
private var _arrowRight:MovieClip;

private var _slides:Array;
private var _curSlide:Slide; //Slide that is currently displaying
private var _loadingSlide:Slide; //only used when a Slide is supposed to show but hasn't been fully loaded yet (like if the user clicks "next" many times before all the images have loaded). We keep track of the one that's in the process of loading and should be shown as soon as it finishes, then we set _loadingSlide back to null.
private var _imagesContainer:Sprite; //the Sprite into which the full-size images are placed (this helps manage the stacking order so that the images can always be behind everything else and yet we can addChild() each image so that it shows up on top of the previous one)
private var _thumbnailsContainer:Sprite; //the Sprite into which the thumbnail images are placed. This also allows us to slide them all at the same time.
private var _destScrollX:Number = 0; //destination x value for the _thumbnailsContainer which is used for scrolling it across the bottom. We don't want to use _thumbnailsContainer.x because it could be in the process of tweening, so we keep track of the end/destination value and add/subtract from it when creating our tweens.
private var _minScrollX:Number; //we know the maximum x value for _thumbnailsContainer is 0, but the mimimum value will depend on how many thumbnail images it contains (the total width). We calculate it in the _setupThumbnails() method and store it here for easier/faster scrolling calculations in the _enterFrameHandler()

public function SlideshowExample() {
super();

//activate the plugins that we'll be using so that TweenLite can tween special properties like filters, colorTransform, and do autoAlpha fades.
TweenPlugin.activate([AutoAlphaPlugin, ColorTransformPlugin, GlowFilterPlugin]);

_progressBar = this.getChildByName("progress_mc") as MovieClip;
_arrowLeft = this.getChildByName("arrowLeft_mc") as MovieClip;
_arrowRight = this.getChildByName("arrowRight_mc") as MovieClip;

_arrowLeft.visible = _arrowRight.visible = false;
_imagesContainer = new Sprite();
this.addChildAt(_imagesContainer, 0);

_thumbnailsContainer = new Sprite();
addChild(_thumbnailsContainer);
_thumbnailsContainer.y = _IMAGE_HEIGHT;
_thumbnailsContainer.alpha = 0; //we want alpha 0 initially because we'll fade it in later when the thumbnails load.
_thumbnailsContainer.visible = false; //ensures nothing is clickable.

var xmlLoader:XMLLoader = new XMLLoader("assets/data.xml", {onComplete:_xmlCompleteHandler});
xmlLoader.load();
}

private function _xmlCompleteHandler(event:LoaderEvent):void {
_slides = [];
var xml:XML = event.target.content; //the XMLLoader's "content" is the XML that was loaded.
var imageList:XMLList = xml.image; //In the XML, we have <image /> nodes with all the info we need.
//loop through each <image /> node and create a Slide object for each.
for each (var image:XML in imageList) {
_slides.push( new Slide(image.@name,
	 image.@description,
	 new ImageLoader("assets/thumbnails/" + image.@name + ".jpg", {name:image.@name + "Thumb", width:_THUMB_WIDTH, height:_THUMB_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:13000, onFail:_imageFailHandler}),
	 new ImageLoader("assets/images/" + image.@name + ".jpg", {name:image.@name + "Image", width:_IMAGE_WIDTH, height:_IMAGE_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:820000, onFail:_imageFailHandler})
	 )
 );
}

//now create a LoaderMax queue and populate it with all the thumbnail ImageLoaders as well as the very first full-size ImageLoader. We don't want to show anything until the thumbnails are done loading as well as the first full-size one. After that, we'll create another LoaderMax queue containing the rest of the full-size images that will load silently in the background.
var initialLoadQueue:LoaderMax = new LoaderMax({onComplete:_initialLoadComplete, onprogress:_progressHandler});
for (var i:int = 0; i < _slides.length; i++) {
initialLoadQueue.append( _slides[i].thumbnailLoader );
}
initialLoadQueue.append(_slides[0].imageLoader); //make sure the very first full-sized image is loaded initially too.
initialLoadQueue.load();

_setupThumbnails();
}

private function _initialLoadComplete(event:LoaderEvent):void {
//now that the initial load is complete, fade out the progressBar. autoAlpha will automatically set visible to false once alpha hits 0.
TweenLite.to(_progressBar, 0.5, {autoAlpha:0});
//fade in the thumbnails container
TweenLite.to(_thumbnailsContainer, 1, {autoAlpha:1});
_setupArrows();
//setup the ENTER_FRAME listeners that controls the thumbnail scrolling behavior at the bottom
this.stage.addEventListener(Event.ENTER_FRAME, _enterFrameHandler, false, 0, true);

//now put all the remaining images into a LoaderMax queue that will load them one-at-a-time in the background in the proper order. This can greatly improve the user's experience compared to loading them on demand which forces the user to wait while the next image loads.
var imagesQueue:LoaderMax = new LoaderMax({maxConnections:1});
for (var i:int = 1; i < _slides.length; i++) {
imagesQueue.append( _slides[i].imageLoader );
}
imagesQueue.load();

//now start the slideshow
_showNext(null);
}

//loops through all the thumbnail images and places them in the proper order across the bottom of the screen and adds CLICK_THUMBNAIL listeners.
private function _setupThumbnails():void {
var l:int = _slides.length;
var curX:Number = _THUMB_GAP;
for (var i:int = 0; i < l; i++) {
var thumbnail:Sprite = _slides[i].thumbnail;
_thumbnailsContainer.addChild(thumbnail);
TweenLite.to(thumbnail, 0, {colorTransform:{brightness:0.5}});
_slides[i].addEventListener(Slide.CLICK_THUMBNAIL, _clickThumbnailHandler, false, 0, true);
thumbnail.x = curX;
thumbnail.y = 4;
curX += _THUMB_WIDTH + _THUMB_GAP;
}
_minScrollX = _IMAGE_WIDTH - curX;
if (_minScrollX > 0) {
_minScrollX = 0;
}
}

private function _setupArrows():void {
_arrowLeft.alpha = _arrowRight.alpha = 0;
_arrowLeft.visible = _arrowRight.visible = true;
_arrowLeft.addEventListener(MouseEvent.ROLL_OVER, _rollOverArrowHandler, false, 0, true);
_arrowLeft.addEventListener(MouseEvent.ROLL_OUT, _rollOutArrowHandler, false, 0, true);
_arrowLeft.addEventListener(MouseEvent.CLICK, _showPrevious, false, 0, true);
_arrowRight.addEventListener(MouseEvent.ROLL_OVER, _rollOverArrowHandler, false, 0, true);
_arrowRight.addEventListener(MouseEvent.ROLL_OUT, _rollOutArrowHandler, false, 0, true);
_arrowRight.addEventListener(MouseEvent.CLICK, _showNext, false, 0, true);
}

private function _showNext(event:Event=null):void {
//if there's a _loadingSlide we should assume that the next Slide would be AFTER that one. Otherwise just get the one after the _curSlide.
var next:int = (_loadingSlide != null) ? _slides.indexOf(_loadingSlide) + 1 : _slides.indexOf(_curSlide) + 1;
if (next >= _slides.length) {
next = 0;
}
_requestSlide(_slides[next]);
}

private function _showPrevious(event:Event=null):void {
//if there's a _loadingSlide we should assume that the previous Slide would be BEFORE that one. Otherwise just get the one before the _curSlide.
var prev:int = (_loadingSlide != null) ? _slides.indexOf(_loadingSlide) - 1 : _slides.indexOf(_curSlide) - 1;
if (prev < 0) {
prev = _slides.length - 1;
}
_requestSlide(_slides[prev]);
}

private function _requestSlide(slide:Slide):void {
if (slide == _curSlide) {
return;
}
//kill the delayed calls to _showNext so that we start over again with a 5-second wait time.
TweenLite.killTweensOf(_showNext);
if (_loadingSlide != null) {
_cancelPrioritizedSlide(); //the user must have skipped to another Slide and didn't want to wait for the one that was loading.
}
//if the requested Slide's full-sized image hasn't loaded yet, we need to show the progress bar and wait for it to load.
if (slide.imageLoader.progress != 1) {
_prioritizeSlide(slide);
return;
}
//fade the old Slide and make sure it's not highlighted anymore as the current Slide.
if (_curSlide != null) {
TweenLite.to(_curSlide.image, 0.5, {autoAlpha:0});
_curSlide.setShowingStatus(false);
}
_curSlide = slide;
_imagesContainer.addChild(_curSlide.image); //ensures the image is at the top of the stacking order inside the _imagesContainer
TweenLite.to(_curSlide.image, 0.5, {autoAlpha:1}); //fade the image in and make sure visible is true.
_curSlide.setShowingStatus(true); //adds an outline to the image indicating that it's the currently showing Slide.
TweenLite.delayedCall(5, _showNext); //create a delayedCall that will call _showNext in 5 seconds.
}

private function _prioritizeSlide(slide:Slide):void {
TweenLite.to(_progressBar, 0.5, {autoAlpha:1}); //show the progress bar
_loadingSlide = slide;
_loadingSlide.imageLoader.addEventListener(LoaderEvent.PROGRESS, _progressHandler);
_loadingSlide.imageLoader.addEventListener(LoaderEvent.COMPLETE, _completePrioritizedHandler);
_loadingSlide.imageLoader.prioritize(true); //when the loader is prioritized, it will jump to the top of any LoaderMax queues that it belongs to, so if another loader is in the process of loading in that queue, it will be canceled and this new one will take over which maximizes bandwidth utilization. Once the _loadingSlide is done loading, the LoaderMax queue(s) will continue loading the rest of their images normally.
}

private function _cancelPrioritizedSlide():void {
TweenLite.to(_progressBar, 0.5, {autoAlpha:0}); //hide the progress bar
_loadingSlide.imageLoader.removeEventListener(LoaderEvent.PROGRESS, _progressHandler);
_loadingSlide.imageLoader.removeEventListener(LoaderEvent.COMPLETE, _completePrioritizedHandler);
_loadingSlide = null;
}

private function _completePrioritizedHandler(event:LoaderEvent):void {
var next:Slide = _loadingSlide; //store it in a local variable first because _cancelPrioritizedSlide() will set _loadingSlide to null.
_cancelPrioritizedSlide();
_requestSlide(next);
}

private function _progressHandler(event:LoaderEvent):void {
_progressBar.progressBar_mc.scaleX = event.target.progress;
}

private function _clickThumbnailHandler(event:Event):void {
_requestSlide(event.target as Slide);
}

private function _rollOverArrowHandler(event:Event):void {
TweenLite.to(event.currentTarget, 0.5, {alpha:1});
}

private function _rollOutArrowHandler(event:Event):void {
TweenLite.to(event.currentTarget, 0.5, {alpha:0});
}

private function _enterFrameHandler(event:Event):void {
if (_thumbnailsContainer.hitTestPoint(this.stage.mouseX, this.stage.mouseY, false)) {
if (this.mouseX < _SCROLL_AREA) {
 _destScrollX += ((_SCROLL_AREA - this.mouseX) / _SCROLL_AREA) * _SCROLL_SPEED;
 if (_destScrollX > 0) {
 _destScrollX = 0;
 }
 TweenLite.to(_thumbnailsContainer, 0.5, {x:_destScrollX});
} else if (this.mouseX > _IMAGE_WIDTH - _SCROLL_AREA) {
 _destScrollX -= ((this.mouseX - (_IMAGE_WIDTH - _SCROLL_AREA)) / _SCROLL_AREA) * _SCROLL_SPEED;
 if (_destScrollX < _minScrollX) {
 _destScrollX = _minScrollX;
 }
 TweenLite.to(_thumbnailsContainer, 0.5, {x:_destScrollX});
}
}
}

//if an image fails to load properly, remove it from the slideshow completely including its thumbnail at the bottom.
private function _imageFailHandler(event:LoaderEvent):void {
var slide:Slide;
var i:int = _slides.length;
while (--i > -1) {
slide = _slides[i];
if (event.target == slide.thumbnailLoader || event.target == slide.imageLoader) {
 slide.dispose();
 _slides.splice(i, 1);
 _setupThumbnails();
 return;
}
}
}

}
}

 

I could figure out that I have to change the line

new ImageLoader("assets/images/" + image.@name + ".jpg", {name:image.@name + "Image", width:_IMAGE_WIDTH, height:_IMAGE_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:820000, onFail:_imageFailHandler}

and instead of ".jpg" put ".swf" (making sure that the names of the files are identical except for their extensions)

The problem is that I get an error message in the output that flash could not convert my swf file to the bitmap.

I suspect that I have to change the hard coding to specify that Loader Max should treat loading bigger swf files as swf and not as image/jpg files.

I don't have enough expertise to decipher all the lines where this has to be changed.

It feels that I am close to accomplishing what I need. Is it possible to point out where this change has to take place?

 

Here is my thought process:

I don't need to specify SWFLoader as LoaderMax is already specified (line 5)

I don't need to change anything in lines 31-34 as "Sprite" and "Slide" could be an .swf file (line31-34)

I don't need to change anything in line 50 for the same reason (line 50)

I don't need to change lines 66 and 68 as image list may contain swf files (line 66 and 68)

I do need to change ".jpg" to ".swf" in line 72 (line 72)

No sure if there are any changes in line 82 (line 82)

LoaderMax has var as imagesQueue does that need to be changed into SFWLoader? (lines98-102)

I don't think anything need to be changed in lines 138-173 as " Slide" can incorporate an SWF file (lines 138-173)

Not sure if there has to be a change in lines 175-177 as it specifies that slide is an image (lines 175-177)

Not sure if there has to be a change in lines 182-200 from imageLoager to SWFLoader (lines 182-200)

Not sure if there has to be a change in lines 239-245 in specifying SWFLoader (lines 239-245)

 

I am attaching the .xml and .as documents as well

Link to comment
Share on other sites

Hi,

 

The main problem is that you are trying to load a swf with an ImageLoader. You need to be using a SWFLoader to load swfs.

 

so this line:

 

new ImageLoader("assets/images/" + image.@name + ".jpg", {name:image.@name + "Image", width:_IMAGE_WIDTH, height:_IMAGE_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:820000, onFail:_imageFailHandler}

 

would have to be changed to

 

new SWFLoader("assets/images/" + image.@name + ".jpg", {name:image.@name + "Image", width:_IMAGE_WIDTH, height:_IMAGE_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:820000, onFail:_imageFailHandler}

 

Also, I believe that Slide.as has code relating specifically to loading images and not swfs, so some changes will have to be made there.

 

Please read the docs about SWFLoader http://www.greensock.../SWFLoader.html

 

and see how far you can get with making the changes.

 

it would be helpful if you attached 1 zip of your entire project with the assets (swfs included). simplify it as much as possible with very few lightweight swfs and images. just enough for it to work. It would be quite a bit of work for us to make sample swfs and try to test and re-configure a project of that complexity.

Link to comment
Share on other sites

I tried your suggestions, but still getting errors.

I made one simplified zip file with all the assets included. I could not fit "com" folder in there and did not generate swfs. I assume it will be made automatically on your side. "com" folder goes into the main directory where the main .fla file is.

Link to comment
Share on other sites

hi,

 

I edited Slide.as and SlideShowExample.as so that the large images are swfs.

The only changes I made were importing the SWFLoader classes and making sure every where the program was using an ImageLoader for the large image I used a SWFLoader instead.

 

extract the attached zip and replace your actionscript files with the new ones.

slideShowActionScriptFIlesForLoadingSwfs.zip

Link to comment
Share on other sites

Hi,

Thanks for looking into this. Unfortunately when I try the code still gives me an error in the Slide.as

Here are two messages I get:

Slide.as, Line 34

1046: Type was not found or was not a compile-time constant: ImageLoader.

public function Slide(name:String, description:String, thumbnailLoader:ImageLoader, imageLoader:SWFLoader) {

 

 

Slide.as, Line 34

1046: Type was not found or was not a compile-time constant: SWFLoader.

public function Slide(name:String, description:String, thumbnailLoader:ImageLoader, imageLoader:SWFLoader) {

 

Is it easier if I make my small thumbs swf's as well?

Link to comment
Share on other sites

Just wanted to say great Thank You for your help.

It all works now.

 

My more complex Flash site is arranged with the code on the timeline. In the file with the thumbnails I stripped the code from the document class. As well deleting the "super();" I read up that even though it is useful it is optional. It seems to work. I now need to move my files around, I could not find where in the code the action script file Slide.as is referenced. I saw reference to data.xml file and understand how to write up a new route to it, but can not see anything for the Slide.as

 

Could you please point out where the change has to happen so the code in Slide.as can be either incorporated in the main time line or properly referenced from the main timeline?

Link to comment
Share on other sites

Slide.as is automatically accessible as it is inside the same folder as your fla

 

new slides are created with this line (around 78)

 

 

new Slide(image.@name,
image.@description,
new ImageLoader("assets/thumbnails/appThmb_imgs/" + image.@name + ".jpg", {name:image.@name + "Thumb", width:_THUMB_WIDTH, height:_THUMB_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:13000, onFail:_imageFailHandler}),
new SWFLoader("assets/images/" + image.@name + ".swf", {name:image.@name + "Image", width:_IMAGE_WIDTH, height:_IMAGE_HEIGHT, scaleMode:"proportionalInside", bgColor:0x000000, estimatedBytes:820000, onFail:_imageFailHandler})
)

 

There isn't an easy way of putting the code in Slide.as on the main timeline. You should keep it as an external class. A lot can go wrong if you try to re-architect the sample files as they were coded to work in a very specific fashion.

 

that being said, if you properly converted the document class SlideShowExample.as to work as timeline code, you should still be able to create new Slide objects.

Link to comment
Share on other sites

I run into an additional problem. Once I placed the code on my main timeline suddenly elements created by code are located in the lower right quadrant of the stage. I suppose it is because my 0 point specified at the center of the stage. I started to alter your code to move SWFLoader and thumbs loader to where I want them to be. I am afraid that by me adding new code I will cripple what was done before me. Please take a look at what I have done:

_thumbnailsContainer = new Sprite();
addChild(_thumbnailsContainer);
_thumbnailsContainer.x = -350;
_thumbnailsContainer.y = _IMAGE_HEIGHT-55;
_thumbnailsContainer.alpha = 0; //we want alpha 0 initially because we'll fade it in later when the thumbnails load.
_thumbnailsContainer.visible = false; //ensures nothing is clickable.

 

I added the line:

 

_thumbnailsContainer.x = -350;

to define the x position as it was not defined before.

In this line I added "-55" value to move the y position:

_thumbnailsContainer.y = _IMAGE_HEIGHT-55;

 

Then in the ImageLoader and SWFLoader I added lines

x:-260, y:-320,

somehow it works for SWFLoader but not for ImageLoader

Here is the complete code for both of them:

function _xmlCompleteHandler(event:LoaderEvent):void {
  _slides = [];
  var xml:XML = event.target.content; //the XMLLoader's "content" is the XML that was loaded.
  var imageList:XMLList = xml.image; //In the XML, we have <image /> nodes with all the info we need.
  //loop through each <image /> node and create a Slide object for each.
  for each (var image:XML in imageList) {
   _slides.push( new Slide(image.@name,
	  image.@description,
	  new ImageLoader("loadingAssets/appThumbnails/slideshow_image scroller greenSock_mine/assets/thumbnails/appThmb_imgs/" + image.@name + ".jpg",
		  {
		   name:image.@name + "Thumb",
		   width:_THUMB_WIDTH,
		   height:_THUMB_HEIGHT,
		   //centerRegistration:true,
		   //x:260, y:320,//doesn't work here but works in line 69
		   scaleMode:"proportionalInside",
		   bgColor:0x000000,
		   estimatedBytes:13000,
		   onFail:_imageFailHandler}),
	  new SWFLoader("loadingAssets/appThumbnails/slideshow_image scroller greenSock_mine/assets/images/" + image.@name + ".swf",
		   {
		    name:image.@name + "Image",
		    width:_IMAGE_WIDTH,
		    height:_IMAGE_HEIGHT,
		    //centerRegistration:true,
		    x:-260, y:-320,
		    scaleMode:"proportionalInside",
		    bgColor:0x000000,
		    estimatedBytes:820000,
		    onFail:_imageFailHandler})

 

Then in the Slide.as file I have to move the text position and the grey bar position, by changing numbers to negative in this line:

bgBar.graphics.drawRect(-11, -22, this.image.width, 24);

and numbers in these lines:

   tf.x = 6;//text indent to the right
   tf.y = this.image.height - 20;//positions the text in the text background bar
   tf.width = this.image.width - 12;//positions the text in the text background bar

Her is the full block of code from Slide.as:

if (description != "") {
   var bgBar:Shape = new Shape();
   bgBar.graphics.beginFill(0x000000, 0.3);//defines color and transparency of the text background bar
   bgBar.graphics.drawRect(0, 0, this.image.width, 24);//defines position and size of the text background bar. height =24
   bgBar.graphics.endFill();
   bgBar.y = this.image.height - bgBar.height;
   this.image.addChild(bgBar);

   var tf:TextField = new TextField();
   tf.defaultTextFormat = new TextFormat("Arial", 12, 0xFFFFFF);
   tf.x = 6;//text indent to the right
   tf.y = this.image.height - 20;//positions the text in the text background bar
   tf.width = this.image.width - 12;//positions the text in the text background bar
   tf.text = description;
   tf.selectable = false;
   tf.embedFonts = true;
   tf.multiline = false;
   tf.antiAliasType = AntiAliasType.ADVANCED;
   tf.filters = [new GlowFilter(0x000000, 0.8, 8, 8, 2, 2)];
   this.image.addChild(tf);
  }

 

Please let me know if what I have done somehow cripples the functionality of the code, and can be done significantly simpler then what I have come up with?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...