Wednesday, May 31, 2006

Override Native Object Methods in Flex 1.5 / Flash 8 /Actionscript 2.0

It is common knowledge that you can extend native classes in Actionscript 2.0 using the prototype inheritance model... Did you know that you can also override native objects and their methods in Flex 1.5 / Flash 8 / Actionscript 2.0 very easily?

This means that you can replace existing functionality with your own logic, or you can extend the functionality of existing objects & methods to suit your custom needs.

Here's a quick example... This example isn't particularly useful, but it exemplifies the concept well.

var old = _global.Array['prototype']['toString'];
_global.Array['prototype']['toString'] = function(){
   return "This is the overrided toString method for the Array Object.";
}
_global.Array['prototype']['toString'].old = old;

Now, when you invoke the toString method (as shown below), the result will be from the overrided function.
var test:Array = new Array();
mx.controls.Alert.show(test.toString());

I can hear it now... You are saying "Okay, thats great, so why would you want to do this?". It actually can be particularly useful. Let me give you a couple of scenarios:

  • Override the XML object's sendAndLoad method to append a unique string on the end of the request to prevent caching within the browser/flash player.
    var old = _global.XML['prototype']['sendAndLoad'];
    _global.XML['prototype']['sendAndLoad'] = function(){
    arguments[0] = arguments[0] + "?rand=" + Math.random().toString();
    return arguments.callee.old.apply( this , arguments );
    }
    _global.XML['prototype']['sendAndLoad'].old = old;

  • Override the XML object's sendAndLoad method to preload WSDL doucments within the swf. This reduces the amount of time it takes to initialize web services and reduces the number of callbacks to the web server, although it slightly increases the download size/time for your swf. I personally like this method beause there is less "lag time" in application initialization. This should get you going in the right direction:

    _global.WSDLObjects = {};
    _global.WSDLObjects['/application/services/TestService?WSDL'] = '<?xml version="1.0" encoding="UTF-8"?><wsdl:definitions> ...WSDL DEFINITION GOES HERE ... </wsdl:wsdl:definitions>';

    var old = _global.XML['prototype']['sendAndLoad'];
    _global.XML['prototype']['sendAndLoad'] = function(){
    var wsdlURL = arguments[0].slice(arguments[0].indexOf("/application"));

    if( _global.WSDLObjects[wsdlURL] != undefined){
    arguments[1].onData( _global.WSDLObjects[wsdlURL] )
    return true;
    }else{
    return arguments.callee.old.apply( this , arguments );
    }
    }
    _global.XML['prototype']['sendAndLoad'].old = old;

I am not sure how well this will work in Flex 2 / Actionscript 3.0. Adobe has made signifigant changes to the prototype inheritance model and now supports class inheritance. I've heard that access to the prototype of native objects is restricted... I'll have to look into this more in the future. In AS3, you can definitely extend a native object class and override the existing functionality.

6/13/06 Just another note...
In order to have the example for preloading work correctly, you must use a custom preloader, and you must override the native xml object within the custom preloader. Otherwise, there is no way to get to the native xml object before initialization of your web servies begins.

Sunday, May 21, 2006

Yahoo! Maps API

Yahoo! Maps has provided the developer community with a really easy to use API for interfacing with the Yahoo Maps (beta) tool. I started toying with it last night, and found it to be quite interesting and fun. I've done work in the past with the Google Maps API, and there are a few things that I like better in the Yahoo! Implementation...

No Geocoding Necessary!
The Yahoo Maps API will automatically resolve a location to a latitude/longitude for you. You only need to pass an address (string) into the map's setCenterByAddress function, and it will do all the work for you. You have the option to specify a location by latitude/longitude if you need/want to, but it is not necessary. The Google Maps API requires you to register all points in the map by using a latitude longitude pair. Yahoo has done us a favor and has taken the burden of geocoding addresses out of our hands. You can create your own geocoding logic if you want, but it is not necessary.

Multiple Programming Interfaces
Google Maps only supports development using their JavaScript API. Yahoo supports development using Javascript, Flash, and/or Flex. Although javascript support is widespread to nearly every browser in use today, it has a few drawbacks. First, the Google maps functionality is not supported in every browser. Although it will work in most modern browsers, you will have to develop and test your javascript code to support multiple platforms. Not all browsers are created equal, and although your javascript code may work in IE, there is a good chance that the exact same code will not work in Safari or Opera. Using the Yahoo Maps API, you can develop tools several ways. You can develop them using Javascript, similar to the Google implementation... OR you can develop them into Flash/Flex RIAs. Some people will complain that Yahoo requires the use of the Adobe (Macromedia) Flash runtime. They don't like relying on a third party tool. I don't agree.
Macromedia Flash Player from Adobe is the world's most pervasive software platform, used by over 2 million professionals and reaching more than 97% of Internet-enabled desktops worldwide as well as a wide range of devices.
As you can see, Flash is everywhere. 97% of internet enabled computers already have the required components installed on their machines. You only need to write your application once, and it will run on all of those machines. You don't have to create custom functions for each browser implementation.

Here's an example application that I put together last night using the Yahoo! Maps API and examples. It was extremely easy to put together. The API documentation had great examples and was very easy to follow.

WebCam in Flash 8 - Part I

I came across some really neat effects using a web cam as an input device... Yes, you can make flash respond to changes in a live video stream. You should check some out, they are really cool (there are some viewable demos, but you will need a web cam to interact with them):

http://incomplet.gskinner.com/index2.html#fluiddynamics
http://www.playdocam.com/

After viewing these I started thinking about how this works, and can I make it work too. I got so intrigued that I went out the other day and bought a web cam so that I can start testing these techniques.

First off, it is really easy to utilize a web cam in flash. It only takes a few lines of actionscript code to invoke the camera object. You will need a null video object on your stage... my video instance is called "video_out". Use this code to get a referrence to the camera object, set the resolution at 640x480, and the frame rate to 30 fps (if your camera supports it):

var activeCamera = Camera.get();
activeCamera.setMode(640, 480, 30);
video_out.attachVideo(activeCamera);

Next, I started looking for any information that I could find on how to detect motion within a flash video. There is a tutorial from adobe that describes a tecnique for detecting motion changes in video, but I haven't had enough time to really look into it yet (Thus the reason that this post is part 1).

Anyway... here is my progress so far. It's just a live camera feed within a swf. More changes will come as I find more time to pursue this.

Launch Live Video Test

Tuesday, May 16, 2006

Video Player in Flash 8

Oh my gosh... Using video in Flash is ridiculously easy. Seriously. I created a pretty advanced video player today, in a matter of minutes. You can create a simple video player in a matter of minutes just by going to the File menu and importing a clip (File --> Import --> Import Video...). Follow the steps of the wizard, and then you "magically" have a great video player that looks good. Its really that easy. If you select the "Progressive download from a web server" option, it will create a player that loads a flv file progressively... so not only does it look good, but it is also FAST.

I took some time and created a more advanced player, but it still only took a few hours (that includes tracking down videos to test it). For my video player, I used the FLVPlayback component. The player takes in an xml file name as an initial parameter. It then loads and parses the xml to determine a list of media clips and their titles, and then displays the content in a drop-down selection list. When you change the selected item in the list, it changes movie clip. Its quick and easy.

Check it out: Launch the Video Player (this requires flash 8)

Not only is it cool, but it is reusable. Just by changing the contents.xml file, you can use it to dislpay a completely different series of videos. You could have the XML be dynamcially created based on a search or user preferences. Using this approach, you can have a really cool context-based video clip series. The possibilities really are limitless. I hope everyone else enjoys this as much as I do.

Monday, May 08, 2006

My Javascript Toolkit - Command Line & Debugging Tools

My javascript toolkit is a set of resources that can help aid in the development of javascript-heavy or AJAX style applications. I encourage the use, enhancement and distribution of this javascript library. I hope that you find it useful as well.

You can download the toolkit here:
http://www.tricedesigns.com/portfolio/js_toolkit/JavaScriptToolKit.js

There are four major components to the Javascript Toolkit. They are not necessarily "pretty" yet, but they are very useful. Each is described on this page. Use the following links to see a demo of each.

CommandPrompt

The CommandPrompt object is simply a command line interface for javascript, within a web page. Just type javascript commands into the text box and hit enter, and your code is executed. It is built so that it can easily be added to any page. From within it, you can call any javascript command, get or set the value of any existing variable within the page, or evaluate expressions. Although, It is still subject to the rules of your browser's security model.
An instance of the CommandPrompt object can be created as easily as this:

<script>
   var cmdPrompt = new CommandPrompt();
</script>

...And it is written such that there can be multiple instances of the
CommandPrompt per browser instance (in the random event that you actually need this).
CommandArea

The CommandArea object is another a command line interface for javascript, within a web page. All internal functionality is identical to the CommandPrompt. The only difference is how you enter the javascript commands. Instead of having a textbox, and listening for the kepress event on the enter key. The CommandArea object uses a multiline textarea control, to allow you to inject longer code chunks and values.
It is also built so that it can easily be added to any page. From within the CommandArea, you can also call any javascript command, get or set the value of any existing variable within the page, or evaluate expressions. One thing to keep in mind is that functions defined within the CommandArea are only accessible during code execution. For example, if you define a function within the CommandArea and execute it, then go and change the contents of the CommandArea... your function will be gone.

An instance of the CommandArea object can be created as easily as this:

<script>
   var cmdArea = new CommandArea();
</script>

...And it is also written such that there can be multiple instances of the
CommandArea per browser instance.

VarWatch

The VarWatch object is a usefull debugging tool. It is designed to watch the values of your javascript variables during code execution. You can either programmatically add variables to the watch list, or you can add them during runtime through the user interface. The VarWatch object will display a list of all variables that you are watching, and their corresponding values will be updated every 500 millisecond.



An instance of the VarWatch object can be created, and variables assigned to it as easily as this:
<script>
   //create varWatch
   var varWatch = new VarWatch();

   ////assign values
   varWatch.addWatch("Math.random()");
   varWatch.addWatch("Math.PI");
   varWatch.addWatch("myVariable");
</script>

DebugConsole

The DebugConsole object is an easy way to create both a VarWatch object and a CommandPrompt object with one line of code. Nothing more, nothing less.



The console image shown above can be created by this easy statement:

<script>
   var debugConsole = new DebugConsole();
</script>

Saturday, May 06, 2006

Hierarchical & Social Relationship Mapping using Flash

Here is another cool project that I worked on recently... I came up with the prototype application over a weekend nearly a year ago. Then I introduced it to my former employer... Turns out it got picked up in a several projects of theirs, so I got to develop it even further. It is a tool for browsing social and hierarchical data relationships. It has gone through many development cycles to beceome what it is today. Each time, with different feedback from the client. Honestly, it is not nearly as powerful as it originally was, although now it has a much less complex interface. I guess that will be better for the general (less technical) user base.

So here it is:


The interface is pretty simple, you can zoom in & zoom out, reset the state (rearrange the nodes). You can click and drag any node on the canvas. Or, you can click anywhere on the canvas and drag the entire diagram around. If you just do a sngle click on a node, it makes a request to the server and pulls back dynamically generated xml that describes the data relationships. It also tracks the history of the nodes that you have navigated to, so that you can easily trace back your steps.

Launch the Relationship Mapper Demo

Here's how it works:

The root movie clip contains 3 objects... the controls (top left), the history (bottom), and the canvas. Each node is another object that is created within the canvas object. The lines that "connect" each node are created using the drawing API [ canvas.lineTo ( x , y ) ]. Since the nodes are objects that reside inside the canvas, they are rendered on top of the canvas, and they will always appear above the lines that are drawn.

When the application is initialized, and on each click on a node, a request is made back to the server to load a dynamically generated XML document (created with ColdFusion), using the loadXML function. The XML is then parsed, the canvas is cleared, and nodes are created accordingly.

Here's an example of the XML that it pulls back from the server:
getXML.cfm

In older versions, I had this setup so that each node click built onto the existing tree, rather than clearing the canvas, and only drawing the most recently viewed relationships. It was quite cool, you could build out a huge tree of relationships, and I had four different algorightms to rearrange them. Ultimately, this was too complex for the typical users, and I had to pull it out, but here is a screenshot of what it could do:

Thursday, May 04, 2006

Fun With Flash & Math ... the Trice 'O Graph

So, I got a great book last christmas (yes, that was months ago), its called Flash Math Creativity. If you like geometric shapes and patterns, then this book is definitley for you. The book got me thinking... one of my favorite experiments in the book was an animation called "Trails" by Glen Rhodes. Basically, an object in the movie clip moves around and clones itself over and over, thus creating a neat trailing effect.

I loved the ideas that this presented, and I started playing around with it. I extended his idea, and created a neat little app that I like to refer as the Trice 'O Graph because it reminds me of those old SpriroGraph toys. Basically, it is just a square that moves in a circular path around the screen. You can adjust its color, cycle its color, rotate it, resize it, change the trail length, offset the center from the axis of rotation, simulate 3 dimensional depth, etc... Really, you should try it out for yourself. Be forewarned, It is extremely addictive.

To get you started:
  • The combo box in the top left control the automatic color cycling.

  • The sliders in the bottom left control the offest from the center of rotation. (the button in between the two sliders resets it to the default position)

  • The sliders in the top right control the movement and trail dynamics.

  • The sliders in the bottom right control the color levels for the RGB channels, and the tint percentage. The checkboxes above each color channel slider determine whether or not that color gets cycled (checked == yes).

Launch the Trice 'O Graph.

Here are a few screenshots of what it can do...

Tuesday, May 02, 2006

Real-Time Permissions Caching in Coldfusion

A little bit of Fusion...

This post has to deal with ColdFusion based applications that require a permission set for a logged in user. It goes without saying... Permissions are extremely important for protecting sensitive content or data, you always want your application to be secure AND permissions up to date. In my experience thus far, I have seen 2 common approaches to this scenario... (and I am about to introduce a third)

  1. Rebuild Permissions Object on EVERY page load.
  2. Build your Permissions Object when the user logs in and store it in the user session.
Each approach has its benefits. The first approach allows you to maintain accurate permissions on every page access. If permissions are changed by an administrator while another user is currently logged in, those permissions are updated at the next page request. In the event that a user's permissions are restricted during the concurrent actions, those restrictions go into effect immediately. The second approach addresses any performance issues that could be encountered by building the permissions set. Its quite simple actually.... Build the permissions when the user logs in, store them in session. If the permissions are changed, then the changes will go into effect in the next login. You will use the cached permissions throughout the remainder of the session.

Each of these approaches have their downfalls... The first approach could be very resource intensive. Building an application permission object or checking data or event access rights could be a costly transaction. The second approach allows for permission synchronization problems. For instance, User A logs in. User B restricts user A's permissions. During User A's current session, they are still working based on the old permissions model, and they still have access to items that they should not.

Now, Let me introduce a third, hybrid approach.

With cached permissions, what happens if I am logged into session A, while someone else is logged into session B, I change their permissions? The permissions for session B should be updated automatically on the next page request. Here's how it can be done....

First, you have to maintain application state. Each time application state changes, the cached permission object should be rebuilt. I did this using a GUID (UUID). I started by putting the following within my application.cfm file.

<cfparam default="#CreateUUID()#" name="Application.permissionCacheUUID">
On initial login, you should bulid your permission set and store it in the session. You should also store the value of your application-scope permission cache guid in the session scope. I would use a reusable header file for this.

<cfif application.permissionCacheUUID NEQ session.permissionCacheUUID OR session.permissionCacheUUID is NULL>

//Add your code here to build your permission set store it in the session
<cfset session.accesslist = GetAccessList()>

//Store the application scope guid within the session.
<cfset session.permissionCacheUUID = Application.permissionCacheUUID>

</cfif>
Now, every time that the permission set is updated, you should update the application scope guid. I use this when adding, editing or updating users within the system.

<cfset Application.permissionCacheUUID = CreateUUID()>
If you notice in the second code block, the code to rebuild the permissions object (session.AccessList) gets executed if session.PermissionCacheUUID does not exist OR Session.PermissionCacheUUID does not equal Application.permissionCacheUUID. Whenever you update the application scope UUID, the code to rebuild the permission object will be executed.

Using this approach, permissions are only updated when necessary, not on every page access. Also, If user A updates permissions for user B, user B's permissions will also get updated automatically. Since the application scope guid was changed by user A, it will no longer be equal to the guid stored in user b's session. On the next page load for user B, their permission set will be updated.