kelvinluck.com

a stroke of luck

BarCamp London 2!

I’m just back from BarCamp London 2. It was really good, lots of interesting talks and a chance to meet some cool people. It was great meeting Carlos (creator of the amazing PaperVision 3D project), Ricardo (creator of loads of cool PaperVision3D demos), Aral Balkan (founder of OSFlash), Graham King, Janette Girod, Niqui Merret, Dan Webb and all of the other great people whose names and URLs I’ve forgotten!

Two of the talks were particularly inspiring for me. The first was Carlos’ PaperVision 3D one (unfortunately it seemed like it clashed with another really popular presentation so not that many people came). I’ve been watching the project closely and haven’t managed to find time to play around with it yet but am constantly amazed by how cool it is and it was great to get some insight into the Maya > Collada > .swf workflow that Carlos has made so easy.

The other especially inspiring talk was by Rhys Jones about web2os. Web2os is a really clever solution to the problem of offline access to web apps. Necessity is the mother of invention and web2os was developed because of Rhys’ long train journeys between Wales and London. Basically a proxy sits on your computer between your browser and the internet and can be instructed to cache requests and results while you are online. Once you go offline it detects this and simulates the server’s response while storing any changes you have made in a local SQL Lite database. When it goes online again it can synchronise your changes. Rhys demonstrated this working perfectly with Google Calendar.

The advantage over other possible solutions (like Apollo, the Dojo offline toolkit and Firefox 3) is that it doesn’t require re-engineering of the website itself (in this case Google Calendar). Instead a little web2os script is written for each website you want it to work with… These scripts end up being surprisingly simple. Also, because the proxy can inject HTML and JS code into the rendered page it also introduces the concept of local mashups. Anyway – definitely a project to keep an eye on – you can check out Rhys’ presentation on slideshare.

I gave a little talk about Flashr. I just gave a quick introduction to the project and then went through the code for a sample application I built in the middle of last night. Then I gave some examples of some of the cool things people have built with Flashr. The slides from the presentation are available on SlideShare and the sourcecode of the “application” from the above URL.

All in all, it was a great weekend and I’m looking forward to BarCamp Brighton in the summer and the potential “FlashCamp” Aral was talking about organising :)



Dynamic shared fonts in Flash

Shared fonts in Flash have always promised a great deal but failed to deliver due to a confusing and buggy implementation.

Recently I built a site which made extensive use of shared fonts. To make the site load smoothly it is made up of a number of swfs – one for each section. And rather than embedding Helvetica Nueue Bold Condensed (the font used for navigation and headings) in each swf I used a shared font. This means that the 17kb of font information is only loaded once and is then cached and shared between swfs. This seemed to work exactly as advertised with none of the bugs I remember from previous attempts – maybe something was fixed in the Flash Player?

So far so good. But then I ran into a problem… The site is available in a variety of locales including Russia and Poland. These require different versions of the font (the Cyrillic and Central European respectively). The problem is that Flash doesn’t provide a way to dynamically choose a shared font library to load – the location of the shared font is hard coded in the library item in your FLA.

So what do you do? Abandon shared font libraries and dynamically load a different font swf dependant on the locale and use actionscript to apply a text format referencing the correct font to all of the relevant text fields? Pay for the Shared Fonts Manager? Neither seemed like a nice solution so I tried something else…

Instead of pointing your shared font directly to an swf you instead point it to a serverside page (of the technology of your choice – the site above uses .NET while the example below uses PHP). This page reads the current locale from a cookie and passes the correct font swf back based on this value. Surprisingly enough this seems to work perfectly and allows Home of HD to work across different locales while providing only the necessary font to each user.

An example is probably worth a thousand words so you can see this technique in action and download the source files if you want to see how it’s done.

The only other issue is that you want your fonts to show up while developing. No problem. Just rename the default font swf file to the name of the serverside script (e.g. fonts.php in my example) and magically it works. Just remember not to overwrite your actual serverside script with this dummy one when you upload your changes!

Update

While writing this article and looking for links about shared fonts I stumbled across a post by Mario Klingemann where he suggests this exact technique. Back in 2003! Since I already wrote the examples and article I thought I might as well publish it but kudos to Mario for coming up with the idea years before me!



jScrollPane – Cross browser custom scrollbars

I’ve just released my latest plugin for jQuery – my favourite JavaScript library. It is a small (4KB) script which allows you to replace any vertical scrollbars on a div with overflow:auto with your own custom scroll bars. More info, demos and download here.



Automatically generating exclude.xml files

I’ve recently been working on a project where a number of swf’s use common classes. The initial swf loaded contains most of these classes but so do the child swfs it loads into itself. This is because they need to be able to call methods in and dispatch events to classes in the main swf. Importing the classes gives me compile time type checking and auto complete (in FDT – my editor of choice).

So I discovered excude.xml files. These allow you to specify classes which you don’t want to be compiled into a given swf. Since all AS2 classes live in the _global scope you can share them between different swf’s. So if your initial swf includes a class that you use in a child swf you load into it then compiling that class into the child swf is redundant.

exclude.xml files are easy enough to understand – simply create a file with the same name as your fla but with _exclude.xml added on (e.g. nav.fla would have an exclude file called nav_exclude.xml) and in it list all the classes you want to exclude from compilation into that swf.

The problem with exclude.xml files is when a class you are excluding has a dependency on other classes the dependant classes aren’t automatically excluded. And manually figuring out the dependency tree in any non-trivial application is tricky to say the least. So what we need is a way to find all of the classes which are included in a given swf. You can then use this to generate an exclude list for any other swfs that will be loaded after it.

I found a program which sounded like they might do just that: sexieR on OSFlash. Unfortunately I got put off by it’s requirements and and didn’t get around to finding out if it could do what I wanted.

Then I realised I could generate the exclude list very easily myself from Actionscript! Since all classes are instantiated as Objects in the _global namespace we can simply recursively loop over this namespace and note all the classes we come across. So I wrote my “IncludedClasses” class, which does the above and outputs a string for you to copy and paste into an exclude.xml file. You simply have to temporarily include this line in your “master” fla (the one which contains the classes you want to access from other flas):

trace(com.kelvinluck.util.IncludedClasses.getInstance().getExcludeXml());

Then in the output window you will find a string which you can copy and paste into an XML file with the correct name and then – bobs your uncle – you’re sorted :)

The IncludedClasses class is shown below or you can download it here.

/**
* Class: IncludedClasses
*
* @author KLuck
*/

class com.kelvinluck.util.IncludedClasses
{
   
   private static var instance:IncludedClasses;
   
   /**
   * Private constructor - Singleton
   **/

   private function IncludedClasses()
   {
     
   }
   
   function getExcludeXml():String
   {
      var classes:Array = _arrayUnique(_getClasses(_global, '', []));
      var r:String = '<excludeassets>' + newline;
      for (var i:Number=0; i<classes .length; i++) {
         r += '<asset name="' + classes[i] + '">' + newline;
      }
      r += '</classes></excludeassets>';
      return r;
   }
   
   function getArrayString():String
   {
      var r:String = '["' + newline;
      r += _arrayUnique(_getClasses(_global, '', [])).join('", "');
      r += '"]';
      return r;
   }
   
   private function _getClasses(obj:Object, path:String, classes:Array):Array
   {
      var ret:Array = [];
      for (var name:String in obj) {

         if (typeof(obj[name]) == 'function') {
            var firstLetter:String = name.substr(0, 1);
            if (firstLetter.toUpperCase() == firstLetter) {
               classes.push(path + '.' + name);
            }
         } else {
            var passPath = path == '' ? name : path + '.' + name;
            classes = classes.concat(_getClasses(obj[name], passPath, classes));
         }
      }
      return classes.concat(ret);
   }
   private function _arrayUnique(a:Array):Array
   {
      var o:Object = {};
      for (var i:Number=0; i<a .length; i++) {
         o[a[i]] = true;
      }
      var r:Array = [];
      for (var i:String in o) {
         r.unshift(i);
      }
      return r;
   }
   
   
   /**
   * @return singleton instance of IncludedClasses
   */

   public static function getInstance():IncludedClasses
   {
      if (instance == null)
         instance = new IncludedClasses();
      return instance;
   }
   function toString():String
   {
      return '[com.kelvinluck.util.IncludedClasses]';
   }
   
}

So simply run this script in your “master” fla (or library fla) and then create exlude files for all your “slave” fla’s. In the project I’m working on this knocked 30-40KB of each of the included swf’s which makes it definitely worthwhile.



Flash bug when printing fonts anti-aliased for readablitiy

I just came across an annoying bug in Flash running in a browser which appears when you use PrintJob to print a TextField with embedded fonts where “anti-alias for readability” is selected… The bug manifests itself by drawing a big green box behind these TextFields.
Since a google around didn’t seem to reveal anything I thought that I would make a note of the problem and my solution (such as it is) here.

The Problem
The problem is exhibited in the swf embedded below:

When this is playing in a browser (I tried IE/PC and Firefox on Mac and PC with the Flash 9 player) and you press the print button your printout will looks something like this:

Displays the green box Flash has added behind the text

Hmmmm! Where did that big green box come from?

If you want to recreate this problem yourself you can download the files from this example here. Bear in mind that the bug doesn’t manifest itself when you are testing from the Flash IDE. I’m not sure if this is because it is a bug in the Flash 9 player or in just in the player when it is running in a browser…

The solution
Not much of a solution but as you can see in the test above this bug only bites when you are printing an embeded font which is set to “anti-alias for readability”. So the way to avoid the problem is not to select this method of anti aliasing when you are embeding fonts and printing a movieclip.

Hopefully this page will show up in google and will save someone else the hour I wasted trying to figure out what was going on!



Has your Flash/ Flickr app stopped working?

Update

For the latest up to date information about Flashr please check out the new Flashr microsite

It was announced on the flickr mailing list last week that flickr.com were making some changes to how their API works. Those changes have completed today with the removal of the crossdomain.xml file from flickr.com.

What does that mean for me?

If you wrote a flash application that used the Flickr API then you will need to make a small change to it and recompile it. If you don’t do this then your swf will not be allowed to connect to flickr.com and query the API and so won’t work.

Why did they change it?

Not just to annoy all flash developers! Basically, the way the API was previously set up, any flash file could request any data from flickr.com (not just via the API). So it would be potentially possible for someone to craft an “evil” swf which could connect to flickr.com. If the viewer’s browser was logged in to flickr.com then this evil swf could potentially do evil stuff like deleting their photos.

How can I fix my app?

Luckily, the fix is very simple. If you are using Flashr you can just apply the changes in this changeset.

The change you have to make will depend on whether you are using version 0.4 or 0.5 of Flashr and should be self explanatory. Basically you are just telling Flashr to connect to http://api.flickr.com/ instead of http://www.flickr.com/.

It only took me a little while to update Selfportratir, my interestingness experiments and my colourfields experiment. Mario and Doug have both posted about this too and have updated their various experiments.

If you’ve written any Flash applications that connect to flickr please check they are still working or apply the fix, if you come across any other sites where Flash is meant to be connecting to flickr and you just see a blank screen then please let their makers know.

I’m not going to update some of my older experiments and examples because version 0.5 of Flashr is going to be released very soon along with a shiny new microsite and I will put new versions of everything up there.



Selfportraitr: An Interactive Exhibition Curating the Flickr Community

A while back I was approached by Stephen Jablonsky from the School of Visual Arts in New York. He was looking for someone to help with a project him and and his colleague Jeremy Chien were doing for the Pace/MacGill Gallery. He had come across Flashr and some of my experiments with it and thought that I may be able to help with the project.

It turned out I could! The project became “Selfportraitr”. The idea is that through ten computers in the gallery itself and through the Pace/MacGill website people can search through the thousands of photographs on flickr tagged with “selfportrait” and can choose the ones they like best to add to the gallery’s favourites. This enables members of the public to act as curators for an exhibition in a major New York gallery. More information on the app and the background to it is available in the official press release.

You can view the exhibition online using one of two applications:
  • Viewr – this application shows a slideshow of self portrait pictures. The interactivity of this application is limited to adding passing images to the gallery favourites.
  • Selfportraitr – this is the full on application as it appears in the gallery. It was designed for display on the Apple 23″ cinema displays in the gallery at a resolution of 1920×1200 so unless you have a massive screen it may appear a bit cramped and some text may be tricky to read. But you will get to play with the full functionality of the app and hopefully find some nice photos :)

This project was featured on the flickr blog, the New York Times (registration required) and even on ABC news which is pretty cool. It also sparked some controversy on the Flickr Central discussion board although in general people seem to appreciate what it is doing.

I built the app in Flash 8 using the bleeding edge version of Flashr. As you will have seen, some of the functionality of the app is pretty advanced and creating this app led to a number of bug fixes and enhancements to the Flashr code. A good by-product of this is that now the long awaited 0.5 release is within sight. It was also interesting to collaborate internationally across time zones on a project as complex as this and all things considered it went remarkably smoothly.



Switch stylesheets with jQuery

Update: I’ve released an updated version of this code which is more flexible. Please check it out.

I’ve just discovered jQuery which is an awesome JavaScript library. From the horse’s mouth:
jQuery is a Javascript library that takes this motto to heart: Writing Javascript code should be fun. jQuery acheives this goal by taking common, repetitive, tasks, stripping out all the unnecessary markup, and leaving them short, smart and understandable.
As an example of how succinct and easy code written with jQuery can be I put together a little example that allows you to add a stylesheet switcher to your site. Check out the example in action.

The stylesheet switcher allows your visitors to choose which stylesheet they would like to view your site with. It uses cookies so that when they return to the site or visit a different page they still get their chosen stylesheet.

The JavaScript code that powers the example looks like this:

/**
* Styleswitch stylesheet switcher built on jQuery
* Under an Attribution, Share Alike License
* By Kelvin Luck ( http://www.kelvinluck.com/ )
**/


(function($)
{
   $(document).ready(function() {
      $('.styleswitch').click(function()
      {
         switchStylestyle(this.getAttribute("rel"));
         return false;
      });
      var c = readCookie('style');
      if (c) switchStylestyle(c);
   });

   function switchStylestyle(styleName)
   {
      $('link[@rel*=style][title]').each(function(i)
      {
         this.disabled = true;
         if (this.getAttribute('title') == styleName) this.disabled = false;
      });
      createCookie('style', styleName, 365);
   }
})(jQuery);

Then all you need to do is to add a class of “styleswitch” to any links that you want to activate the stylesheet switcher and a “rel” attribute which corresponds to the “title” attribute of the link tag embedding the stylesheet you want to switch to. Just view the source of the example and all should become clear…

I’d appreciate any feedback on the effectiveness of this technique. I think it should work fine on any browser that jQuery supports (I’ve tested on IE5.5, IE6 and FF1.5 on XP and Safari on OSX). It should degrade gracefully by going to the href of the link when jQuery isn’t supported or JavaScript is disabled. I have linked to a page which suggests possible ways to deal with this situation (disable JavaScript and try and switch stylesheets on the example to see the page).

If you would like to use this code then please feel free to download the zip



FlashrSimpleSearch

Update 3:

This is a very old page imported from my previous blog. If there is missing content below or anything that doesn’t make sense then please check the page on my old blog.

Update 2:

For the latest up to date information about Flashr please check out the new Flashr microsite

Update:

This example will no longer work as-is – you will need to update your Flashr files as described here.

Somebody on the Flashr mailing list was having difficulties getting to grips with Flashr. Since a picture is worth a thousand words and I needed to do some examples of using Flashr 0.5 anyway, I put this very simple example together…

Basically all it does is connects to the Flickr API and does a search for a tag using flickr.photos.search. It then calls flickr.photos.getInfo on each of the returned photos to get more detailed information (like authors name, description and tags used). Once it has got all this information it simply traces it to the output window in Flash.

All of this is made much easier by a feature in the as yet not officially released Flashr 0.5. Now when you make multiple requests to the Flickr API the requests are added to a queue and each one executes in turn. This makes writing applications that rely on multiple API requests (such as this one) much simpler.

DOWNLOAD
You can download all the files for this example from here. This includes the latest version of Flashr 0.5 (see the trac timeline for recent changes). The specific file you are interested in is com.kelvinluck.flashr.example.FlashrSimpleSearch.as.

THE CODE
Here is the entire class which powers this little “application”.

import com.kelvinluck.util.LogWrapper;
import com.kelvinluck.flashr.core.FlashrResponse;
import com.dynamicflash.utils.Delegate;
import com.kelvinluck.flashr.core.ResultsSet;
import com.kelvinluck.flashr.core.Photo;
import com.kelvinluck.flashr.core.Flashr;
/**
* Class: FlashrSimpleSearch
*
* Very simple example showing how to search for a tag using Flashr 0.5 and then
* get more detailed information about each matching photo.
*
* Currently just traces the relvant information out.
*
* Author:
* Kelvin Luck
*/

class com.kelvinluck.flashr.example.FlashrSimpleSearch extends MovieClip
{
   
   public static var SEARCH_TAG:String = "snow";
   public static var NUM_RESULTS:Number = 10;
   
   private var _flashr:Flashr;
   private var _flashrResponse:FlashrResponse;
   
   private var _numResults:Number;
   private var _photos:Array;
   
   /**
   * Function: FlashrSimpleSearch
   * Constructor
   **/

   function FlashrSimpleSearch()
   {
      // uncomment the following lines if you want to see the internals of what is happening with Flashr.
      //LogWrapper.getInstance().init();
      //LogWrapper.getInstance().addTracePublisher();
     
      _photos = [];
     
      _flashr = Flashr.getFlashr();
      _flashr.apiKey = "b40e05adf210ad4c4cc4da00f99f4184";
      _flashr.cacheQueries = true;
     
     
      _flashrResponse = new FlashrResponse();
      _flashrResponse.onPhotosSearch = Delegate.create(this, onPhotosSearch);
      _flashrResponse.onPhotosGetInfo = Delegate.create(this, onPhotosGetInfo);
     
      trace("Searching for " + NUM_RESULTS + " photos matching tag '" + SEARCH_TAG + "'");
      _flashr.photosSearch({tags:SEARCH_TAG, per_page:NUM_RESULTS});
   }
   
   function onPhotosSearch(rs:ResultsSet)
   {
      _numResults = rs.photos.length;
      trace("Loaded data for " + _numResults + " photos out of " + rs.total + " matching tag, requesting more details about each photo");
      for (var i:Number=0; i<_numresults ; i++) {
         var thisPhoto:Photo = rs.photos[i];
         _flashr.photosGetInfo(thisPhoto.id, thisPhoto.secret);
      }
   }
   function onPhotosGetInfo(photo:Photo)
   {
      trace("Loaded detailed data for photo '" + photo.id + "'");
      _photos.push(photo);
      if (_photos.length == _numResults) {
         onAllPhotosLoaded();
      }
   }
   function onAllPhotosLoaded()
   {
      trace("*************ALL PHOTO INFO LOADED*************");
      trace(" ");
      for (var i:Number=0; i<_photos.length; i++) {
         var thisPhoto:Photo = _photos[i];
         trace("Photo " + thisPhoto.id + " :");
         trace("  Title: " + thisPhoto.title);
         trace("  Description: " + thisPhoto.description);
         trace("  Taken: " + thisPhoto.dateTaken);
         trace("  Author: " + thisPhoto.owner.username);
         trace("  Author ID: " + thisPhoto.owner.nsid);
         trace("  Thumbnail: " + thisPhoto.thumbnailUrl);
         trace("  Photo page URL: " + thisPhoto.photoPageUrl);
         trace("  Tags: " + thisPhoto.getTagsAsStrings());
         trace("------------------");
         trace(" ");
      }
   }
   
   /**
   * Function: toString
   **/

   public function toString():String
   {
      return "[com.kelvinluck.flashr.example.FlashrSimpleSearch]";
   }
}

I hope this is useful to someone, please leave any feedback as a comment below or on the Flashr mailing list;



Textpattern upgraded

Update:

This is a very old page imported from my previous blog. If there is missing content below or anything that doesn’t make sense then please check the page on my old blog.

I finally got around to updating the version of Textpattern that my blog is running on to the latest version. I was running a very old beta (from december 04) until now!

I was disappointed to find that I still had to hack the textpattern core to get my syntax highlighting plugin to work despite raising a bug ticket about the problem over a year ago. In fact, looking through the Textpattern source code I was very tempted to write my own blog system using my new favourite PHP framework: CodeIgniter. I think that will have to wait until I find some spare time though…

Anyway, if you notice any bugs with the blog now that it has been updated then please let me know either via a comment below or through my contact form.