Home  >  

Having Fun With Google Maps Flash API

Author photo
AddThis Social Bookmark Button
Here's a silly post that contains a trick combining graphics filters with Google maps for some interesting effects. They don't necessarily make it easier to read the maps, nor do they have a lot of value, but they look interesting, and are fun to play with.

I can't claim this idea as my own. I just randomly stumbled across this post on axismaps.com, and figured I'd throw together a Flex example showing how to do it.

The effects are applied directly to the map tiles, not the entire map component, so all of the other controls still look like normal. Let's take a look at it in action... You can either select a preset, or adjust the slider values to change the filters applied to the map instance.



The original post has some other interesting effects which can be achieved through various permutations of the input array for the ColorMatrixFilter instance. This example is pretty basic, and only manipulates the red, green, and blue channels independently.

Here's how to make it all work. It's really pretty simple. This example just creates color matrix filters and applies them to the mapping components. I started with the samples for the Google Maps API, and just started applying different filters.

<?xml version="1.0" encoding="utf-8"?>
<mx:Application 
   xmlns:maps="com.google.maps.*" 
   xmlns:mx="http://www.adobe.com/2006/mxml" 
   layout="absolute">
   
   <mx:Style>
      Application {
          backgroundColor: #999999;
          themeColor: #cccc00;
       }
      
      Panel {
          borderColor: #cccccc;
          borderAlpha: 0.85;
          borderThicknessLeft: 1;
          borderThicknessTop: 0;
          borderThicknessBottom: 1;
          borderThicknessRight: 1;
          cornerRadius: 3;
          backgroundAlpha: 0.92;
          highlightAlphas: 0.26, 0;
       }
   </mx:Style>
   
   <mx:Script>
       <![CDATA[
         import com.google.maps.services.ClientGeocoder;
         import mx.controls.Alert;
         import com.google.maps.MapMouseEvent;
         import com.google.maps.services.GeocodingEvent;
         import com.google.maps.controls.MapTypeControl;
         import com.google.maps.controls.PositionControl;
         import com.google.maps.controls.ZoomControl;
         import com.google.maps.LatLng;
         import com.google.maps.Map;
         import com.google.maps.MapEvent;
         import com.google.maps.MapType;
         
         private var geocoder : ClientGeocoder;
         
         private function onMapReady(event:Event):void 
         {
             map.setCenter( new LatLng( 38.895108,-77.035961 ), 14, MapType.NORMAL_MAP_TYPE);
             map.addControl(new ZoomControl());
             map.addControl(new PositionControl());
             map.addControl(new MapTypeControl());
             geocoder = new ClientGeocoder();
             geocoder.addEventListener( GeocodingEvent.GEOCODING_SUCCESS, onGeocodeSuccess);
             geocoder.addEventListener( GeocodingEvent.GEOCODING_FAILURE, onGeocodeFault );
          }
         
         private function doGeocode():void 
         {
             geocoder.geocode(searchString.text);
          }
         
         private function onGeocodeSuccess( event : GeocodingEvent ) : void
         {
             var placemarks:Array = event.response.placemarks;
             if (placemarks.length > 0)
                map.setCenter(placemarks[0].point);
          }
         
         private function onGeocodeFault( event : GeocodingEvent ) : void
         {
             Alert.show("Geocoding failed");
             trace(event);
             trace(event.status);
          }
       
          private function setFilter() : void
          {
              var filter : ColorMatrixFilter = new ColorMatrixFilter();
              var matrix:Array = new Array();
              matrix = matrix.concat([r.value, 0, 0, 0, 0]); // red
              matrix = matrix.concat([0, g.value, 0, 0, 0]); // green
              matrix = matrix.concat([0, 0, b.value, 0, 0]); // blue
              matrix = matrix.concat([0, 0, 0, a.value, 0]); // alpha
              filter.matrix = matrix;
              setMapFilter( filter );
           }
          
          private function setFilterPreset() : void
          {
              switch  ( preset.selectedIndex )
              {
                  case 1: // grayscale
                     var red:Number = 0.3086; // luminance contrast value for red
                     var green:Number = 0.694; // luminance contrast value for green
                     var blue:Number = 0.0820; // luminance contrast value for blue
                     var cmf:ColorMatrixFilter = new ColorMatrixFilter([red, green, blue, 0, 0, 
                                                                        red, green, blue, 0, 0, 
                                                                        red, green, blue, 0, 0, 
                                                                        0, 0, 0, 1, 0]);
                     setMapFilter( cmf );
                     return;
                     break;
                  case 2: // Blood
                     r.value = .97;
                     g.value = .05;
                     b.value = .05;
                     a.value = .9;
                     break;
                  case 3: // Green
                     r.value = .05;
                     g.value = .65;
                     b.value = .05;
                     a.value = .9;
                     break;
                  case 4: // Yellow
                     r.value = .95;
                     g.value = .95;
                     b.value = .05;
                     a.value = .9;
                     break;
                  default:
                     r.value = 1;
                     g.value = 1;
                     b.value = 1;
                     a.value = 1;
                     break;
               }   
              setFilter();
           }
          
          private function setMapFilter( filter : ColorMatrixFilter ) : void
          {
              var s1:Sprite = map.getChildAt(1) as Sprite;
              var s2:Sprite = s1.getChildAt(0) as Sprite;
              s2.filters = [ filter ];   
           }
          
       ]]>
   </mx:Script>

   <mx:ApplicationControlBar dock="true" defaultButton="{ searchButton }">
      
      <mx:TextInput id="searchString" width="150" />
      <mx:Button click="doGeocode()" label="Find!" id="searchButton" />
      
   </mx:ApplicationControlBar>

   <maps:Map id="map" mapevent_mapready="onMapReady(event)" 
      width="100%" height="100%" key="API key goes here"/>

   <mx:Panel 
      top="50" right="10" 
      width="250" height="200"
      layout="vertical"
      title="Map Effects">
      
      <mx:Form width="100%" height="100%">
         
         <mx:FormItem label="preset:">
            <mx:ComboBox id="preset" 
               dataProvider="[ 'Normal', 'Gray Scale', 'Blood', 'Green', 'Yellow' ]" 
               change="setFilterPreset()" />      
         </mx:FormItem>
         
         
         <mx:FormItem label="red:">
            <mx:HSlider 
               minimum="0" maximum="2" value="1" 
               id="r" change="setFilter()" 
               liveDragging="true"  width="140"/>      
         </mx:FormItem>
         
         
         <mx:FormItem label="green:">
            <mx:HSlider 
               minimum="0" maximum="2" value="1" 
               id="g" change="setFilter()" 
               liveDragging="true"  width="140"/>      
         </mx:FormItem>
         
         
         <mx:FormItem label="blue:">
            <mx:HSlider 
               minimum="0" maximum="2" value="1" 
               id="b" change="setFilter()" 
               liveDragging="true"  width="140"/>      
         </mx:FormItem>
         
         
         <mx:FormItem label="alpha:">
            <mx:HSlider 
               minimum="0" maximum="1" value="1" 
               id="a" change="setFilter()" 
               liveDragging="true"  width="140"/>      
         </mx:FormItem>
         
      </mx:Form>
      
   </mx:Panel>
   
</mx:Application>
___________________________________
Andrew Trice
Principal Architect
Cynergy Systems
http://www.cynergysystems.com

Read more from Andrew Trice. Andrew Trice's Atom feed

Comments

8 Comments

DannyT said:

One good use of such a thing is accessibility concerns for those who can't see colours properly. Very cool stuff!

Brent Lamborn said:

Nice. I like grayscale. For me it makes the map much easier to read.

Krzysztof Kotlarski said:

Nice one it can realy improve accessibility

Pamela Fox said:

Thanks, Andrew, great post!

Since developers can potentially create un-usable maps with this hack, we are currently requesting that all developers re-coloring their maps formally request permission:
https://spreadsheets.google.com/viewform?formkey=cm0zMDkzOHZWMjJneEl2RVdkNFZRb0E6MA

We've approved most of the uses so far, we just want to make sure users are getting a good experience.

shiva said:

Google's mapping services are chock full of secrets. For a while Google Moon had a really great one.
http://www.googleeastereggs.com/

Hitesh Agja said:

Dear sir,

I have just tried your example in flex. but does not work. I dont know why filter is not applying on map. please help me.

Hitesh Agja said:

I got my answer. I done little change in your code. I have changed setMapFilter function. I removed all three lines and just set "map.filters" property directly. It works fine.

I hope it will helpful to others also !

Andrew Trice said:

Hitesh, this will also change the colors on the Google logo overlay. With the logic described above, it will not change the overlays.

Leave a comment


Tag Cloud

iPad

What's your take on the iPad? (Putting aside the Flash/iPad flame war)

Answer

Latest Features

Recommended for You

@InsideRIA on Twitter

Archives

  • Or, visit our complete archive.  

About This Site

Welcome to the premiere community site for all things RIA sponsored by O'Reilly Media and Adobe Systems Incorporated.