Extending the Wonder Wall

wonderwallI don't like the Wonder Wall effect in Flash, but a lot of designers love it. And if you work in a company that have one of these designers… I found a nice code shared by Flashmonkey in order to code this Flash effect. But this code runs only for an image from the Flash library. Obviously the designer told me that he wants to load tons of external images. So let's modify the code.

STEP 1. Load some external images.

In the file "Application.as" we found the code. The code loads a bitmap and distort it. So the first thing we must do is to change the bitmap loaded from Flash library with an array of bitmaps externally loaded. We create the array with the image names, and change the BitmapData variable to an array of BitmapData:

private var bmd:Array=new Array();  //THIS WAS private var bmd:BitmapData;
private var imagenes:Array=new Array("mono1.jpg","mono2.jpg","mono3.jpg","mono4.jpg","mono5.jpg","mono6.jpg","mono7.jpg","mono8.jpg","mono9.jpg");

Next, find the line:

bmd = new Monkey(100, 100);

Monkey is a simple class to name the bitmap from library. We need to change this class to a class that loads an image externally, so we will need a class named "bitmap":

----bitmap.as----

package
{
import flash.display.Bitmap;
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.events.Event;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;

public class bitmap extends Sprite
{
private var _url:String = "";
private var _bytesLoadProgress:int = 0;
private var _loaded:Bitmap;
private var _loadedBData:BitmapData;

public function bitmap(url:String)
{
  var loader:Loader = new Loader();
  loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
  loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, progressLoaded);
  loader.load(new URLRequest(url));
}
public function onComplete(e:Event):void
{
  _loadedBData = new BitmapData(100,100);
  _loadedBData = e.target.loader.contentLoaderInfo.content.bitmapData.clone();
  _loaded = new Bitmap(_loadedBData);
  this.addChild(_loaded);
  dispatchEvent(new Event("cargado"));
}

public function progressLoaded(e:ProgressEvent):void
{
  _bytesLoadProgress = e.bytesLoaded/e.bytesTotal;
}
public function getProgress():int
{
  return _bytesLoadProgress;
}
public function getBitmapData():BitmapData
{
  return _loadedBData;
}
}
}

This class loads the image and dispatches the event "cargado" (loaded) when the image has been loaded. So now we are going to change the previous line to:
for(i = 0; i < imagenes.length; i++)  //THIS WAS bmd = new Monkey(100, 100);
{
  bmd.push(new bitmap(imagenes[i]));
  bmd[i].addEventListener("cargado", estaCargado, false, 0, true);
}

And in the loaded image event we count the images loaded, to know when the last image ends its loading, and in that moment, we start the animation
private function estaCargado (evt:Event):void {
  evt.target.removeEventListener("cargado", estaCargado);
  counterLoader++;
  if (counterLoader==imagenes.length)
    addEvent(this, Event.ENTER_FRAME, draw);
}

Now, the last modification will be calling the distort object, we will pass the array to it:
distort.setTransform(img, bmd[i].getBitmapData(), images[i].tl.point, images[i].tr.point, images[i].br.point, images[i].bl.point);

STEP 2. Load some external images, BUT NOT HARDCODED IN THE SCRIPT.

Ok, its ugly to have the images in an array, so let's load them with an XML. So we create the XML, with "images" as the root node and "image" as the element nodes. Next, we define the code:
private var myXMLLoader:URLLoader = new URLLoader();
private var imagenes:Array=new Array();

Now we need to load the XML at the beginning of the "added" function, below the
if(showGuides) addChild(mouseGuide);

line , and define the number of image points depending on the number of images loaded.
myXMLLoader.load(new URLRequest("images.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);

And then continue the "added" function in the "processXML" function. We will use a two rows image wall, so the number of images would be a multiple of 2.
private const wh:uint=2; //NUMBER OF ROWS

…….

private function processXML(e:Event):void {
  var xmlFull:XML = new XML(e.target.data);
  xmlFull.ignoreWhite = true;
  myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
  myXMLLoader = null;
  for (var i:uint=0; i<xmlFull.descendants("image").length(); i++) {
    imagenes.push(xmlFull.descendants("image")[i]);
  }

  var hw:uint=imagenes.length/wh;
  var layout:Array = [];
  var xpos:int = 150;
  var ypos:int = 150;
  var w:int;
  var h:int;

for(w = 0; w <= wh; w++)
{
  layout[w] = [];
  for(h = 0; h <= hw; h++)
  {
    var point:ImagePoint = new ImagePoint();
    point.x = point.ox = xpos;
    point.y = point.oy = ypos;
    point.maxDist = maxDist;
    points[points.length] = point;

    layout[w][h] = point;

    xpos += IMAGEWIDTH;
  }

  xpos = 150;
  ypos += IMAGEWIDTH;
 }

var l:int = layout.length-1;
var i2:int;
var l2:int;
var imgPoints:ImagePoints;
counterLoader=0;
for(i = 0; i < l; i++)
{
  l2 = layout[i].length-1;
  for(i2 = 0; i2 < l2; i2++)
  {
   imgPoints = new ImagePoints(layout[i][i2], layout[i][i2+1], layout[i+1][i2+1], layout[i+1] [i2]);
   imgPoints.color = Math.random() * 0xCCCCCC;
   images[images.length] = imgPoints;
  }
}

for(i = 0; i < imagenes.length; i++)
{
  bmd.push(new bitmap(imagenes[i]));
  bmd[i].addEventListener("cargado", estaCargado, false, 0, true);
}

  distort = new DistortImage(250, 250);
}

STEP 3. I want to know the image number who has the mouse over

There are some methods to achieve this. We are going to code an easy method, using Rectangle objects. When we are filling the "images" array, we will fill a Rectangles array too:
for(i2 = 0; i2 < l2; i2++)
{
  imgPoints = new ImagePoints(layout[i][i2], layout[i][i2+1], layout[i+1][i2+1], layout[i+1][i2]);
  imgPoints.color = Math.random() * 0xCCCCCC;
  images[images.length] = imgPoints;
  imagerectangles.push(new Rectangle(layout[i][i2].x, layout[i][i2].y, Math.abs(layout[i] [i2+1].x - layout[i][i2].x), Math.abs(layout[i][i2].y-layout[i+1][i2+1].y)));
}

Each Rectangle class will hold the position of each image. So now we only need to use the Contains method to see if the mouse is over certain image. We will use a Number variable "zNum" that will hold the mouse-over image number every time. In the "draw" method:
for(i = 0; i < l; i++)
{
  if (imagerectangles[i].contains(mouseX,mouseY) ) {
  zNum=i;
}
  distort.setTransform(img, bmd[i].getBitmapData(), images[i].tl.point, images[i].tr.point,   images[i].br.point, images[i].bl.point);
}

And the mouse events? The sprite on which all the graphics are drawn is "imgSprite", so add the events to it:
imgSprite.buttonMode = true;
imgSprite.addEventListener(MouseEvent.CLICK, clicked);

and now the function "clicked" will tell us the value of the "zNum" variable:
private function clicked(event:MouseEvent):void {
  trace(String(zNum));
}

6 comments
  • yannb
    16-09-2010 22:22
    Hello, Thanks for sharing, but I have some error when I try your setup, any chance to post source example ? Thanks
  • admin
    18-09-2010 16:32
    Here is: http://iphonema.com/pdf/colwall_imgs_source.zip
  • Gerard Garcia
    10-11-2010 06:56
    Excellent! Thank you for sharing. Can each image be turned into a hyperlink? Muchas gracias. Su trabajo es simple y hermoso.
  • Gerard Garcia
    15-11-2010 10:55
    I'd like to add a hyperlink button with 3 states to the website that you've provided here but when I attempt to do this the colorwall effect no longer works. Please let me know how to add a hyperlink button to the colorwall website. I'm using Flash CS5 and AS3. Please help. Thank you. Gerard Garcia
  • Andres
    04-12-2010 17:53
    Yo también estoy interesado al cargar la imagen desde el xml Pero con link a url algo asi. mono1.jpg mono2.jpg como podre hacerlo? Saludos!!!
  • Jumbosana
    08-01-2011 17:48
    Hi, Yes i would also need to know how to add links to the images through XML.
Leave a comment
I have read and accept the Privacy Policy

The comments sent by each user will always be visible in the corresponding post, and will not be used for any other purpose. The user has the right to access, rectify and suppress said comments, as reflected in our Privacy Policy