Tuesday, March 30, 2010

Need help fine tuning my gallery

Hello everybody... first let me post the code and then I'll post the errors and what needs to be done...

XML Code:

%26lt;images%26gt;
%26lt;image src=''images/image1.jpg'' title=''Jelly 4'' url=''images/image1.jpg'' /%26gt;
%26lt;image src=''images/image2.jpg'' title=''Cat'' url=''images/image2.jpg'' /%26gt;
%26lt;image src=''images/image3.jpg'' title=''Statue'' url=''images/image3.jpg'' /%26gt;
%26lt;image src=''images/image4.jpg'' title=''Arch 3'' url=''images/image4.jpg'' /%26gt;
%26lt;image src=''images/image5.jpg'' title=''Penguin'' url=''images/image5.jpg'' /%26gt;
%26lt;image src=''images/image6.jpg'' title=''Jelly'' url=''images/image6.jpg'' /%26gt;
%26lt;image src=''images/image7.jpg'' title=''Statue 2'' url=''images/image7.jpg'' /%26gt;
%26lt;image src=''images/image8.jpg'' title=''Arch 1'' url=''images/image8.jpg'' /%26gt;
%26lt;image src=''images/image9.jpg'' title=''Arch 2'' url=''images/image9.jpg'' /%26gt;
%26lt;/images%26gt;


Need help fine tuning my gallery

The compiler is telling you exactly what your problem is:

function removeImg(e:MouseEvent):void
{
TweenMax.to(mcFullImage, 0.2, {alpha: 0, onComplete: unloadImg});
}

function unloadImg(e:Event):void
{

You are calling unloadImg from TweenMax - and no event is passed when you do that - but you have an event parameter in unloadImg. So, argument count mismatch - 1 is expected, but none were passed.

The easy fix:

function unloadImg(e:Event = null):void
{
Need help fine tuning my gallery

actually I tried that before posting the whole thread cuz I, too, thought this was the problem, but it didn't work. I also tried: function unloadImg():void { } and it didn't work. it gave me this error:

ArgumentError: Error #2025: The supplied DisplayObject must be a child of the caller.

at flash.display::DisplayObjectContainer/removeChild()

at XMLScroller_fla::MainTimeline/unloadImg()

at Function/http://adobe.com/AS3/2006/builtin::apply()

at gs::TweenLite/complete()

at gs::TweenMax/complete()

at gs::TweenMax/render()

at gs::TweenLite$/updateAll()

oh ok now I got this one fixed, the problem is that I was removing fullLdr from the stage while it's actually a child of mcFullImage, so the following fixed it:

function unloadImg():void

{

mcFullImage.removeChild(fullLdr);

fullLdr.unload();

removeChild(mcFullImage);

mcFullImage = null;

}

Now I tried adding a boolean to check whether there's an image that is already loaded to the stage or not and still no luck I really need to fix this, so please someone tell me where did I go wrong...!! here's the code:

import gs.*;

import gs.easing.*;

//load xml

var xmlLoader:URLLoader = new URLLoader();

var xmlData:XML = new XML();

xmlLoader.addEventListener(Event.COMPLETE, LoadXML);

var xmlPath:String = ''image-scroller.xml'';

xmlLoader.load(new URLRequest(xmlPath));

function LoadXML(e:Event):void {

xmlData = new XML(e.target.data);

buildScroller(xmlData.image);

}

//declaring variables

var scroller:MovieClip = new MovieClip();

var speed:Number;

var padding:Number = 5;

var thumbFadeOut:Number = .2;

var thumbFadeIn:Number = 1;

var thumbSmall:Number = 1;

var thumbLarge:Number = 1.1;

this.addChild(scroller);

scroller.y = scroller.x = padding;

var thisOne:MovieClip

var loaded:Boolean = false;

//build scroller from xml

function buildScroller(imageList:XMLList):void{

for (var item:uint = 0; item %26lt; imageList.length(); item++ )?{

thisOne = new MovieClip();

//outline

var blackBox:Sprite = new Sprite();

blackBox.graphics.beginFill(0xFFFFFF);

blackBox.graphics.drawRect( -1, -1, 82, 82);

blackBox.alpha = thumbFadeOut;

thisOne.addChild(blackBox);

thisOne.blackBox = blackBox;

thisOne.x = thisOne.myx = (80 + padding) * item;

thisOne.itemNum = item;

thisOne.title = imageList[item].attribute(''title'');

thisOne.link = imageList[item].attribute(''url'');

thisOne.src = imageList[item].attribute(''src'');

//image container

var thisThumb:Sprite = new Sprite();

//add image

var ldr:Loader = new Loader();

var urlReq:URLRequest = new URLRequest(thisOne.src);

ldr.load(urlReq);

//assign event listeners for Loader

ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, completeHandler);

ldr.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, errorHandler);

thisThumb.addChild(ldr);

thisOne.addChild(thisThumb);

//create listeners for this thumb

thisOne.buttonMode = true;

thisOne.addEventListener(MouseEvent.MOUSE_OVER, overScrollerItem);

thisOne.addEventListener(MouseEvent.MOUSE_OUT, outScrollerItem);

if(loaded == false) {

thisOne.addEventListener(MouseEvent.CLICK, clickScrollerItem);

}

//add item to the scroller mc

scroller.addChild(thisOne);

}

scroller.addEventListener(Event.ENTER_FRAME, moveScrollerThumbs);

}

function overScrollerItem(e:MouseEvent):void {

//trace(''over'' + e.currentTarget.name);

TweenMax.to(e.currentTarget, 0.5, { scaleX:thumbLarge, scaleY:thumbLarge, x:e.currentTarget.myx - e.currentTarget.width * Math.abs(thumbSmall - thumbLarge)/2, y: -e.currentTarget.width * Math.abs(thumbSmall - thumbLarge)/2} );

TweenMax.to(e.currentTarget.blackBox, 1, { alpha:thumbFadeIn} );

}

function outScrollerItem(e:MouseEvent):void {

//trace(''out'' + e.currentTarget.name);

TweenMax.to(e.currentTarget, 0.5, { scaleX:thumbSmall, scaleY:thumbSmall, x:e.currentTarget.myx, y:0} );

TweenMax.to(e.currentTarget.blackBox, 0.5, { alpha:thumbFadeOut} );

}

var mcFullImage:MovieClip;

var fullLdr:Loader

function clickScrollerItem(e:MouseEvent):void {

mcFullImage = new MovieClip();

fullLdr = new Loader()

var urlReq:URLRequest = new URLRequest(e.currentTarget.link);

fullLdr.load(urlReq);

fullLdr.contentLoaderInfo.addEventListener(Event.INIT, initHandler)

addChild(mcFullImage);

mcFullImage.x = 100;

mcFullImage.y = 90;

mcFullImage.addChild(fullLdr);

var image:Bitmap = Bitmap(e.target.content);

image.smoothing = true;

loaded = true;

}

function initHandler(e:Event):void

{

TweenMax.from(fullLdr, 1, {alpha: 0});

mcFullImage.addEventListener(MouseEvent.CLICK, removeImg);

}

function removeImg(e:MouseEvent):void

{

TweenMax.to(mcFullImage, 0.2, {alpha: 0, onComplete: unloadImg});

}

function unloadImg():void

{

mcFullImage.removeChild(fullLdr);

fullLdr.unload();

removeChild(mcFullImage);

mcFullImage = null;

loaded = false;

}

function completeHandler(e:Event):void {

//size image into scroller

resizeMe(e.target.loader.parent, 80, 80, true, true, false);

var image:Bitmap = Bitmap(e.target.content);

image.smoothing = true;

TweenMax.to(e.target.loader.parent.parent, 0.5, { alpha:1} );

}

function errorHandler(e:IOErrorEvent):void {

trace(''thumbnail error=''+e);

}

//The resizing function

// parameters

// required: mc = the movieClip to resize

// required: maxW = either the size of the box to resize to, or just the maximum desired width

// optional: maxH = if desired resize area is not a square, the maximum desired height. default is to match to maxW (so if you want to resize to 200x200, just send 200 once)

// optional: constrainProportions = boolean to determine if you want to constrain proportions or skew image. default true.

function resizeMe(mc:DisplayObject, maxW:Number, maxH:Number=0, constrainProportions:Boolean=true, centerHor:Boolean=true, centerVert:Boolean=true):void{

?maxH = maxH == 0 ? maxW : maxH;

?mc.width = maxW;

?mc.height = maxH;

?if (constrainProportions) {

?mc.scaleX %26lt; mc.scaleY ? mc.scaleY = mc.scaleX : mc.scaleX = mc.scaleY;

?}

if (centerHor) {

mc.x = (maxW - mc.width) / 2;

}

if (centerVert){

mc.y = (maxH - mc.height) / 2;

}

}

function moveScrollerThumbs(e:Event):void {

if ( mouseY %26gt; scroller.y %26amp;%26amp; mouseY %26lt; scroller.y + scroller.height) {//vertically over scroller

if (mouseX %26lt; stage.stageWidth/2 - padding*2 %26amp;%26amp; mouseX %26gt; 0) {//left of stage explicitly

%26amp;n bsp; speed = -(mouseX - (stage.stageWidth/2 - padding*2)) / 8;

}

else if (mouseX %26gt; stage.stageWidth/2 + padding*2 %26amp;%26amp; mouseX %26lt; stage.stageWidth) {//right of stage explicitly

%26amp;n bsp; speed = -(mouseX - (stage.stageWidth/2 + padding*2)) / 8;

}

else {

%26amp;n bsp; speed = 0;

}

scroller.x += speed;

//scroller limits

if (scroller.x %26lt; -scroller.width + stage.stageWidth - padding) { //if scrolled too far left

%26amp;n bsp; scroller.x = -scroller.width + stage.stageWidth - padding;

}

else if (scroller.x %26gt; padding) { //if scrolled to far right

%26amp;n bsp; scroller.x = padding;

}

}

}

First, one of the suggestions given is correct - you must default the parameters to null.

Second, try to change the order of unloading and removing the children.

But the main problem I guess is that fullLdr is a child of mcFullImage but you attempt to remove it from the scope of [this] - hence the error:

function unloadImg(e:Event = null):void
{

removeChild(mcFullImage);

mcFullImage.removeChild(fullLdr);
?fullLdr.unload();
mcFullImage = null;
}

Also, remove event listener:

function initHandler(e:Event):void
{
?fullLdr.contentLoaderInfo.removeEventListener(Event. INIT, initHandler)
?TweenMax.from(fullLdr, 1, { alpha: 0 } );
?mcFullImage.addEventListener(MouseEvent.CLICK, removeImg);
}

Also, remove event listener:

function initHandler(e:Event):void
{
?fullLdr.contentLoaderInfo.removeEventListener(Event. INIT, initHandler)
?TweenMax.from(fullLdr, 1, { alpha: 0 } );
?mcFullImage.addEventListener(MouseEvent.CLICK, removeImg);
}

thisOne will always return the last element of the array because in the loop in buildScroller function the latest assignment was from the last loop iterations.

If you need to referenc eht item clicked you need to do the following:

function clickScrollerItem(e:MouseEvent):void {
?mcFullImage = new MovieClip();
?fullLdr = new Loader()
?var urlReq:URLRequest = new URLRequest(e.currentTarget.link);
?fullLdr.load(urlReq);
?fullLdr.contentLoaderInfo.addEventListener(Event.INIT, initHandler)
?addChild(mcFullImage);
?mcFullImage.x = 100;
?mcFullImage.y = 90;
?mcFullImage.addChild(fullLdr);
?var image:Bitmap = Bitmap(e.target.content);
?image.smoothing = true;
?e.currentTarget.removeEventListener(MouseEvent.CLICK, clickScrollerItem);
?trace(Object(e.currentTarget.itemNum) + '' can't be clicked anymore'');
}

Ok what you said actually worked, and now it returns the item that was clicked. But what if I want to remove the mouse click listener from ALL of the thumbs so that I couldn't load another image when there's already an image that is loaded to stage... I tried assigning the ''clickScrollerItem'' function to scroller and then removing it inside the ''clickScrollerItem'' function, but I got this error:

ypeError: Error #2007: Parameter url must be non-null.

at flash.display::Loader/_load()

at flash.display::Loader/load()

at XMLScroller_fla::MainTimeline/clickScrollerItem()

Frankly, I am not sure what you want to accomplish and I am not sure I agree with your approach.

I think you need to take a step back and describe the use cases as clearly as possible so everyone can be on the same page. Code, unfortunately, doesn't demonstrate your intentions.

In my mind what you are trying to do is to build a thumbnail menu. If this is it - why bother with creating dependencies of thumbnail loading on mouse event? Why not just load all the thumbnails and be done with it?

Ok here's what this application actually is...

1. This is based on a horizontal scroll image menu. It was a tutorial that creates an XML based horizontal scroll which loads the thumbs and then when you click on a thumb it triggers a navigateToURL function which opens a URL in a new window. That wasn't what I wanted, I wanted to transform this into an image gallery, therefore I changed this navigateToURL thing to an internal loading of images to the stage using the Loader() class.

2. Now everything is working fine except that bug I'm trying to fix. What I want to achieve is simply stop images from loading when I click on a thumb once there is an image that is already loaded to stage. So when there is an image on stage, I want to remove the mouse click event listener from ALL of the thumbs. Or, if possible, add a boolean that checks whether an image is already loaded to the stage and accordingly decide whether to load another image or not. It doesn't matter what approach is followed as long as images stop loading on top of eachother.

I hope everything is clear now...

So, is it a slide show from your previous posts in which you want to load main images when corresponding thumbs are clicked?

If so, this tutorial is useless (to my point of blindly accommodating someone else's code). There is a better way to do that.

''So, is it a slide show from your previous posts in which you want to load main images when corresponding thumbs are clicked?'' %26lt;%26lt; That is EXACTLY what I want to do!

Now I'm thinking if I cannot remove the mouse click event listener maybe I can do something else, like for example when I click another thumb, it unloads the current image and loads the corresponding new image...

If that's not possible, do you think I should start from scratch again? :S

Look, it is not ''I told you so'' but rather friendly advice. In one of the earliest post I asked wether you saw your application to scale up. I guess I was not assertive enough regarding the importance of this.

Question of scalability must be always on developer's mind when code is written. The answer is yes in 75% of the cases (where I got this number I am not going to tell you).

As for your particular task if you insist on using mouse events from the tutorial - I am afraid no one will help you for this is a very cumbersome way to do that. Tutorial is a reflection of totally different goals and its architecture is not suitable for your tasks IMHO.

If you want to do everything on timeline - you will need, perhaps, create a slide symbol in the library and instantiate it as needed. This slide object may accomplish loading of images and all this jazz so you don't have to worry what is loaded and what is not. This is not the only way but one of the ways.

ok I finally decided to give up on this gallery... I'll start off with loading and using the xml data to link between the thumbs and the full size images, and then when I'm done with that I'll worry about scrolling this thing in a way or another... Thanks for the help Andrei1, much appreciated

I totally support your decision and am willing to contribute to your explorations.

I would like to point out that often third party solutions cloud the road to success and move the real task out of the focus. In your case it shows that clarity is regained and you will be where you are going soon.

Thanks for the support, if making mistakes and learning from them is what it takes to become really good at actionscript 3.0 and programming in general, then so be it. I'm actually glad to have professionals like you guiding my way.

Right now I'm starting right from the beginning, I'm re-writing my XML file and will get to the actionscript code as well. I'll keep it simple for learning purposes and then I'll expand on it for my project once I'm confident about it.

No comments:

Post a Comment