Archive for June, 2007

Flex / Twitter App Take 2

Thursday, June 14th, 2007

If you think this looks like any fun and don’t know anything about WPF go check out Kurt Brockett’s blog for an interesting challenge.

Thanks to a great tip from Matt Chotin, from Adobe, in the comments of my previous post I take a massive step forward in the UI department.  Again, the Open Source gods ( is this open source? ) work their magic to give me an even more useful component:  SpringGraph from another Adobe Engineer ( seeing a pattern are we ) named Mark Shepard.  He hasn’t blogged in some time, so I’m not sure he is still doing stuff with Adobe/Flex or blogging but, his component totally rules and fits my needs pretty closely.  Here is the original SpringGraph Demo and the Roamer Demo which is like the SpringGraph just with nodes hidden or collapsed ( which may be the final component I use ).  Well onto, what I’m trying to do:

Shiny New Object

First things first, time to see what makes the SpringGraph tick.  Given my limited knowledge of all things Flash, I had to piece together how the main body of his MXML file even worked. 

<fc:SpringGraph id="s" backgroundColor="#ffffff" lineColor="#333388" left="0" right="0" top="0" bottom="0" itemRenderer="AmazonItemView" repulsionFactor="{rep.value}" > </fc:SpringGraph>

It took me a few minutes to understand the beauty of the itemRenderer system built into Flex.  If you check out the other source objects in Mark’s project you will notice AmazonItem.as and AmazonItemView.as.  Think of this as a mini MVC subsystem.  With a collection of AmazonItem-s being the model, the SpringGraph control being the controller and the AmazonItemView obviously being the view.   This is made clearer when you add the following AS3 snippet to the mix

private var items: Graph; public function addItem(id: String, name: String, linkTo: AmazonItem): AmazonItem { var newItem: AmazonItem = new AmazonItem(id, name); items.add(newItem); if(linkTo != null) items.link(newItem, linkTo); s.dataProvider = items; return newItem; }

What is happening here?  Well as you call the addItem function an instance of the model, AmazonItem is created and added to collection.  This collection is then bound to the dataProvider of the SpringGraph.  When SpringGraph is drawn on the stage it loops at this dataProvider and instantiates a view object named itemRenderer for each item in the dataProvider.  So this allows you to completely change what the SpringGrid is rendering on your behalf — pretty cool, huh?

My “Model”

Now that I think I understand how that component works I need a place to store some data about a Twitter user.  Normally, you could just create a basic class and use that but, in the case of this component it seems you need to subclass the delivered Item class.  Once again, no big deal.  Created a new class called TwitterPerson.  That class has a few attributes:

public class TwitterPerson extends Item { [Bindable]public var screenName:String; [Bindable]public var name:String; [Bindable]public var profile_image:String;

These will store the data returned from the API, I’ve named the attributes nearly the same as the API to make it easier to follow.  The attributes are bindable so that as I fill in the information the “view” will update automatically.  The constructor is uber-simple:

public function TwitterPerson(xml:XML){ screenName = xml.screen_name; name = xml.name; profile_image = xml.profile_image_url; }

To make it as easy as possible to construct the TwitterPerson I just pass in an XML node and map the parameters myself.  If you check out the API you will see that the two services I use “statuses/friends/” and  ”users/show/” return different data but have the same information about each person with the same attribute names ( thanks for the consistency Twitter guys! ).

My “View”

The other piece I need to construct is the view that the SpringGraph will call to render the data stored in the model.  For right now all I want to do is put the picture of the person being rendered up there and give a tool tip for their name.  Flex makes something like this so easy it’s barely worth mentioning but for completeness:

<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"> <mx:Image source="{data.profile_image}" scaleX="1" scaleY="1" toolTip="{data.name}"/> </mx:VBox>

Two Heads are better then one but One’s a start

Back in the main MXML of our application things have changed a bit:

<mx:HTTPService id="myInfoService" url="http://twitter.com/users/show/dan_mcweeney.xml" resultFormat="e4x" result="onMyInfoServiceResult(event)" fault="onMyInfoServiceFailed(event)" /> <fc:SpringGraph id="springLayout" backgroundColor="#ffffff" lineColor="#333388" left="0" right="0" top="0" bottom="0" itemRenderer="TwitterPersonView" repulsionFactor=".80" canDragNodes="false" />

You can see how nice and clean the SpringGraph is to use it was basically a one for one swap of other component.  Another change here is method used to fetch the data.  As you will see in the next section I leave it up to the Model class itself to determine how their friends are, hopefully this will be a good decision architecturally, so the start of the application is to just call the send method of the myInfoService HTTPService.  The result event is then triggered and that’s where everything gets stuck back together again.

At this point if you are following along, which I’m fairly certain no one is, you should get one head floating in the middle of a big white background, yay!  Although the astute observer will notice that I snuck a new method into that last snippet of code: “person.getFriends()”. 

 One head

 

Model^2 Math.pow(Model,2)

As I mentioned eariler I have now moved the getting of friends into the Model.  I did this to hopefully make it easier for some ideas I have in the long run but also to see how to make a HTTPService entirely in AS.  All this method does is ask the Twitter API to for the user’s list of friends:

1 public function getFriends():void{ 2 var friendsService:HTTPService = new HTTPService(); 3 var friends:Array = new Array(); 4 friendsService.url = 5 "http://twitter.com/statuses/friends/" + 6 screenName + ".xml"; 7 friendsService.resultFormat = "e4x"; 8 friendsService.addEventListener(FaultEvent.FAULT, 9 friendsFault); 10 friendsService.addEventListener("result", 11 friendsResult); 12 friendsService.send(); 13 }

The only remaining mystery is what happens in the friendsResult method which gets bound to the “result” event on line 10-11. 

private function friendsResult(result:ResultEvent):void{ var friendsArray:Array = new Array(); for each (var userEntry:XML in result.result.user){ friendsArray.push(new TwitterPerson(userEntry)); } sevenDegress_2(Application.application). onAddFriends(this, friendsArray); }

When the friends HTTPService returns it has a list of all the user’s friends and their current status.  The method just pushes these newly minted TwitterPerson(s) into an array and then calls another mysterious method from the application that contains it.  I don’t know if this is the best way to do this or not — seems like a bad case of statically linking these two objects but it seemed like the easiest way at the time.  This line of code gets the root Application object’s attribute called application and invokes a method on it.  For this to work at compile time though you need to cast that application attribute over to to the specific type of your application hence that funky, sevenDegrees_2 thing you see there.  The source code to that one extra method is also pretty straightforward thanks once again to Mark’s Graph class:

public function onAddFriends(node:TwitterPerson, friendsList:Array):void{ for each (var person:TwitterPerson in friendsList){ people.add(person); people.link(person, node); } }

When the friends HTTPService gets a result it passes it back up to the application which in turn modifies the data provider by adding the new nodes ( via the add() method ) and then linking them to each other ( via the link() method ).  This should now produce the pretty little Poof ball like below:

Poof

 

Hatchet Attack

This control is actually a little too useful for my needs, I don’t really want anyone to be able to drag folks around once they have been placed on the screen so, I have to delve into Mark’s control and get rid of that functionality.  This turned out to be a fairly straightforward:

1 private function mouseDownEvent 2 (event: MouseEvent):void { 3 var now: int = getTimer(); 4 if((now - lastMouseDownTime) < 300) { 5 // it's a double-click 6 var node: GraphNode = _dataProvider.findNode( 7 UIComponent(event.currentTarget)); 8 if(node != null) { 9 dragEnd(event); 10 if(Object(node.view). 11 hasOwnProperty("doubleClick")) 12 Object(node.view).doubleClick(event); 13 } 14 return; 15 } 16 lastMouseDownTime = now; 17 if (_canDragNodes) 18 dragBegin(event); 19 event.stopImmediatePropagation(); 20 }

Beyond the addition of line 17, the only other thing I needed to add was one parameter _canDragNodes ( and its’ getter and setter methods ).  Although it is truly tons of fun to drag the seed member of the graph around and watch all their Twitter Friends fly after them — it’s not really useful.

If you want to see it running live, meaning you really think I’m a liar, here is a link to the Current Version of 7DegreesOfTwitter.

Extreme Programming to the Max

Tuesday, June 12th, 2007

I’ve always thought it would be interesting for people to see what a programmer goes through when creating a new system.  Telling the world where you are getting stuck so others can learn from and/or laugh at your mistakes.  It might also be interesting for people who create languages or frameworks to see a blow by blow of someone learning a new programming language / toolkit — how many times do you get to see that!

I also have wanted to build a Twitter ( hanger-on ) application that shows you your web friends and their friends and their friends and so on — think 6 Degrees of Kevin Bacon but, for Twitter.  I’ve thought about the visualizations for this and feel that Flex/Flash is the only way to go, which I luckily no nothing about!  So, tonight is the first episode of stuff I wish I knew about Flex while building 7DegreesOfTwitter.

I will only be working on this at night and on the weekends so, progress will be slow and sometimes painful.  I may even try and post nightly “builds” somewhere so people can see what I’m up to help give me pointers where required.

A Plan

Here is what i think the visualization should look like ( yes this was done in MS Paint, hopefully I am a better programmer then artist ):

 7degrees

Basically, you should see all your friends circled around your portrait then as you click on a friend it will shift the view so that your friend is now the focus on the screen, and you can move along your web of friends exploring other people’s connection.  Obviously, this whole visualization is rife with opportunity.  Adding some cool like the Mac doc magnify feature would be pretty cool, or even maybe have the whole thing look like a horizon instead of a flat web of people.

First Day 

First thing to do is get two chunks of data out of Twitter using the Twitter API.  The first bit is your list of friends:

<mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; public var myInfo:XML; public var friends:XML; private function onFriendsResult(result:ResultEvent):void{ friends = XML(result.result); } private function onFriendsFault(result:FaultEvent):void{ var error:XML; error = XML(result.fault); } ]]> </mx:Script> <mx:HTTPService id="friendsService" url="http://twitter.com/statuses/friends/dan_mcweeney.xml" resultFormat="e4x" result="onFriendsResult(event)" fault="onFriendsFault(event)"/>

So basically, this is all it takes in Flex to get data from a web service and parse it into an XML document that is easily traversable.  If you don’t know what E4X is neither did I — go read the Wikipedia entry about E4X then have a look at the W3Schools Tutorial on E4X.  Just remember it’s actually a lot easier then you think, no big scary XSLTs here.  The next thing to do was the other piece of data I need, in this case it’s your mug shot associated with your Twitter account:

 

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="friendsService.send()"> <mx:Script> <![CDATA[ import mx.rpc.events.FaultEvent; import mx.rpc.events.ResultEvent; public var myInfo:XML; public var friends:XML; private function onFriendsResult(result:ResultEvent):void{ friends = XML(result.result); myInfoService.send(); } private function onFriendsFault(result:FaultEvent):void{ var error:XML; error = XML(result.fault); } private function onMyInfoServiceResult(result:ResultEvent):void{ myInfo = XML(result.result); myMug.source = myInfo.profile_image_url; } private function onMyInfoServiceFailed(result:FaultEvent):void{ var error:XML; error = XML(result.fault); } ]]> </mx:Script> <mx:HTTPService id="friendsService" url="http://twitter.com/statuses/friends/dan_mcweeney.xml" resultFormat="e4x" result="onFriendsResult(event)" fault="onFriendsFault(event)"/> <mx:HTTPService id="myInfoService" url="http://twitter.com/users/show/dan_mcweeney.xml" resultFormat="e4x" result="onMyInfoServiceResult(event)" fault="onMyInfoServiceFailed(event)"/> <mx:Image id="myMug" source="" horizontalCenter="0" verticalCenter="0" width="48" height="48"/> </mx:Application>

Major additions here are a a new HTTPService to grab my information and also a small slight of hand to keep the two asynchronous services at least somewhat in sync.  In the onFriendsResult function I call the next HTTPService.  This is an easy way to create simple dependencies among asynchronous requests.

The Layout

I started tonight to try and write this myself — and I soon realized I was probably in over my head.  I got up to the point where I am able to calculate the correct radius for a circle to easily hold all of the objects and then where their positions should be in radians around the circle.  The thought of having to write this in Flex made me want to jump out a window, so I thought to myself — maybe someone has already done this. Just then the Red Sea was parted and the open source gods smiled upon me.  Circle Layout was created by Sho Kuwamoto, an Adobe Engineer, it does exactly what I want in terms of layout and some other snazzy stuff with drag and drop.  Here is a demo of the Circle Layout for Flex just press the “Change to Circle” button to see what I am talking about.  It’s a pretty impressive bit of code for my needs though I need to get rid of the drag and drop bits but, for right now I will leave all that in.

So here is the the running code for Iteration 1 of the 7DegreesOfTwitter.  If you want the source just right-click the movie and use the “View Source” menu option.  When asked for a username and password just use your Twitter Log-in info.

Current issues:

  • Only works for me!
  • No clue what will happen when you have lots of friends

Next time?

  • Create a hover over for the images to at least show the name
  • Come up with a way of Clicking on a person then moving to their “circle”

If you find more issues in the code just post a comment — if I’m doing something totally silly please tell me that too!

Once again big thanks to Sho Kuwamoto for saving me having to do any real programming :-)

Flex and SAP, initial impression

Monday, June 11th, 2007

I have to admit developing in Flex makes life very easy. It is very simple to get something going quickly and link it to simple web services. The internal help inside the Flex builder is a great start when you are finding your way and the “Live Docs” web based documentation is really great at filling in more complex holes.

It’s an Adobe( formerly Macromedia product ) so creating very attractive user interfaces is so easy, especially when compared to most SAP delivered options. The best comparison I guess for Flex Builder would be WebDynpros as you can quickly throw together a UI and bind data to it. However, unlike WebDynpro the delivered Flex components are extendable and skinnable. Not only that but you can go as far to build your own Flex components and use existing open source libraries of Flex components. So your options are really limitless.

In working with the tool for a few days the ability to “have your cake and eat it too” in Flex is really nice. You have the ability to do most simple tasks via MXML, the Flex version of a UI layout language, but when you need to really affect how the component responds you can sub-class it in AS and do whatever you want to it.

If you plan on working with Flex and SAP, get Flex 3. The webservice handling in Flex 2 was not very good when used with complex types in webservices. I was losing whole outbound parameters — not good. However, after downloading Flex 3 its seems they have fixed all these problems.

Some of the documentation is still a little disorganized. I found it really hard to find examples of the Advanced Datagrid but, I am in a giving mood so here is the direct link to download Advanced DataGrid Examples, thanks to the Yahoo! Flexcoders group for handing that out. I am sure as they move forward they will better integrate their documentation.