Word. I’ve been trying to figure out how to make a 3D Flex UIComponent with Papervision 2 for a while now and have come up with a system that seems to work. I learned a lot from the YahooMapInPV3D AIR example, as well as a ton of other random posts. Check out this demo and see the source code:
How it Works…
The important class is the FlexBasicView. This extends Papervision’s BasicView, making it easy to just add whatever 3D objects you want and to apply MovieMaterials to them all in one place, separate from the main Flex application. In this class, a few things happen.
First, you create a main DisplayObject3D called sceneManipulationContainer into which you are going to add your Flex-skinned Papervision 3D objects (planes, cubes, etc.) for easy manipulation. You add that to the FlexBasicView. The next thing is the most important: renderMovieClips(). This packages your UIComponents, which themselves can only be instantiated 3 children down from the main application (for now at least), into a movieClip that is used to create the MovieMaterial. Once that movieClip is made, you then pass it to the MovieMaterial. Then you create your DisplayObject3D (Plane in this case), and add your material, which is basically a thick nest => material(movie(uiComponent)).
The movie movieClip (the one used for the material) is then added to a parent movieClip, called movieParent. And this movieParent is added to the FlexBasicView.
After this, another important step must take place, and this is straight from the YahooMapInPV3D example. You first add an event listener for the plane (InteractiveScene3DEvent.OBJECT_MOVE). Then once the object is created and there is movement, this event is handled by the method skinDisplayObject3D(). What this does is align the movieClip/bundle/material into the right place on the Plane. Strange… But it works!!!
All you have to do now to add custom Flex UIComponents onto this plane is to 1) get a reference to your uiComponent which is 3 levels down from the main application, and 2) pass them into a movieClip which then is passed into the “movie” movieClip:
var newMovieClip:MovieClip() = newMovieClip();
newMovieClip(Application.application.myUIComponent);
movie.addChild(newMovieClip);
Better Design Patterns for the Future
I would like to have separated this FlexBasicView into more well defined classes, but I don’t have the time right now to dig that deep. Basically, you would create a UIComponentMaterial class that did all the movieClip configuration, and this would take in a UIComponent from the 3-level-down location. To make this so you don’t have to do Application.application.myComponent, it would be nice to create this on the main app, and to have a method like UIComponentMaterial.addUIComponent(myComponent) that took care of everything for you. However, the UIComponent you use for the MovieMaterial skin must also have a reference to the DisplayObject3D in order to become the correct width and height and whatnot, so this might get tricky. John Grden’sWinterWonderland screencast, which is a pretty hardcore example of what papervision can do, has an excellent example of how to let the movieClip used to make a MovieMaterial have reference to its parent MovieMaterial AND the DisplayObject3D it’s skinning. It’s pretty neat, and maybe that can be applied in this situation.
The goal would be a scenario something like this:
-In the main application mxml file, add the 2 canvases and make the 3rd layer “FlexBasicView”
-Then it would be nice to be able to just put some MXML nested in the FlexBasicView tag that created Papervision components skinned with your UIComponent. Something like this:
<Application><Canvasid="pv3dContainer"><me:FlexBasicViewid="flexBasicView"><me:sceneManipulationContainer><me:FlexPlaneid="extendsDisplayObject3D"material="{myUIComponent}"></me:FlexPlane><me:FlexCubeid="alsoExtendsDisplayObject3D"><me:MaterialList><Lots of Materials with UIComponent references></me:MaterialList></me:FlexCube></me:sceneManipulationContainer></me:FlexBasicView><Canvasid="2ndLayer"><me:CommentBoxid="myCommentUIComponent"/><me:ProfileBoxid="myProfileUIComponent"/><me:CustomBoxid="myUIComponent"/></Canvas></Canvas></Application>
Another way of doing that would be to stop at the level, and then do the rest in Actionscript so you could have a little more control. If any of you guys have any ideas or suggestions, please comment!
Now for the glitches…
Some things I’ve noticed.
1) You’ll notice I have a custom Font in the assets folder. This is because, for some reason, the Text appears in the top left corner if you use Flex’s default font. The main glitch you get in all cases is something unexpected appearing in the left corner.
2) If you nest things too deeply, you will get a white box appearing in the top left corner. This seems to be somewhat arbitrary and I haven’t pinpointed the reason why it happens. For example, if you add another nested DataGrid into the CommentBox that comes with the source code, nesting it into a FormItem (just for testing purposes), the white box glitch appears. Maybe I am missing something about the way Flex UIComponents are supposed to be nested? This also happens in more normal cases.
3) Sometimes there are differences between Flex Boxes vs. Panels/Canvases. I’ve had HBoxes show the white box in the corner too…
4) In the renderMovieClips() function in FlexBasicView, there are many ways to addChild the movieClips. Sometimes it works with just one. Sometimes every nested UIComponent should get their own newMovieClip, and then you add all of them in the order you want to a main movieClip as shown above.
5) Things with Popups don’t work well, such as the ComboBox. And there’s no way to capture the Popup from that class unless you change either the PopupManager or create a CustomComboBox. You can grab the Combobox.dropdown, but it also tweens, so it’s sketchy.
6) The scrollbar is jumpy.
7) In some situations you can comment out //movieParent.addChild(movie) and //addChild(movieParent) and you’ll still see it work, in other situations you won’t.
If the width of your component is not a % (like width=”100%”), it may create that white box in the corner. That is, if your width is an absolute value.
9) Sometimes, if you add your UIComponent in MXML it won’t work. So you just do it in actionscript. But sometimes you can also add your UIComponent in MXML, and also say “addChild(myComponent)” in actionscript at it will work.
Flex and Papervision Don’t Mix Well…
But with enough time, it’s definitely possible
As you can see, this is very rough; there’s no real system for making Papervision Flex UIComponents yet, though I wish there was! Maybe the guys from OutSmart can shed some of their wisdom… I have just found that there are no examples on the internet of this being successfully done, and done in such a way that you can switch out components easily and apply it to different DisplayObject3D’s. So I’m throwin this out there for everyone to mess around with
Needless to say, Flex doesn’t play very well with Papervision, at least in my experience. Sure there are a few examples on the web of using Sprites in Flex, like the 3d product gallery, but the real goal is to have 3D Flex UIComponents. If anyone knows of a better way to do this, by all means let us know. I’m looking forward to seeing how this can be done better.
I love my morning espresso and biscotti! Strada is a Godsend.
This is going to be my first complete tutorial for the Social Computing world on how to use the most cutting edge open source Enterprise Web 2.0 Application Framework ever, Ruboss. Check it out! With a community of active Ruboss contributors, we will, in very short order, take the internet by storm. Building websites like Facebook or Youtube or Digg with an interactive Flash and/or Flex interface will be so insanely simple (Heroku for the backend server scaling) that any one individual could support such a data-driven madhouse. Add to this all of the functionalities of web services available (google maps, amazon, salesforce …), and we have an information revolution.
But in order to get to this point, some key principles must be well understood. These are found within DESIGN PATTERNS, and the principles of REST. With the publication of Design Patterns - Elements of Reusable Object-Oriented Software Fall of 1994, the Gang of Four ushered in a new age of building scalable, reusable, and extremely well-defined software components. J2EE, the Java 2 Enterprise Edition, then implemented and expanded on these core Design Patterns into the famous MVC (Model View Controller) application framework. However, they and no software other group or company has, for one reason or another, been able to unite together and implement a powerful AND well excepted Web Application Framework for building amazing, highly structured, and repeatable software components based on design patterns.
Enter Flex, Cairngorm, and Ruby on Rails.
2004 was a BIG year… Flex packages Actionscript into an XML document, Cairngorm packages Flex XML Documents into an Enterprise application that can efficiently talk to a backend database, and Ruby on Rails comes out and revolutionizes the way people around the globe build software and web applications. Everyone is super excited.
Flex takes Actionscript, the most widely adopted and interactive-friendly programming language to hit the internet and turns it into basically an XML document, so what took 10 lines of code in Actionscript now takes only 1 line in Flex XML (MXML for Macromedia XML). Actionscript and Flash by themselves took over the interactive market. At around the same time, a few Adobe consultants recognized the limitations faced by J2EE developers when building Rich Internet Applications and released Cairngorm for Flex, an Enterprise level Warning: gzuncompress() [function.gzuncompress]: data error in /home/.zwingli/lancorn411/systemsofseven.com/blog/wp-content/plugins/easyswf.php on line 255
.
David Heinemeier Hansson, creator of Rails, saw the inefficiencies and repetitives tasks required to build web applications and used cutting edge design patterns to automate almost all of these commonalities using the dynamic programming language Ruby.
Now, in 2008, Peter Armstrong and Dima Berastau have integrated Flex and Ruby on Rails into the most powerful, highly efficient, and scalable Rich Web Application Framework, Ruboss. This is it! What all of these frameworks have in common is very well thought out design patterns that allow us to think about building software on the web like scientists, something that most other programming languages are leaving out of the picture and which is hurting them tremendously.
Design Patterns and the Evolution of the Universe
Design Patterns are the best things to have hit the software world in my opinion. They tie software development perfectly into the evolutionary process of the universe. Once they are set into place, you no longer have to think about the implementation details because they follow consistent patterns. This is the basis of evolution: as complexity arises, patterns emerge from these complexities and ultimately become new entities themselves. And as these entities grow in number, they create a new complex system out of which new patterns arise, on and on and on into the infinite…
Energy condenses into atoms; atoms condense into molecules; molecules into cells; cells into organisms; organisms into intelligent organisms. Thoughts become encapsulated into words, which are strung together into sentences and stories, and sent as signals to other human beings for them to unpack and understand and integrate into their own being. Ken Wilber, a prominent philosopher today, has come up with a universal theory of how all things in the universe are modeled, as holons, or whole-parts, and this can be seen in design patterns. With patterns implement at all levels, we can focus on the highest level, which is, ultimately, our own experience in the world–our ideas and our communication of those ideas to other people.
We are now at the point of implementing these evolutionary design patterns into the web to create a foundation of richly interactive and database driven content, freely accessible and modifiable by the social computers, us. I recommend these books and people, in no particular order, to get going on understanding design patterns and their implementation for the evolution of the social web:
And the second important principle is REST, Representational State Transfer. If there is one things that needlessly increases the complexity of a software application, its creating un-RESTful methods when they can be RESTful. In short, all actions between a User Interface and a Database can be mapped onto four simple HTTP methods: GET, POST, UPDATE, and DELETE. These four methods comprise the Universal Interface. Before this design pattern was discovered/revealed, it was often difficult to tell how to do certain things to data in a database. But recognizing that you only need to do these four things, ALL of the thinking is done for you, AND we now have a template by which all Flex UIComponents access a database. Now if you want to make a blog post component for instance, know that it only needs to implement those four methods; same for most everything else.
In order to hasten the evolution of the social interactive web, I recommend getting to know these books well, along with the ones above, as they are the basis of everything in this tutorial:
Ruboss currently consists of a Flex front end and a Ruby on Rails back end. Ruby on Rails then uses ActiveRecord (Martin Fowler’s design pattern) to access the database, abstracting away all the complicated SQL. I have also modified the Ruboss plugin to include the ability to load files to/from the server from Flex and to create authenticated users. Download it for the tutorial.
To get you started using Ruboss, make sure you have installed Ruby, Rails, Mongrel, Flex 3 (or the Flex 3 SDK), and MySQL. Then download the plugin-enhanced Ruboss. We will first create a single Flex UIComponent, a blog “Post”, and see how everything is wired together. Then we will add to it to create the beginnings of a Flexible Blog, which, in short order, can surely be made into an open source Flexible Social Networking Platform.
Creating a Flex UIComponent with Ruboss…
Let’s start by creating a new project called “flexible_blog” in rails:
Now run the rconfig command to generate Flex and Rails scaffolding for the application (”scaffolds” are just predefined template classes to get you going, taking most of the initial work out of the project):
If you haven’t yet set a root password for MySQL, type the following:
sudo mysqladmin -u root password your_password
Now we will generate a scaffold for a blog “Post” and rerun rconfig to wire up the Flex Application controller and the events with the models, views, and commands. Our blog Post will have a title, a subtitle, a body, an author, a published boolean, and a created_at date. Also, to make it authenticated, we will say that it belongs_to a user, an authenticated User.
The last line doesn’t matter (I’ll fix that later). The rscaffold command creates for you:
For Ruby on Rails:
posts_controller.rb => controller
post.rb => model
create_posts.rb => migration
posts_helper.rb => helper (does nothing now)
posts.yml => yaml scaffold
map.resources :posts => routing for posts
For Flex:
Post.as => model
PostBox.mxml => view UIComponent
PostCommand.as => command
Ruboss for Ruby on Rails - The Main Parts
The Post Controller:
The posts_controller defines 6 RESTful methods, all based off the four basic HTTP methods: GET, POST, UPDATE, and DELETE:
index => retrieves all of the posts (based on user if you specify with_user)
show => retrieves a specific Post
new => refreshes the page if an error occurs, it is not used by Ruboss
create => creates and saves a new Post into the database
update => edits the Post if you have modified it
destroy => deletes a specific Post from the database
posts_controller.rb
class PostsController < ApplicationController
# GET /posts# GET /posts.xml# GET /posts.fxmldef index
@posts = current_user.posts
respond_to do|format|format.html# index.html.erbformat.xml{ render :xml=>@posts}format.fxml{ render :xml=>@posts}endend# GET /posts/1# GET /posts/1.xml# GET /posts/1.fxmldef show
@post = current_user.posts.find(params[:id])
respond_to do|format|format.html# show.html.erbformat.xml{ render :xml=>@post}format.fxml{ render :xml=>@post}endend# GET /posts/new# GET /posts/new.xmldef new
@post = Post.new
respond_to do|format|format.html# new.html.erbformat.xml{ render :xml=>@post}endend# GET /posts/1/editdef edit
@post = current_user.posts.find(params[:id])rescueActiveRecord::RecordNotFound=> e
prevent_access(e)end# POST /posts# POST /posts.xml# POST /posts.fxmldef create
@post = current_user.posts.new(params[:post])
respond_to do|format|if@post.save
flash[:notice] = 'Post was successfully created.'format.html{ redirect_to(@post)}format.xml{ render :xml=>@post, :status=>:created, :location=>@post}format.fxml{ render :xml=>@post}elseformat.html{ render :action=>"new"}format.xml{ render :xml=>@post.errors, :status=>:unprocessable_entity}format.fxml{ render :xml=>@post.errors}endendend# PUT /posts/1# PUT /posts/1.xml# PUT /posts/1.fxmldef update
@post = current_user.posts.find(params[:id])
respond_to do|format|if@post.update_attributes(params[:post])
flash[:notice] = 'Post was successfully updated.'format.html{ redirect_to(@post)}format.xml{ head :ok}format.fxml{ render :xml=>@post}elseformat.html{ render :action=>"edit"}format.xml{ render :xml=>@post.errors, :status=>:unprocessable_entity}format.fxml{ render :xml=>@post.errors}endendend# DELETE /posts/1# DELETE /posts/1.xml# DELETE /posts/1.fxmldef destroy
@post = current_user.posts.find(params[:id])@post.destroy
respond_to do|format|format.html{ redirect_to(posts_url)}format.xml{ head :ok}format.fxml{ render :xml=>@post}endendend
Each Rails controller is called from Flex’s HTTPService request, and the routes.rb file determines how to route the HTTP request to the appropriate controller. Ruboss added the following to the routes.rb file to make this happen:
map.resources:posts
The appropriate method is then executed in the controller. Then controller the talks to the database using methods on the Post model such as Post.find(:all) or Post.new(), and the result is then formatted into HTML, XML, or FXML (or even JSON or AMF if you’d like!). Flex then receives this data and updates its view! Cake.
Note: I’ve included/created the last argument, with_user, to wire the Ruby posts_controller for restful_authentication, so it can only access the posts that our user is authorized to access. It should be named with the same thing you call your user model (user, person, human, entity, …). if you leave this out, then the controller will retrieve all files regardless of the user. The subtle difference looks like this, for finding all Posts related to one user:
Ruboss generates a Post model that only has code for its associations, in this case, that it belongs_to the user model:
post.rb
class Post <ActiveRecord::Base
belongs_to :userend
The Post Migration:
Ruboss creates this Rails migrations file for our Post automatically:
001_create_posts.rb
class CreatePosts <ActiveRecord::Migrationdefself.up
create_table :postsdo|t|
t.string:title
t.string:subtitle
t.text:body
t.string:author
t.boolean:published
t.date:created_at# belongs_to the following...
t.references:user
t.timestampsendenddefself.down
drop_table :postsendend
All of the arguments you typed into the command line are mapped here, allowing you to create a posts database table with all of those columns by typing a simple command: rake db:migrate. Migrations are powerful because if you later decide you want to add a number_of_comments column to your posts table, you can easily do that!
Ruboss for Flex - The Main Parts
The Post Model:
Ruboss creates an Actionscript Model class that is essentially a map of the database model found in the create_posts migrations file. It is a Bindable class too, so you can assign any of the variables to values easily in a Flex UIComponent. It also extends the RubossModel class, allowing you to call RESTful methods directly from the Post model. Here’s the class (you don’t need to modify it):
Ruboss generates for you a sample Flex UIComponent to visualize your data! It uses a Datagrid to display all of your database listings, and input boxes to write to the database. Here is the PostBox.mxml file: