Article

Map Your OpenSocial Data Using Flex

Page: 1 2 3 Next

What we need to do is tweak our project settings so that Flex Builder places the compiled SWF files and such in the local web server directory. If you’re running on Windows, this probably means storing them somewhere in c:\inetpub\wwwroot (for the IIS web server) or c:\apache\htdocs\ (for Apache). On a Mac, these files can be placed in either ~/Sites or in /Library/WebServer/Documents.

The two settings you need to change in the project settings are the Output Folder, which is where we want Flex Builder to copy our files, and Output Folder URL, which is the URL of that folder on the web server. These text fields are shown in Figure 2.

The project settings dialog window

Once you’ve made these changes, re-launch the application. You should see something like the image shown in Figure 3.

The working map

Now when the user presses Enter after typing a value into the Location input field, our application runs the geocode and sets the center of the map to the value that was typed—Fremont, California, in the case of the example above.

Adding Flickr Results

The next step is to add functionality for our application to communicate with the Flickr web server. Specifically, we’re after images that correspond to the current latitude and longitude of our map. The cool thing about Flickr is that many of its images are geotagged. This means that we can provide Flickr with a latitude, longitude, and radius, and it will return a selection of photos taken within the area specified by those parameters.

There is a Flickr library for Flex, but it doesn’t currently support the geotagging API. So in the code below, I’ve queried the Flickr REST API directly by using a Flex HTTP Service:

Listing 2. The Flickr Mapping application  
<?xml version="1.0" encoding="utf-8"?>  
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute"  
 creationComplete="onStartup()">  
<mx:Script>  
<![CDATA[  
import com.google.maps.overlays.MarkerOptions;  
import com.google.maps.overlays.Marker;  
import mx.rpc.events.ResultEvent;  
import com.google.maps.services.GeocodingEvent;  
import com.google.maps.services.ClientGeocoder;  
import com.google.maps.controls.ZoomControl;  
import com.google.maps.controls.MapTypeControl;  
import com.google.maps.MapEvent;  
import com.google.maps.LatLng;  
import com.google.maps.Map;  
import mx.core.UIComponent;  
 
private const FLICKR_KEY:String = 'Your Flickr Key';  
 
private var map:Map = new Map();  
 
private function createFlickrURL( search:String, lat:Number, lng:Number, radius:Number = 20 ) : String {  
 var query:String = 'http://api.flickr.com/services/rest/?api_key='+FLICKR_KEY;  
 query += '&method=flickr.photos.search&text=dog&extras=geo&lat='+lat+'&lon='+lng+'&radius='+radius;  
 query += '&per_page=100&page=1&sort=date-posted-desc';  
 return query;  
}  
 
private function onStartup() : void {  
 var uic:UIComponent = new UIComponent();  
 uic.setStyle( 'top', 0 );  
 uic.setStyle( 'left', 0 );  
 uic.width = width;  
 uic.height = height;  
 addChildAt( uic, 0 );  
   
 map.key = 'Your Google Maps Key';  
 map.width = width;  
 map.height = height;  
 map.addEventListener( MapEvent.MAP_READY, onMapReady );  
 uic.addChild( map );  
   
 locPanel.setStyle( 'top', height - locPanel.height - 20 );  
}    
private function onMapReady( event:MapEvent ) : void {  
 map.setCenter( new LatLng( 34.101509, -118.32691 ) );  
 map.setZoom( 12 );  
   
 map.addControl( new MapTypeControl() );  
 map.addControl( new ZoomControl() );  
}  
private function onSearch() : void {  
 flickrSearch.url = createFlickrURL( searchText.text, map.getCenter().lat(), map.getCenter().lng() );  
 flickrSearch.send();  
}  
private function onFlickrResult( event:ResultEvent ) : void {  
 map.clearOverlays();  
 for each( var photo:XML in event.result..photo ) {  
   var pMarker:Marker = new Marker( new LatLng( photo.@latitude, photo.@longitude ),  
     new MarkerOptions( {  
       label:photo.@title,  
       hasShadow:true } ) );  
   map.addOverlay( pMarker );  
 }  
}  
private function onGeocodeSuccess( event:GeocodingEvent ) : void {  
 map.setCenter( event.response.placemarks[0].point );  
 onSearch();  
}  
private function onKeyDown( event:KeyboardEvent ) : void {  
 if ( event.keyCode == Keyboard.ENTER ) {  
   var cg:ClientGeocoder = new ClientGeocoder( "USA" );  
   cg.addEventListener( GeocodingEvent.GEOCODING_SUCCESS, onGeocodeSuccess );  
   cg.geocode( loc.text );  
 }  
}  
]]>  
</mx:Script>  
<mx:HTTPService id="flickrSearch" resultFormat="e4x" result="onFlickrResult(event)" />  
<mx:Panel id="locPanel" title="Location" top="500" left="20" borderAlpha="0.95" layout="vertical">  
 <mx:TextInput id="searchText" keyDown="onKeyDown( event )" width="300" text="dog" />  
 <mx:TextInput id="loc" keyDown="onKeyDown( event )" width="300" text="fremont, ca" />  
</mx:Panel>  
</mx:Application>

You’ll notice at the bottom of the file that I’ve added a searchText field in addition to the location field. This field contains the search term that we’ll send to Flickr in addition to the current map location.

The bulk of the code that renders our map is unchanged from the simple example that we looked at a moment ago. The new stuff happens when the onGeocodeSuccess method calls the onSearch method to start a Flickr search. That Flickr search uses the flickrSearch HTTP service with a URL that we generate on the fly using the createFlickrURL method.

When our query to Flickr returns a selection of results (expressed as XML), the onFlickrResult method is called. This method takes that XML and looks for the photo elements in the XML tree. It then creates a Google Maps Marker object for each of the photos and adds this marker to the map.

Figure 4 shows the result of running this code.

A map of pictures of dogs in Fremont, CA

Things are really starting to come together—our user can find photos of something given a location. But what if he or she actually wants to view the photo?

Let’s adjust our code to add this feature:

Listing 3. The updated code  
private function createMarker( photo:XML ) : void {  
 var reqUrl:String = 'http://static.flickr.com/'+photo.@server+'/'+photo.@id+'_'+photo.@secret+'_s.jpg';  
 var pMarker:Marker = new Marker( new LatLng( photo.@latitude, photo.@longitude ),  
   new MarkerOptions( {  
   label:photo.@title,  
   tooltip:photo.@title,  
   name: reqUrl,  
     hasShadow:true } ) );  
 pMarker.addEventListener( MapMouseEvent.CLICK, function( event:MapMouseEvent ) : void {  
   pMarker.openInfoWindow( new InfoWindowOptions(  
     { contentHTML: '<img width="75" height="75" src="'+reqUrl+'">' } ) );  
 } );  
 map.addOverlay( pMarker );  
}  
private function onFlickrResult( event:ResultEvent ) : void {  
 map.clearOverlays();  
 
 for each( var photo:XML in event.result..photo )  
   createMarker( photo );  
}

In the code above, we’ve changed the onFlickrResult function so that it just calls createMarker. The createMarker method in turn creates a Marker, and we’ve added an event listener to detect when the user clicks on the Marker. When this happens, we display a small “info window” above our marker. This info window, which resembles a speech bubble, contains a thumbnail version of the Flickr image.

Figure 5 shows this thumbnail display code in action.

One of the dogs in Fremont, CA

So, there we have it—we can produce Flickr pictures of big poodle-esque dogs in Fremont.

Now, what if we want to view images of people?

If you liked this article, share the love:
Print-Friendly Version Suggest an Article

Sponsored Links