The Flash Platform and Cloud API’s Part I: Flickr

February 23rd, 2009 § 2 comments

The Internet is full of sites that offer information and services for their users to store and share data from their favorite web sites and articles to their family photos. Many of these sites also offer an application programming interface or API to access this data. For years this functionality was limited to the browser, however, new emerging technologies are allowing this information to break free from the browser to the desktop, mobile phones and devices. The Adobe Flash Platform is leading this initiative with tools like Flash, Flex and AIR. This series will take some of the most popular Internet services and demonstrate how to use their API's to create your own rich, engaging applications with the Flash Platform.

Part I of this series covers the ubiquitous Flickr API. If you've done much searching around you've probably found a fair number of Flickr applications including various search tools, data visualizations and just plain "cool to look at" applications. The Flickr API lends itself well to building rich apps because the data itself is intriguing and visually appealing, and there's lots of it. I'm going to show you how to build a relatively simple desktop application using Flash that taps into the vast Flickr photo library, grabs 50 random "interesting" photos and displays them "Poloroid style" on your desktop. The finished application is available for download from the Adobe Marketplace (for free). Let's get started.

What you'll need:

1. Adobe® Flash®; download a 30 day trial
2. A Flickr account and API key, sign up at flickr.com
3. Flickr AS3 library, available here
4. Tweener AS3 library, available here


Here's a shot of what we're working towards.

Start by creating a new Flash file, name if flickr.fla and set the desired document properties. See the screen shot for the settings I used.

Because we're creating an AIR application that will run on the user's desktop we'll need to make a close button so they can exit out of the app when they're finished. Create a new movie clip named cmdClose (Insert > New Symbol...). Be sure the "Export for Actionscript" box is checked. Now build out your button in the design view. It can be as simple or as complex as you want. Be creative.

Go back into the main properties for you document. Where it says "Class" or "Document Class" if you're using CS3 type "Flickr"

Save your file.

Create a new Actionscript file and name it Flickr.as. Be sure to save it in the same directory as your FLA. This is where we're going to write all of the code for our application. If you're not familiar with how to use document classes in your Flash applications check out this tutorial at gotoandlearn.com . First we need to setup our class file, the basic structure is as follows:

package {
    import flash.display.MovieClip;
 
    public class Flickr extends MovieClip {
 
        public function Flickr() {
 
        }
 
    }
}

Next we'll need to import some classes that we'll be using to create our application. Add the following code right after your class declaration.

    import caurina.transitions.*; //import the tweener classes
 
    import com.adobe.webapis.flickr.methodgroups.Interestingness; //import flickr classes
    import com.adobe.webapis.flickr.FlickrService; //import flickr classes
    import com.adobe.webapis.flickr.events.FlickrResultEvent; //import flickr classes
 
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.display.Sprite;
    import flash.display.Loader;
    import flash.net.URLRequest;
    import flash.filters.DropShadowFilter;
    import flash.display.DisplayObject;

This code adds references in our class to the external classes we need to build out the various components of our app. Without these references our code would not compile because it wouldn't know what we were talking about when we tried to create a new tween for example. Next we need to declare some variables that we'll need in our code. After your import statements add the following variable declarations. I'll explain what they're used for as we need them.

    private const API_KEY:String = "ENTER YOUR OWN API KEY HERE";
    private var flick:FlickrService;
    private var flickrId:String;
    private var photoUrl:String;
    private var ldr:Loader;
    private var photoList:Object;
    private var index:uint;
    private var lastIndex:uint;
    private var lastX:Number;
    private var lastY:Number;
    private var curImg:DisplayObject;
 

Now that we have some of the ground work laid let's start working on the interface. The first function you created is the constructor function for you document class. This code will run when the app loads. We've already "stubbed" it out now let's add some code. First let's setup our close button.

    public function Flickr() {
        var btnClose:cmdClose = new cmdClose();
        btnClose.x = 949;
        btnClose.y = 22;
        btnClose.buttonMode=true;
        btnClose.useHandCursor=true;
        this.addChild(btnClose);
        btnClose.addEventListener(MouseEvent.CLICK,doClose);
 
        flick = new FlickrService(API_KEY);
        flick.addEventListener(FlickrResultEvent.INTERESTINGNESS_GET_LIST,interestingNessResult);
 
        flick.interestingness.getList(null,null,50,Math.random()*10);
   }

Here we're creating an instance of the button we built in our main FLA file, setting some initial properties including the x, y coordinates, the buttonMode and telling it to use the hand cursor when the user hovers over it. Next we add our button to the stage and finally we add an event listener so we can tell when the button has been clicked and we can call the appropriate function to close the application. After setting up our button we created an instance of the FlickrService object. This is the object we will use to communicate with the Flickr API service.

flick = new FlickrService(API_KEY);

The next line adds an event listener to our newly created 'flick' object. This tells our object to be on the lookout for anything that broadcasts a FlickrResultEvent (specifically, the 'INTERESTINGNESS_GET_LIST' event). When that event is broadcast our event listener will fire off the interestingNessResult function.

flick.addEventListener(FlickrResultEvent.INTERESTINGNESS_GET_LIST,interestingNessResult);

Finally we tell our object to actually go get the data we're requesting by calling the interestingness.getList method. This method takes the following parameters;

* date: (optional) A specific date, formatted as YYYY-MM-DD, to return interesting photos for. - we don't care so we pass in null
* extras: (optional) A comma-delimited list of extra information to fetch for each returned record. Currently supported fields are: license, date_upload, date_taken, owner_name, icon_server, original_format, last_update, geo, tags, machine_tags, o_dims, views, media. - we don't care so we pass in null
* per_page: (optional) Number of photos to return per page. If this argument is omitted, it defaults to 100. The maximum allowed value is 500. - we want 50 images so we pass in 50
* page: (optional) The page of results to return. If this argument is omitted, it defaults to 1. - we want a random page between 1 and 10 so we generate a random number within these bounds.

flick.interestingness.getList(null,null,50,Math.random()*10);

Now let's write our results code. The first function is pretty simple, it just sets up an object to store the photo data returned from the Flickr service call. Then it calls another function that actually does the work of laying out the photos on the screen.

private function interestingNessResult(e:FlickrResultEvent):void {
        photoList = new Object();
        photoList = e.data.photos;
        loadImages(0);
    }

Since this is a tutorial on using the Flickr API I'm not going to cover all of the code to layout the photos on the screen but I will cover some of the key things related to the Flickr results. The code you will get back should resemble the XML below. If your data looks different you may have an error somewhere in your code. A list of error codes can be found here .

 
<photos page="2" pages="89" perpage="10" total="881">
<photo id="2636" owner="47058503995@N01"
		secret="a123456" server="2" title="test_04"
		ispublic="1" isfriend="0" isfamily="0" />
<photo id="2635" owner="47058503995@N01"
		secret="b123456" server="2" title="test_03"
		ispublic="0" isfriend="1" isfamily="1" />
<photo id="2633" owner="47058503995@N01"
		secret="c123456" server="2" title="test_01"
		ispublic="1" isfriend="0" isfamily="0" />
<photo id="2610" owner="12037949754@N01"
		secret="d123456" server="2" title="00_tall"
		ispublic="1" isfriend="0" isfamily="0" />
</photos>

The loadImages() function loops through the object we created to store the photo results, calls a function to build the image URL and then loads the image. Because we need to wait for the image to load before we add it to the screen we add an event listener to the loader object to handle this.

private function loadImages(index:uint):void
        {
            if(index < photoList.photos.length)
            {
                ldr = new Loader;
                ldr.load(new URLRequest(buildPhotoUrl(photoList.photos[index].server,
                                        photoList.photos[index].id,
                                        photoList.photos[index].secret)));
                ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
            }
        }

Because Flickr stores photos on various servers we need to use the different pieces of data associated with a photo to build the path to the image. The function below does that for us.

private function buildPhotoUrl(server:String,photoId:String,secret:String):String{
            photoUrl = "http://farm1.static.flickr.com/" + server;
            photoUrl += "/" + photoId + "_" + secret + ".jpg";
            //trace("photo url = " + photoUrl);
            return photoUrl;
        }

There are many more methods available in the API than what we covered here but they are all used in essentially the same manner;

1. Import the necessary classes and libraries
2. Create your Flickr object
3. Call the appropriate methods
4. Handle the results when they come back.

With relatively little difficulty you can have access to millions of photos available on Flickr right in your own application. The full code for the PhotoPile application is given below.

  1. package {
  2. import flash.display.MovieClip;
  3.  
  4. public class Flickr extends MovieClip {
  5. import caurina.transitions.*;
  6. import com.adobe.webapis.flickr.methodgroups.Interestingness;
  7. import com.adobe.webapis.flickr.FlickrService;
  8. import com.adobe.webapis.flickr.events.FlickrResultEvent;
  9. import flash.events.Event;
  10. import flash.events.MouseEvent;
  11. import flash.display.Sprite;
  12. import flash.display.Loader;
  13. import flash.net.URLRequest;
  14. import flash.filters.DropShadowFilter;
  15. import flash.display.DisplayObject;
  16.  
  17. private const API_KEY:String = "[ENTER YOUR API KEY HERE]";
  18. private var flick:FlickrService;
  19. private var flickrId:String;
  20. private var photoUrl:String;
  21. private var uname:String;
  22. private var ldr:Loader;
  23. private var photoList:Object;
  24. private var index:uint;
  25. private var lastIndex:uint;
  26. private var lastX:Number;
  27. private var lastY:Number;
  28. private var curImg:DisplayObject;
  29.  
  30. public function Flickr() {
  31. var btnClose:cmdClose = new cmdClose();
  32. btnClose.x = 949;
  33. btnClose.y = 22;
  34. btnClose.buttonMode=true;
  35. btnClose.useHandCursor=true;
  36. this.addChild(btnClose);
  37. btnClose.addEventListener(MouseEvent.CLICK,doClose);
  38.  
  39. flick = new FlickrService(API_KEY);
  40. flick.addEventListener(FlickrResultEvent.INTERESTINGNESS_GET_LIST,interestingNessResult);
  41.  
  42. flick.interestingness.getList(null,null,50,Math.random()*10);
  43. }
  44.  
  45. private function doClose(e:MouseEvent):void {
  46. this.stage.nativeWindow.close();
  47. }
  48.  
  49. private function interestingNessResult(e:FlickrResultEvent):void {
  50. photoList = new Object();
  51. photoList = e.data.photos;
  52. loadImages(0);
  53. }
  54.  
  55. private function loadImages(index:uint):void
  56. {
  57. if(index < photoList.photos.length)
  58. {
  59. ldr = new Loader;
  60. ldr.load(new URLRequest(buildPhotoUrl(photoList.photos[index].server,
  61. photoList.photos[index].id,
  62. photoList.photos[index].secret)));
  63. ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, loaded);
  64. }
  65. }
  66.  
  67. private function loaded(e:Event):void{
  68.  
  69. var sp:Sprite = new Sprite();
  70. sp.addChild(ldr.content);
  71. sp.x = 10;
  72. sp.y = 10;
  73.  
  74. // create a filter
  75. var dropShadow:DropShadowFilter = new DropShadowFilter(4, 45, 0x000000, 0.4, 8, 8, 2, 3);
  76.  
  77. var frame:Sprite = new Sprite();
  78. // Thickness of the stroke
  79. frame.graphics.lineStyle(0);
  80. // Draw the background layout box
  81. frame.graphics.beginFill(0xFFFFFF);
  82. // x, y, width, height
  83. frame.graphics.drawRect(0,0,sp.width + 20,sp.height+60)
  84.  
  85. frame.scaleX = frame.scaleY = .25;
  86. frame.x = Math.random()*(this.stage.stageWidth-frame.width);
  87. frame.y = Math.random()*(this.stage.stageHeight-frame.height);
  88.  
  89. frame.filters = [dropShadow];
  90. frame.addChild(sp);
  91. frame.addEventListener(MouseEvent.CLICK,doClick);
  92.  
  93. this.addChild(frame);
  94. frame.alpha = 0;
  95. Tweener.addTween(frame,{alpha:1,time:.25,transition:"linear"});
  96.  
  97. index++;
  98. loadImages(index);
  99. }
  100.  
  101. private function doClick(e:MouseEvent):void{
  102. var img:DisplayObject = e.currentTarget as DisplayObject;
  103. if(curImg == img)
  104. {
  105. this.setChildIndex(img,lastIndex);
  106. Tweener.addTween(img,{x:lastX,
  107. y:lastY,
  108. scaleX:.25,
  109. scaleY:.25,
  110. time:.5,
  111. transition:"easeOutCubic",
  112. onComplete:function() {curImg = null;}});
  113. } else {
  114. if(curImg != null){
  115. this.setChildIndex(curImg,lastIndex);
  116. Tweener.addTween(curImg,{x:lastX,
  117. y:lastY,
  118. scaleX:.25,
  119. scaleY:.25,
  120. time:.5,
  121. transition:"easeOutCubic"});
  122. }
  123.  
  124. lastIndex = this.getChildIndex(img);
  125. lastX = img.x;
  126. lastY = img.y;
  127. this.setChildIndex(img,index);
  128. Tweener.addTween(img,{x:((this.stage.width/2) - (img.width)),
  129. y:img.height/2,
  130. scaleX:1,
  131. scaleY:1,
  132. time:.5,
  133. transition:"easeOutCubic"});
  134. curImg = img;
  135. }
  136. }
  137.  
  138. private function buildPhotoUrl(server:String,photoId:String,secret:String):String{
  139. photoUrl = "http://farm1.static.flickr.com/" + server;
  140. photoUrl += "/" + photoId + "_" + secret + ".jpg";
  141. //trace("photo url = " + photoUrl);
  142. return photoUrl;
  143. }
  144. }
  145. }

Tagged , , ,

§ 2 Responses to The Flash Platform and Cloud API’s Part I: Flickr"

  • jim says:

    I try your code : The Flash Platform and Cloud API’s Part I: Flickr

    but i have miltiple error like :

    example for this line : “private var flick:FlickrService;”

    - the private attribute may be used inly on class property definitions.

    ??? any help ?

    or can you send me the source file in fla and as ?

    regards

  • timT says:

    Make sure you are putting all of the code in a separate Actionscript class and not in your FLA.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

What's this?

You are currently reading The Flash Platform and Cloud API’s Part I: Flickr at T3B.

meta