AS3 simple horizontal gallery - actionscript-3

I have a simple horizontal gallery of 24 pictures.
The idea is to show 3 pictures on the screen from all (24) and the middle one to be shown above as the big one automaticly ( like the scheme ). This means that when some of the arrows is pressed the movement of the images have to be by one. Also they have to be auto looped. So the first one can go in the middle to.
Here is my code so far. ( I didn't put the all 24 thumbnails, here are only 3 thumbnails only for the tests ) I've managed to move the thumbnails and select a big picture. But I need it to be auto selected when comes to the middle.
buttonL1_btn.addEventListener(MouseEvent.CLICK, left);
buttonR1_btn.addEventListener(MouseEvent.CLICK, right);
function left(event:Event):void{
box_mc.x -=50;
}
function right(event:Event):void{
box_mc.x +=50;
}
//imgs
img_3_big.visible = false;
box_mc.img_1.addEventListener(MouseEvent.CLICK, img1_show);
function img1_show(e:MouseEvent):void {
img_3_big.visible = true;
img_3_big.gotoAndStop(3);
}
box_mc.img_2.addEventListener(MouseEvent.CLICK, img2_show);
function img2_show(e:MouseEvent):void {
img_3_big.visible = true;
img_3_big.gotoAndStop(2);
}
box_mc.img_3.addEventListener(MouseEvent.CLICK, img3_show);
function img3_show(e:MouseEvent):void {
img_3_big.visible = true;
img_3_big.gotoAndStop(1);
}

Although a different approach than what you have already done, the way I would do it is by keeping all 24 images outside of the .swf in their own image files and keeping track of the current image index. Something similar to this (untested code):
import flash.display.Bitmap;
import flash.display.Loader;
import flash.events.MouseEvent;
var allImagePaths:Vector.<String> = new Vector.<String>(); // Holds reference to all big images
var allImageThumbPaths:Vector.<String> = new Vector.<String>(); // Holds reference to all thumbnail images
var currentImageIndex:int = 0; // Keeps track of what image is currently selected
// Loaders that would load big image and thumbnails
var loaderMain:Loader;
var loaderThumb_Left:Loader;
var loaderThumb_Middle:Loader;
var loaderThumb_Right:Loader;
SetupGallery(); // initialize gallery
function SetupGallery()
{
// Setup image loaders
loaderMain = new Loader();
loaderThumb_Left = new Loader();
loaderThumb_Middle = new Loader();
loaderThumb_Right = new Loader();
// Add loaders to existing MovieClips on stage.
imageHolderMain_mc.addChild(loaderMain);
imageHolderThumbLeft_mc.addChild(loaderThumb_Left);
imageHolderThumbMiddle_mc.addChild(loaderThumb_Middle);
imageHolderThumbRight_mc.addChild(loaderThumb_Right);
// Load image paths into a vector collection (like an array)
loadImages();
// Setup arrow button listeners
buttonL1_btn.addEventListener(MouseEvent.CLICK, showImageLeft);
buttonR1_btn.addEventListener(MouseEvent.CLICK, showImageRight);
}
function loadImages()
{
// Initialize collection of images for easier looping/displaying
allImagePaths = new Vector.<String>();
allImageThumbPaths = new Vector.<String>();
// Load up all image paths into the image array(vector).
allImagePaths.push("image1.jpg");
allImageThumbPaths.push("image1_thumb.jpg");
// ... image2 - image23 ...
allImagePaths.push("image24.jpg");
allImageThumbPaths.push("image24_thumb.jpg");
// NOTE: Consider loading paths to image files via xml
}
function showImageLeft(evt:MouseEvent)
{
currentImageIndex--;
showCurrentImage();
}
function showImageRight(evt:MouseEvent)
{
currentImageIndex++;
showCurrentImage();
}
// Call this after each arrow click, direction will be determined by currentImageIndex
function showCurrentImage()
{
// Keep current index within bounds, if out of range then "loop back"
if(currentImageIndex < 0) currentImageIndex = allImagePaths.length - 1;
if(currentImageIndex > allImagePaths.length - 1) currentImageIndex = 0;
// Set right and left thumbnail indexes based on current image
// (Assuming my logic is correct of course :)
var indexRight:int = currentImageIndex - 1;
if(indexRight < 0) indexRight = allImagePaths.length - 1; // "Loop back" if needed
var indexLeft:int = currentImageIndex + 1;
if(indexLeft > allImagePaths.length - 1) indexLeft = 0; // "Loop back" if needed
// clear out any existing images
loaderMain.unload();
loaderThumb_Left.unload();
loaderThumb_Middle.unload();
loaderThumb_Right.unload();
// set correct images based on new indexes
loaderMain.load(allImagePaths[currentImageIndex]);
loaderThumb_Left.load(allImageThumbPaths[indexLeft]);
loaderThumb_Middle.load(allImageThumbPaths[currentImageIndex]);
loaderThumb_Right.load(allImageThumbPaths[indexRight]);
}
There may be some additional things you'll have to handle, but that's the general idea.
Going with this approach you will not deal with keyframes, in fact you would want to have only one keyframe where the AS code is located and you would want to remove all images from the .swf file itself.
This approach will:
Allow for "Looping back" of images when at the end or beginning of the gallery.
Make it easier to add or remove images in the future.
Improve initial load time for the end user.

Related

How do I get images to update dynamically with a slider in actionscript 3?

Here is my dilemma. We use image stacks a lot here with alpha channels. I want to call up images in series using a slider. I am getting a concatenated string a pull up an image from my folder. But I can not get the images to load dynamically when I slide the slider bar.
I am using the frame number to change the file name to pull up the next frame. I can get the image to show up if I put the loader outside of the function, but when I put the loader in the function I get error after error saying the file cannot be located.
Here is the code as it currently stands :
var imgLoader = new Loader();
var str1 = String (".jpg");
var sliderValue:uint = mySlider.sliderKnob.x / 3;
addEventListener(Event.ENTER_FRAME, onEnterFrame);
function onEnterFrame(event:Event):void {
sliderValue = mySlider.sliderKnob.x / 3;
status_txt.text = "Slider position is: "+sliderValue;
fileText.text = "Sketch_0"+sliderValue+".jpg";
imgLoader.load( new URLRequest ( "Sketch_0"+sliderValue+".jpg"));
addChild(imgLoader);
setChildIndex(imgLoader, 0);
}
First thing up, you need to load one image without that slider stuff and see if it loads. Verify the paths if not. Relative paths, as you put them, will work relatively to the folder where SWF is (or where the HTML page, containing the SWF, is).
Second, relieve the heavy burden you are trying to put on the Flash Player.
addEventListener(Event.ENTER_FRAME, onFrame);
var nextName:String;
function onFrame(e:Event):void
{
var anIndex:int = mySlider.sliderKnob.x / 3;
var aName:String = "Sketch_0" + anIndex + ".jpg";
status_txt.text = "Slider position is: " + anIndex;
fileText.text = aName;
// Flash Player does not load images instantly,
// so lets request new image only if user stopped moving the slider.
if (aName == nextName)
{
loadNext(nextName);
}
else
{
nextName = aName;
}
}
var currentName:String;
var currentImage:Loader;
function loadNext(value:String):void
{
// If the requested file is the same as current, just ignore the request.
if (value == currentName) return;
currentName = value;
// Dispose of the previous image in a proper way.
if (currentImage)
{
removeChild(currentImage);
currentImage.unloadAndStop(true);
currentImage = null;
}
// Create a new one.
var aRequest:URLRequest = new URLRequest(currentName);
currentImage = new Loader();
currentImage.load(aRequest);
addChild(currentImage);
}

AS3 Loading dynamically named text files

I have a preload movie that loads an interface. In the interface I have many buttons. When I click on a button I want to load a text file into a movie called "TextMovie.swf". I want to be able to click on a button, take the name of the button and load a text file that is the same name as the button instance, and have the window appear close to the mouse click. There will be hundreds of buttons and hundreds of text files. I'm sure this is easy for some. Here is the loader for a button:
button_1.addEventListener(MouseEvent.CLICK, fl_ClickToPosition_2);
function fl_ClickToPosition_2(event:MouseEvent):void
{
var my2ndLoader:Loader = new Loader();
var url2:URLRequest = new URLRequest("TextMovie.swf");
my2ndLoader.load(url2);
addChild(my2ndLoader);
my2ndLoader.x = 200;
my2ndLoader.y = 10;
}
Then in the TextMovie.swf I have:
import flash.net.URLLoader;
import flash.events.Event;
import flash.net.URLRequest;
import flash.text.StyleSheet;
var css:StyleSheet = new StyleSheet();
css.setStyle("a:hover", {textDecoration:"underline"});
var textLoader: URLLoader = new URLLoader();
textLoader.dataFormat = URLLoaderDataFormat.VARIABLES;
textLoader.addEventListener(Event.COMPLETE, textLoaded);
loadText();
function textLoaded(evt: Event): void {
title_txt.htmlText = textLoader.data.txtTitle;
main_txt.htmlText = textLoader.data.txtBody;
URL_txt.htmlText = textLoader.data.txtURL;
URL_txt.styleSheet = css
}
function loadText(): void {
// var fileName: String = "assets/test_01.txt";
var fileName: String = "assets/" + + ".txt";
textLoader.load(new URLRequest(fileName));
}
I'm not sure how to get the name of the button I pushed and apply it to the string that will load the correct text file. I also can't get the window to appear close to the mouse click. Right now I just have it set with an x and y for testing.
I know it's a lot but thanks for any help.
I suggest you take a look at the docs for MouseEvent so you better understand what data is passed as parameters when the event is triggered.
In the event handler, a reference is passed to the object which was clicked: the event target– and from that you can get its name, location, etc. This is good because it means you only need one event handler for all your buttons.
Once you have the name, you can build the string you need for your url. (I wouldn't do it that way if it is a project which is going to have any sort of lifespan but it's an ok approach).
You can get the x and y location of the target, its width and height, and use that data to position your window. The localX and localY properties refer to the click location relative to the rect of the target (button) – with top/left of the target== 0,0.
This is the trace output from the function below:
red red.swf
600 400
25 8.5
button_1.addEventListener(MouseEvent.CLICK, onHandleButtonClick);
function onHandleButtonClick(event:MouseEvent):void
{
var btnName:String = event.target.name;
var swfName:String = btnName + ".swf";
trace(btnName, swfName);
trace(event.target.x, event.target.y);
trace(event.localX, event.localY);
}

Save order and placement of movieclips to a file

I have an application that allows the user to create a custom banner. The app allows the user to add uploaded images (using FileReference) to the banner as well as adding images that are built-in to the application and can be selected within the app. Most of the elements that can be added to the banner are movieclips or textfields.
What I want to do is have a 'Save Design' button that saves the current configuration that the user has set so that if they close and reopen the app they can click the 'Load Design' button and it will load in their previously made design with the right properties (Colours, image position etc.)
What is the best way to do this?
The best way to do this is to store the information in a SharedObject.
The images that are loaded using FileReference can each be stored as a ByteArray. Then, when they're retrieved, you can use Loader.loadBytes() to reload the images.
Here's a quick example which is in no way complete, but it should get you started in the right direction:
import flash.net.SharedObject;
import flash.display.DisplayObject;
var so:SharedObject = SharedObject.getLocal("savedBanner");
function save():void
{
so.data.objects = [];
// loop over all of your display objects and save their information/position
for(var i:int = 0; i < numChildren; i++)
{
var displayObject:DisplayObject = getChildAt(i);
var savedObject:Object = {};
savedObject.className = getQualifiedClassName(displayObject);
savedObject.x = displayObject.x;
savedObject.y = displayObject.y;
savedObject.rotation = displayObject.rotation;
savedObject.scaleX = displayObject.scaleX;
savedObject.scaleY = displayObject.scaleY;
// store any other pertinent data
so.data.objects.push(savedObject);
}
so.flush();
}
function load():void {
for each(var savedObject:Object in so.data.objects)
{
var newObject:DisplayObject = new (getDefinitionByName(savedObject.className) as Class)();
newObject.x = savedObject.x;
newObject.y = savedObject.y;
newObject.rotation = savedObject.rotation;
newObject.scaleX = savedObject.scaleX;
newObject.scaleY = savedObject.scaleY;
addChild(newObject);
}
}

Actionscript Image with clickable spots

Can any one help in suggesting a solution for the following:
i have a large image, consider it as a map, i want to put this image in a viewer that is smaller than the image and i have to be able to scroll the image by clicking and dragging it.
and i want to put in this image a clickable spots in a specified x and y coordinated, and be able to click the spots.
when clicking any spot in the image, the image will be changed with a new spots.. and so on..
can you help in suggesting what is the best object to load the image in and be able to do all the mentioned points.
Thanks in advance.
This is easier than you think. You have a few goals to consider:
"i want to put this image in a viewer that is smaller than the image": You dont need anything special to do this. The concept of this is simply that you have a mask overlay where you want the large image visible.
var viewer:Sprite = new Sprite; //200x200
var imageMask:Sprite = new Sprite; //200x200
var imageContainer:Sprite = new Sprite; //400x500
imageContainer.mask = imageMask;
viewer.addChild(imageContainer);
//this will allow you to visibly see only 200x200 of the
//imageContainer at any time
"i have to be able to scroll the image by clicking and dragging it": This is a little more logic as the imageContainer will have to move in the -(negative) direction of the mouse. Add some listeners to check for mouse actions, and drag as required.
var allowDrag:Boolean = false;
imageContainer.addEventListener(MouseEvent.MOUSE_DOWN, onMouseDown);
imageContainer.addEventListener(MouseEvent.MOUSE_UP, onMouseUp);
imageContainer.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
function onMouseDown(e:Event):void{
allowDrag = true;
}
function onMouseUp(e:Event):void{
allowDrag = false;
}
function onMouseMove(e:Event):void{
//return if not dragging
if(!allowDrag) return;
//move the imageContainer in a -(negative) direction of the mouse
//use an index relative to the size of the viewer and imageContainer
var speed:Number = 0.5;
imageContainer.x -= (viewer.width/imageContainer.width)*speed;
imageContainer.y -= (viewer.height/imageContainer.height)*speed;
//clean the positions so the image remains within the viewer
if(imageContainer.x > 0) imageContainer.x = 0;
if(imageContainer.x < -viewer.width) imageContainer.x = -viewer.width;
if(imageContainer.y > 0) imageContainer.y = 0;
if(imageContainer.y < -viewer.height) imageContainer.y = -viewer.height;
}
"i want to put in this image a clickable spots in a specified x and y coordinated, and be able to click the spots": This also requires a little more thinking. In this case what you want to do is create [hotspots] on the image that are clickable, when clicked = do actions.
//USAGE
//define the click area coords
var clickCoords:Rectangle = new Rectangle();
clickCoords.x = 10; //starts at x 10
clickCoords.y = 10; //starts at y 10
clickCoords.width = 100; //100 wide
clickCoords.height = 100; //100 tall
//add the click listener
var clickArea:Sprite = hotSpot(imageContainer,clickCoords);
clickArea.addEventListener(MouseEvent.CLICK, onHotSoptClick);
//hot spot factory
function hotSpot(target:Sprite,coords:Rectangle):Sprite{
//create the hotspot
var hs:Sprite = new Sprite;
hs.graphics.beginFill(0,0);
hs.graphics.drawRect(0,0,coords.width,coords.height);
hs.graphics.endFill();
//add the hotspot to the target
hs.x = coords.x;
hs.y = coords.y;
target.addChild(hs);
}
function onHotSoptClick(e:MouseEvent):void{
//do something
}
IMPORTANT:
You may want to keep a list of hot spots you create so you can do garbage cleanup, and you plan on dynamically generating hotspots per image... then YOU MUST keep an active list of hot spots and remove when not in use.
You can catch the events MouseDown, MouseUp, MouseMove, MouseOut, on your viewing window, this way you can control exactly what do you want to do.
Here is the pseudo-code:
reset()
{
isDown=false;
downPointX=0;
downPointY=0;
distanceX=0;
distanceY=0;
}
onMouseDown()
{
isDown=true;
downPointX=mouseX;
downPointY=mouseY;
}
onMouseUp()
{
if(distanceX+distanceY==0 and isDown)
click(downPointX,downPointY);
reset();
}
onMouseMove()
{
if isDown then
distanceX=mouseX-downPointX;
distanceY=mouseY-downPointY;
drag(distanceX,distanceY);
endif;
}
onMouseOut()
{
reset();
}
drag(distanceX,distanceY)
{
change your map coordinates
}
click(downPointX,downPointY)
{
if(inSpot(downPointX,downPointY)==true)
changeMap();
endif;
}
changeMap()
{
change your maps and spots
}
avoid implementing any event for your spots sprites or you can get unexpected results.
You can check these for more information
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/display/Sprite.html#eventSummary

Best way of attaching bitmaps from library with a linkagename (currently trying with - getDefinitionByName(tempName) as Class)

I basically have 5 images in library, which I've given af linkage name as so:
head_image0, head_image1, head_image2 etc...
On Stage I have two containers which I will be loading my images into.
- pictureContainer1_mc
- pictureContainer2_mc
Pr default I have already loaded an image into container1.
What will happen is that, when I click menu button2, then head_image2 will load into container2 and fade up from alpha 0 -> alpha 1 - giving a transition between the two images.
After the image has alpha'ed into container2, then I run a function to swap containers, so that container1 will hold the image currently loaded and container2 will be ready to load another picture upon menu button click.
This looks like the following:
//Function receiving an ID from the button click, which we can use to load the connected image
function headerFadeIn(receivedNumber:Number):void
{
//Getting container2 rdy to tween from 0 -> 1
pictureContainer2_mc.alpha = 0;
//Preparing image string - linkagename
var tempName:String = "header_image" + receivedNumber;
//Loading the image into container 1
var headImage:Bitmap = new Bitmap();
var classDefinition:Class = getDefinitionByName(tempName) as Class;
var img:BitmapData = new classDefinition(1,1);
headImage.bitmapData = img;
pictureContainer2_mc.addChild(headImage);
//Tweening currecntly added image from 0 -> 1
//When tween is done call function onFinishTween to swap containers
TweenLite.to(pictureContainer2_mc,1,{alpha:1, ease:menuEasing, onComplete:onFinishTween});
function onFinishTween():void
{
//Setting currently loaded image in container 1
var headImage:Bitmap = new Bitmap();
var classDefinition:Class = getDefinitionByName(tempName) as Class;
var img:BitmapData = new classDefinition(1,1);
headImage.bitmapData = img;
pictureContainer1_mc.addChild(headImage);
pictureContainer2_mc.alpha = 0;
}
}
This works for me. HOWEVER I'm experiencing some "lagging" issue. When I've clicked back and forward menu buttons to change images like 15 times, then the tweening begins to "lag" and wont happen in a smooth transition.
Any calls on this?
Could I do this in a smarter way?
I would suggest to create images only once, and reuse them. Also, after the tween, i would remove the old image and save it for the next time you need that image. Also, when you swap the image from container 2 into container 1, don't create a new one, just move the image from one container to the other.
Something like this, code is not tested, just to give you an idea.
var instances:Object = {};
var currentImage:String;
//Function receiving an ID from the button click, which we can use to load the connected image
function headerFadeIn(receivedNumber:Number):void
{
//Getting container2 rdy to tween from 0 -> 1
pictureContainer2_mc.alpha = 0;
//Preparing image string - linkagename
currentImage = "header_image" + receivedNumber;
var headImage:Bitmap = _getImage(currentImage);
pictureContainer2_mc.addChild(headImage);
//Tweening currecntly added image from 0 -> 1
//When tween is done call function onFinishTween to swap containers
TweenLite.to(pictureContainer2_mc,1,{alpha:1, ease:menuEasing, onComplete:onFinishTween});
function onFinishTween():void
{
//Setting currently loaded image in container 1
//cast returned DisplayObject into a Bitmap.
var headImage:Bitmap = pictureConainer2_mc.getChildByName(currentImage) as Bitmap;
pictureContainer1_mc.addChild(headImage);
pictureContainer2_mc.alpha = 0;
}
}
function _getImage(id:String):Bitmap{
if( instances[id] ) return instances[id];
//Loading the image into container 1
var headImage:Bitmap = new Bitmap();
var classDefinition:Class = getDefinitionByName(tempName) as Class;
var img:BitmapData = new classDefinition(1,1);
headImage.bitmapData = img;
instances[id] = headImage;
return headImage;
}