As a simple addition to yesterday's coverflow post, I wanted to show the same example but with loading images via XML. For simplicity sake the XML is loaded and parsed all in the main file.
The structure for our XML is very simple:
-
<?xml version="1.0" encoding="utf-8" ?>
-
<data>
-
<image><![CDATA[images/image1.jpg]]></image>
-
<image><![CDATA[images/image2.jpg]]></image>
-
<image><![CDATA[images/image3.jpg]]></image>
-
<image><![CDATA[images/image5.jpg]]></image>
-
<image><![CDATA[images/image4.jpg]]></image>
-
<image><![CDATA[images/image6.jpg]]></image>
-
<image><![CDATA[images/image7.jpg]]></image>
-
</data>
We simply load our XML file with BulkLoader
-
protected function loadXML():void
-
{
-
bulkInstance = new BulkLoader("bulkInstance");
-
bulkInstance.add(xmlPath);
-
bulkInstance.addEventListener(BulkProgressEvent.COMPLETE, onXMLReady);
-
bulkInstance.start();
-
}
Parse the results, now adding the images to the BulkLoader:
-
protected function onXMLReady(evt:BulkProgressEvent):void
-
{
-
bulkInstance.removeEventListener(BulkProgressEvent.COMPLETE, onXMLReady);
-
bulkInstance.addEventListener(BulkProgressEvent.COMPLETE, onImagesReady);
-
-
var xml:XML = bulkInstance.getXML(xmlPath);
-
var xmlList:XMLList = xml.image;
-
-
for (var i:int = 0; i <xmlList.length(); i++)
-
{
-
var imagePath:String = String(xmlList[i])
-
bulkInstance.add(imagePath);
-
-
//Add path to array for later access
-
images.push(imagePath);
-
}
-
-
//Set our number of items based on how many images we load
-
numItems = images.length;
-
}
When our images are ready we can continue the process of setting up our coverflow. But now using the images we just loaded for our materials.
-
var mat:BitmapMaterial = new BitmapMaterial(bulkInstance.getBitmapData(images[i]));
It's that simple. Be sure to let us know if you find this useful and are able to use it in a project.
Here is the full code:
-
package
-
{
-
import br.com.stimuli.loading.BulkLoader;
-
import br.com.stimuli.loading.BulkProgressEvent;
-
import flash.display.Sprite;
-
import flash.events.MouseEvent;
-
import flash.filters.GlowFilter;
-
import gs.easing.Quint;
-
import gs.TweenLite;
-
import org.papervision3d.events.InteractiveScene3DEvent;
-
import org.papervision3d.materials.BitmapMaterial;
-
import org.papervision3d.objects.DisplayObject3D;
-
import org.papervision3d.objects.primitives.Plane;
-
import org.papervision3d.view.BasicView;
-
-
/**
-
* ...
-
* @author Charlie Schulze, charlie[at]woveninteractive[dot]com
-
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
-
*/
-
-
public class Main extends BasicView
-
{
-
protected var planes:Array = [];
-
protected var images:Array = [];
-
protected var numItems:Number;
-
protected var currentItem:Number = 3;
-
protected var angle:Number = 25;
-
protected var rightBtn:Sprite;
-
protected var leftBtn:Sprite;
-
protected var xmlPath:String = "xml/imageXML.xml";
-
protected var bulkInstance:BulkLoader;
-
-
public function Main():void
-
{
-
//Make sure that your scene is set to interactive
-
super(640, 480, true, true);
-
loadXML();
-
}
-
-
//First load our XML
-
protected function loadXML():void
-
{
-
bulkInstance = new BulkLoader("bulkInstance");
-
bulkInstance.add(xmlPath);
-
bulkInstance.addEventListener(BulkProgressEvent.COMPLETE, onXMLReady);
-
bulkInstance.start();
-
}
-
-
//When our xml is ready parse and load our images
-
protected function onXMLReady(evt:BulkProgressEvent):void
-
{
-
bulkInstance.removeEventListener(BulkProgressEvent.COMPLETE, onXMLReady);
-
bulkInstance.addEventListener(BulkProgressEvent.COMPLETE, onImagesReady);
-
-
var xml:XML = bulkInstance.getXML(xmlPath);
-
var xmlList:XMLList = xml.image;
-
-
for (var i:int = 0; i <xmlList.length(); i++)
-
{
-
var imagePath:String = String(xmlList[i])
-
bulkInstance.add(imagePath);
-
-
//Add path to array for later access
-
images.push(imagePath);
-
}
-
-
//Set our number of items based on how many images we load
-
numItems = images.length;
-
}
-
-
//Images are finished loading we can now create our papervision coverflow
-
protected function onImagesReady(evt:BulkProgressEvent):void
-
{
-
init();
-
}
-
-
protected function init():void
-
{
-
createChildren();
-
createNavigation();
-
animate();
-
startRendering();
-
}
-
protected function createChildren():void
-
{
-
for (var i:int = 0; i <numItems; i++)
-
{
-
//Grab our bitmapData from the bulkLoader using our array of image paths as our key
-
var mat:BitmapMaterial = new BitmapMaterial(bulkInstance.getBitmapData(images[i]));
-
mat.interactive = true;
-
mat.smooth = true;
-
var plane:Plane = new Plane(mat, 280, 351, 4, 4);
-
-
planes.push(plane);
-
-
//Click straight to any plane
-
plane.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, onPlaneClick);
-
-
//Set an id to target current item
-
plane.id = i;
-
-
//Add plane to the scene
-
scene.addChild(plane);
-
}
-
-
camera.zoom = 50;
-
}
-
-
protected function onPlaneClick(evt:InteractiveScene3DEvent):void
-
{
-
currentItem = evt.target.id;
-
animate();
-
}
-
-
//Animate the coverflow left / right based off of currentItems
-
protected function animate():void
-
{
-
for (var i:int = 0; i <planes.length; i++)
-
{
-
var plane:Plane = planes[i];
-
-
//Each if statement will adjust these numbers as needed
-
var planeX:Number = 0;
-
var planeZ:Number = -50;
-
var planeRotationY:Number = 0
-
-
//Place & Animate Center Item
-
if (i == currentItem)
-
{
-
planeZ = -300
-
-
TweenLite.to(plane, 1, { rotationY:planeRotationY,x:planeX,z:planeZ, ease:Quint.easeInOut } );
-
}
-
-
//Place & Animate Right Items
-
if(i> currentItem)
-
{
-
planeX = (i - currentItem + 1) * 120;
-
planeRotationY = angle + 10 * (i - currentItem);
-
-
TweenLite.to(plane, 1, { rotationY:planeRotationY,x:planeX,z:planeZ, ease:Quint.easeInOut } );
-
}
-
-
//Place & Animate Left Items
-
if (i <currentItem)
-
{
-
planeX = (currentItem - i + 1) * -120;
-
planeRotationY = -angle - 10 * (currentItem - i);
-
-
TweenLite.to(plane, 1, { rotationY:planeRotationY,x:planeX,z:planeZ, ease:Quint.easeInOut } );
-
}
-
}
-
}
-
-
/*
-
* Everything below this point is just for creating the buttons and
-
* setting button events for controlling the coverflow.
-
*/
-
-
protected function createNavigation():void
-
{
-
//Create / Add Buttons
-
rightBtn = createButton();
-
leftBtn = createButton();
-
-
addChild(leftBtn);
-
addChild(rightBtn);
-
-
//Add button listeners
-
rightBtn.buttonMode = true;
-
leftBtn.buttonMode = true;
-
rightBtn.addEventListener(MouseEvent.CLICK, buttonClick);
-
leftBtn.addEventListener(MouseEvent.CLICK, buttonClick);
-
-
//Place buttons on stage
-
rightBtn.x = stage.stageWidth - 20;
-
leftBtn.x = 20;
-
rightBtn.y = stage.stageHeight / 2;
-
leftBtn.y = (stage.stageHeight / 2) + 20;
-
leftBtn.rotation = 180;
-
}
-
-
//Button actions
-
protected function buttonClick(evt:MouseEvent):void
-
{
-
switch (evt.target)
-
{
-
case rightBtn:
-
currentItem ++
-
break;
-
-
case leftBtn:
-
currentItem --;
-
break;
-
}
-
-
//Don't allow any number lower than 0 or past max so there
-
//is always a center item
-
-
if (currentItem <0)
-
{
-
currentItem = 0;
-
}
-
if (currentItem> (planes.length - 1))
-
{
-
currentItem = planes.length - 1;
-
}
-
-
//Call animation
-
animate();
-
}
-
-
//Creates a simple arrow shape / returns the sprite
-
protected function createButton():Sprite
-
{
-
var btn:Sprite = new Sprite();
-
-
btn.graphics.beginFill(0x333333);
-
btn.graphics.moveTo(0, 0);
-
btn.graphics.lineTo(0, 20);
-
btn.graphics.lineTo(10, 10);
-
btn.graphics.lineTo(0, 0);
-
btn.graphics.endFill();
-
btn.filters = [new GlowFilter(0xFFFFFF,1,10,10,3)]
-
return btn;
-
}
-
}
-
}



Why do you use “InteractiveScene3DEvent” for a plane instead of a MouseEvent?
Nate
When you’re applying these types of events to a Plane object you need to use InteractiveScene3DEvent. You can apply MouseEvents to MovieClips and Sprites which are sometimes used with materials of Planes.
Cool Component! Thanks. I tried to add it into a Flex project and it almost worked. It hung up sometime after loading the iphone picture. Thanks for any tips!
<![CDATA[
import mx.core.UIComponent;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.filters.GlowFilter;
import gs.easing.Quint;
import gs.TweenLite;
import org.papervision3d.events.InteractiveScene3DEvent;
import org.papervision3d.materials.BitmapFileMaterial;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.view.BasicView;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.render.BasicRenderEngine;
/**
* ...
* @author Charlie Schulze, charlie[at]woveninteractive[dot]com
* Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
*/
protected var planes:Array = [];
protected var numItems:Number = 7;
protected var currentItem:Number = 3;
protected var angle:Number = 25;
protected var mat:BitmapFileMaterial;
protected var view:BasicView;
public function init():void
{
//Make sure that your scene is set to interactive
view = new BasicView(640, 480, true, true, CameraType.TARGET);
view.renderer = new BasicRenderEngine();
// these 3 lines are key to putting Papervision in Flex
var uicomp:UIComponent = new UIComponent();
GallerycanvasPv3D.addChild( uicomp );
uicomp.addChild( view );
Main();
}
protected function Main():void
{
makeChildren();
//createNavigation();
animate();
view.singleRender();
}
protected function makeChildren():void
{
//Create Material
mat = new BitmapFileMaterial("images/iPhone-back2.png");
mat.smooth = true;
mat.interactive = true;
for (var i:int = 0; i < numItems; i++)
{
var plane:Plane = new Plane(mat, 177, 334, 4, 4);
planes.push(plane);
//Click straight to any plane
plane.addEventListener(InteractiveScene3DEvent.OBJECT_PRESS, onPlaneClick);
//Set an id to target current item
plane.id = i;
//Add plane to the scene
view.scene.addChild(plane);
}
//cam.zoom = 60;
}
protected function onPlaneClick(evt:InteractiveScene3DEvent):void
{
currentItem = evt.target.id;
animate();
}
//Animate the coverflow left / right based off of currentItems
protected function animate():void
{
for (var i:int = 0; i currentItem)
{
planeX = (i – currentItem + 1) * 120;
planeRotationY = angle + 10 * (i – currentItem);
TweenLite.to(plane, 1, { rotationY:planeRotationY,x:planeX,z:planeZ, ease:Quint.easeInOut } );
}
//Place & Animate Left Items
if (i < currentItem)
{
planeX = (currentItem – i + 1) * -120;
planeRotationY = -angle – 10 * (currentItem – i);
TweenLite.to(plane, 1, { rotationY:planeRotationY,x:planeX,z:planeZ, ease:Quint.easeInOut } );
}
}
}
/*
* Everything below this point is just for creating the buttons and
* setting button events for controlling the coverflow.
*/
//Button actions
protected function buttonClick(evt:MouseEvent):void
{
switch (evt.target)
{
case rightBtn:
currentItem ++
break;
case leftBtn:
currentItem –;
break;
}
//Don't allow any number lower than 0 or past max so there
//is always a center item
if (currentItem (planes.length – 1))
{
currentItem = planes.length – 1;
}
//Call animation
animate();
}
]]>
Hey Chuck,
Sorry for the late reply. I am not sure if you got this coverflow fully working in Flex yet. Here is an example of this class working with Flex.
http://pastebin.com/f6566f277
Charlie
I’m pretty new to this, so I was wondering if its possible to add a link from each photo inside of the XML?
Hey Charlie. First off. I absolutely love your work. Quick and esay to get an overview of, even for a relative newb as me. I’m having a bit of a problem though. It’s most likely a straight forward fix, but if I wanted to add a textfield to the Coverflow somewhere on the stage, and then have the titles for the individual pictures show up in said textfield, how would I go about doing that? Both how the content of the .xml file should look, and how I should retrive it using bulkLoader. I’m not at all familiar with bulkloader, and I don’t know if that’s the thing that has got me stumped.
I really hope you can help me.
Hey Charlie. First off. I absolutely love your work. Quick and easy to get an overview of, even for a relative newb as me. I’m having a bit of a problem though. It’s most likely a straight forward fix, but if I wanted to add a textfield to the Coverflow somewhere on the stage, and then have the titles for the individual pictures show up in said textfield, how would I go about doing that? Both how the content of the .xml file should look, and how I should retrieve it using bulkLoader. I’m not at all familiar with bulkloader, and I don’t know if that’s the thing that has got me stumped.
I really hope you can help me.
could you teach me how to create a buttton(such as”BACK TO INDEX”or “NEXT PAGE”) in the pv3D scene?
@Johan
Ive not used bulkloader myself but it should be pretty straight forward to get it working.
Your XML image nodes should look like this :-
“IMAGE URL HERE”
“Title Here”
Then you make a dynamic textfield on the stage and give it an instance name for example “title_txt”
Then in buttonClick function just after the first switch and case add a line something like this :- title_txt.text = xmlList[currentItem].imageTitle;
Im not the best at AS3, still pretty new to it myself so it might not be the best way, might not even work for you. but i hope that gets you on the right tracks
**EDIT
Oops it cut out the nodes for the xml.. within each image just add a new child of imageTitle and then add the title inside of that :)
Hi,
Let me ask you… is possible add reflection effect to the images ?
How hard is?
It would be a nice idea a tutorial rsrs
Thanks, nice work!