Monday, December 29, 2008

Keeping DataTips in Charts boundaries

Here goes a little trick I used for an application some time ago. The problem was that data tips that are displayed on mouse overing Flex Charts, fly over the Application content, and in some cases do not respect the visible boundaries of it. This effect can be undesired, and a usability problem because can make the information impossible to read in some situations.

The attached application shows the problem in action.

If you hover the first pair of charts, you'll see the custom created data tip appearing at the right of the central point of the sector being pointed. For the pie on the right, the information is unreadable.
The second set of charts, use another data tip renderer implementation that keeps the data tip in the pie boundaries, making the information always visible.




Get the source code here.



It's so simple, just take care when displaying the data tip in the default position that it fits into its owner chart, and if it's not possible, adjust its position. Hope it helps! And if you find a better way to solve the problem... or see anything that could be improved, please write! ;-)

Wednesday, December 17, 2008

Webcam picture taking with Flash and AS3

Long time since last post... It's been nearly 2 months since I changed my internet provider at home... and have no connection yet :-(


I recently had to implement a cool feature for a project, consisting in a picture-taker using the webcam, for a user registration process. The feature has been added recently in Facebook, allowing users to upload pictures and videos directly to their friends' walls.


Displaying the webcam content in a Flash movie is quite easy:


// 1. Access the default camera

var cam:Camera = Camera.getCamera();
// 2. Create a video display object

var video:Video = new Video(550,400);

// 3. Attach the camera to the video display
video.attachCamera(cam);
// 4. Add the video display object to the stage
stage.addChild(video);


Then, through the BitmapData object, it's possible to take a snapshot at the desired moment drawing the data from the Video object into a ByteArray (and encoding this information using an encoder JPEG/PN
G/...). This binary data can be sent to the server, with a URLRequest and there processed by whatever server side technology.

// 1. Create the req
uest object
var req:URLRequest = new URLRequest(remoteURL);
// 2. Specify we're sending binary data
req.contentType = "application/octet-stream";
// 3. Send by POST (GET doesn't allow enough data)
req.method = URLRequestMethod.POST;
// 4. Put the image binary data in the request body
req.data = binaryArray;

It's quite easy to get this point. But there's a usability issue with all this stuff, which is that to access the webcam, Flash needs the user authorization, requested through a dialog. First thing that drove me crazy, because if the Flash movie doesn't have the minimum dimensions (215 x 138) to show this dialog, there's no advice, but the video won't be displayed. It's clearly explained in the ActionScript 3 language reference (link to API), it's true. My fault, my fault :-P


But then, a second usability problem. Camera.getCamera() retrieves the "default" camera in the computer. In my MacBook Pro, Flash detects 3 webcams (even I just have the built-in one), which are displayed as "FireWire Video","DV Video" and "USB Video Class Video".


The problem is that just from the "USB Video Class Video" I'm able to capture video images. So it's not just asking for permission to access the webcam to the user, but also requiring him/her to go to the camera tab in the Flash settings menu, to try between this unknown video devices to check which one works? But wait, Facebook is detecting my webcam automatically! Even if I choose one of the non valid... when I try again the "USB Video Class Video" it's being used. So it must be possible to select the correct one somehow. And then I came across this article (Sander Kruger's blog):

Here, the author explains a tricky way to detect the valid one. The basics:

- Camera.getCameras() returns an array of Camera objects with the system cameras (in my MacBook Pro [FireWire Video, DV Video. USB Video Class Video], so we can know how many are accessible.
- Camera.getCamera() will get the default one (could be any of the system ones, available or not), but there's a second method, Camera.getCamera(String), that retrieves one specifically, from the total we discovered using Camera.getCameras(). The String parameter, represents the index of every camera in the array Camera.getCameras(), [0 to N-1]. So in my case, we can get the USB Video Class Video Cam for example, doing Camera.getCamera("2").
- The Camera object will dispatch a StatusEvent notifying if the user has accepted or rejected the access to the webcam from the Flash built dialog.
- The Camera object will dispatch ActivityEvents when it detects movement in the scene, but only if the camera is attached to a Video object where to be displayed.

With all this ingredients then you can cook a camera detection process. Once the Camera says it's accessible from the user request dialog (StatusEvent), you can loop over each cam object from Camera.getCameras, adding an activity handler for the ActivityEvents it could dispatch, and attach the Camera to a Video object, that's not added to the Stage (always hidden then). Then starting a Timer, we can give the Camera some time to detect activity... if it was not the case and the countdown finishes, then we should remove the activity event, detach the camera from the video and move to try the next Camera from the Array. Keep looping this way until one of the Cameras gives some activity news... or all of them are checked and none response to activity.

Hope the experience is helpful to someone :-)

MAXwidget