<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>Substance Labs</title>
	
	<link>http://labs.findsubstance.com</link>
	<description>Create. Constantly.</description>
	<lastBuildDate>Mon, 21 Dec 2009 17:42:00 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/SubstanceLabs" /><feedburner:info uri="substancelabs" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:emailServiceId>SubstanceLabs</feedburner:emailServiceId><feedburner:feedburnerHostname>http://feedburner.google.com</feedburner:feedburnerHostname><item>
		<title>Working with AMFPHP and the Google Maps Flash API</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/0PLZiUCZRtU/</link>
		<comments>http://labs.findsubstance.com/2009/09/25/working-with-amfphp-and-the-google-maps-flash-api/#comments</comments>
		<pubDate>Fri, 25 Sep 2009 18:11:50 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Google Maps]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/?p=200</guid>
		<description><![CDATA[We&#8217;ve been working a lot with the Google Maps Flash API lately; recent projects Ride Oregon and Oregon Bounty make regular use of Google Maps to plot various types of data. Each project raised unique challenges, the solutions to which were rarely found in Google&#8217;s documentation.
A note about setup: for data storage, retrieval, and manipulation, [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve been working a lot with the <a href="http://code.google.com/apis/maps/documentation/flash/">Google Maps Flash <abbr title="Application Programming Interface">API</abbr></a> lately; recent projects <a href="http://rideoregonride.com/">Ride Oregon</a> and <a href="http://bounty.traveloregon.com/">Oregon Bounty</a> make regular use of Google Maps to plot various types of data. Each project raised unique challenges, the solutions to which were rarely found in Google&#8217;s documentation.</p>
<p>A note about setup: for data storage, retrieval, and manipulation, we use <a href="http://www.amfphp.org/"><abbr title="Action Message Format PHP">AMFPHP</abbr></a>; for our local dev environment, <a href="http://mamp.info"><abbr title="Macintosh, Apache, Mysql and PHP">MAMP</abbr></a> and <a href="http://clickontyler.com/virtualhostx/">VirtualHostX</a>, managed with a <a href="http://www.smashingmagazine.com/2008/09/18/the-top-7-open-source-version-control-systems/">version control system</a>. That said, here are are some tips for working with the <a href="http://maps.googleapis.com/maps/flash/release/sdk.zip">Google Maps Flash <abbr title="Software Development Kit">SDK</abbr></a>:</p>
<ul>
<li><a href="#creating-custom-markers">Creating Custom Markers</a></li>
<li><a href="#tracking-markers">Tracking Markers Outside the Viewport</a></li>
<li><a href="#panning-markers">Panning Markers Back Into the Viewport</a></li>
<li><a href="#centering-on-markers">Centering on a Group of Markers</a></li>
<li><a href="#getting-elevation-data">Getting Elevation Data</a></li>
<li><a href="#plotting-long-routes">Plotting Long Routes</a></li>
<li><a href="#saving-an-image">Saving an Image of the Map</a></li>
<li><a href="#custom-amfphp-services">Custom AMFPHP Services</a></li>
</ul>
<p>
<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="395"> <param name="movie" value="/d/working-with-amfphp-and-the-google-maps-flash-api/map.swf" /> <param name="flashvars" value="apiKey=ABQIAAAA5z4K5KRtblC3mI7YX8Jp5RR7vnDOwvFcfFFvuaGW1Qd73xkJahQi2mvFBFAKclaabioQvA3_i5peHA&amp;gateway=/amfphp/gateway.php" /> <!--[if !IE]>--> <object type="application/x-shockwave-flash" data="/d/working-with-amfphp-and-the-google-maps-flash-api/map.swf" width="100%" height="395"> <param name="flashvars" value="apiKey=ABQIAAAA5z4K5KRtblC3mI7YX8Jp5RR7vnDOwvFcfFFvuaGW1Qd73xkJahQi2mvFBFAKclaabioQvA3_i5peHA&amp;gateway=/amfphp/gateway.php" /> <!--<![endif]--> <a href="http://adobe.com/go/getflashplayer">You need the Adobe Flash player to view this.</a> <!--[if !IE]>--> </object> <!--<![endif]--> </object>
</p>
<h2 id="creating-custom-markers">Creating Custom Markers</h2>
<p>To easily create custom markers, extend the <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#Marker">Marker</a> class and pass a custom icon display into <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#MarkerOptions">MarkerOptions</a> from the constructor. This keeps everything contained in one object, and makes references to the custom icon a snap.</p>
<pre><code>// extends Marker;
public var icon : CustomIcon;
public function CustomMarker ( latLng : LatLng )
{
  icon = new CustomIcon();
  icon.latLng = latLng;

  super( latLng, new MarkerOptions( { icon : icon } ) );
}</code></pre>
<h2 id="tracking-markers">Tracking Markers Outside the Viewport</h2>
<p>Tracking markers when they go offstage can be a pain, fortunately there are some <a href="http://code.google.com/p/gmaps-utility-library-flash/">useful libraries</a> written to help with that kind of thing. I&#8217;ve also included our custom implementation (<a href="/d/working-with-amfphp-and-the-google-maps-flash-api/classes/GhostTracker.as">GhostTracker.as</a>) as a part of the <a href="/d/working-with-amfphp-and-the-google-maps-flash-api/working-with-amfphp-and-the-google-maps-flash-api.zip">source code</a> for this post.</p>
<h2 id="panning-markers">Panning Markers Back Into the Viewport</h2>
<p>When a marker is offstage and is selected by the user, the map can be centered or panned to move the marker detail into view. Centering the map with <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#Map.setCenter">setCenter</a> can be a jarring user experience, since opening any marker will pan the map view; an alternate approach is to use the <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#Map.panBy">panBy</a> function to accomplish the same thing with only the minimal necessary movement:</p>
<pre><code>var pt : Point = map.fromLatLngToViewport( latLng );
var np : Point = new Point();
var edgePadding : Number = 10;
var center : Number = _detail.width * 0.5 + edgePadding * 2;
var displayHeight : Number = _detail.height + edgePadding;
var mapRect : Rectangle = new Rectangle( 0, 0, map.width, map.height );

// if x is less than left boundary ( data sort window right edge );
if ( pt.x - center &lt; mapRect.x ) np.x = ( pt.x - center ) - mapRect.x; // if x is greater than right edge; if ( pt.x + center &gt; mapRect.right - edgePadding ) np.x = ( pt.x + center ) - ( mapRect.right - edgePadding );

// if y is greater than map height - padding;
if ( pt.y &gt; mapRect.bottom - edgePadding ) np.y = pt.y - ( mapRect.bottom - edgePadding );

// if y - height is less than top edge;
if ( pt.y - displayHeight &lt; edgePadding * 2 ) np.y = ( pt.y - displayHeight ) - edgePadding * 2;

// position map so that full display area is visible;
map.panBy( np );</code></pre>
<h2 id="centering-on-markers">Centering on a Group of Markers</h2>
<p>When working with an array of markers that need to be displayed together within the viewport, a <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#LatLngBounds">LatLngBounds</a> object can be extended to include all <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#LatLng">LatLng</a> points. From there, it&#8217;s just a matter of setting the center of the map to the center of the bounds area.</p>
<pre><code>var bounds : LatLngBounds = new LatLngBounds();
var marker : Marker;
var latLng : LatLng;
var maxZoom : Number = 13;
var t : int = markers.length;
for ( var i : int = 0; i &lt; t; i++ )
{
  marker = markers[ i ] as Marker;

  latLng = marker.getLatLng();

  if ( latLng.lat() != 0 &amp;&amp; latLng.lng() != 0 ) bounds.extend( latLng );
}

if ( !bounds.isEmpty() ) map.setCenter( bounds.getCenter(), Math.min( maxZoom, map.getBoundsZoomLevel( bounds ) ) );</code></pre>
<h2 id="getting-elevation-data">Getting Elevation Data</h2>
<p>Elevation data for routes and markers can be retrieved and stored efficiently via PHP, or at runtime in AS3, using a couple of <a href="http://www.geonames.org/export/web-services.html">different</a> <a href="http://gisdata.usgs.gov/XMLWebServices/TNM_Elevation_Service.php">sources</a>.</p>
<pre><code>// PHP with vars $lat &amp; $lng (returns value in meters);
$primary = "http://ws.geonames.org/srtm3?lat=$lat&amp;lng=$lng";
$secondary = "http://gisdata.usgs.gov/xmlwebservices2/elevation_service.asmx/getElevation?X_Value=$lng&amp;Y_Value=$lat&amp;Elevation_Units=METERS&amp;Source_Layer=-1&amp;Elevation_Only=TRUE";</code></pre>
<h2 id="plotting-long-routes">Plotting Long Routes</h2>
<p>When plotting routes on custom maps in Ride Oregon, we often had to exceed the 25 point max in the <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#Directions.loadFromWaypoints">loadFromWaypoints</a> function of the <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#Directions">Directions</a> class. The solution was simply to queue multiple requests, with the last point from the previous request as the first point in the new one.</p>
<pre><code>// assumes class variable _waypoints is an array containing stored points to get directions for;
var max : Number = 25;
var tot : Number = _waypoints.length;
var req : Number = Math.ceil( _waypoints.length / max )
var per : Number = Math.min( max, tot );
var first : Marker;

// split directions into multiple requests;
for ( var j : int = 0; j &lt; req; j++ )
{
  // store latLng points;
  var waypoints : Array = [];

  // store first recorded point as first point in new query;
  if ( first ) waypoints.push( first.getLatLng() );

  per = Math.min( max, tot );

  // create series of directions with max or fewer waypoints;
  for ( var k : int = 0; k &lt; per; k++ )
  {
    var w : Marker = _waypoints[ k + j * max ];

    waypoints.push( w.getLatLng() );
  }

  // reduce total;
  tot -= max;

  // store first point;
  first = w;

  // break if invalid request;
  if ( waypoints.length &lt;= 1 ) break;

  // set up new directions instance;
  var directions : Directions = new Directions( new DirectionsOptions( { avoidHighways : true } ) );
  directions.addEventListener( DirectionsEvent.DIRECTIONS_SUCCESS, onDirectionsSuccess );
  directions.addEventListener( DirectionsEvent.DIRECTIONS_FAILURE, onDirectionsFailure );

  // get new set of directions;
  directions.loadFromWaypoints( waypoints );
}</code></pre>
<p>Listen for a response <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#DirectionsEvent">DirectionsEvent</a> to be dispatched:</p>
<pre><code>function onDirectionsSuccess ( e : DirectionsEvent ) : void
{
  // push e.directions to array of direction requests;
  // add to e.directions.distance to total route distance;
  // add e.directions.createPolyline to map;
}

function onDirectionsFailure ( e : DirectionsEvent ) : void
{
  // failed;
}</code></pre>
<h2 id="saving-an-image">Saving an Image of the Map</h2>
<p>In order to create no-flash versions of all the maps, we combined the display layer of the map, with Google&#8217;s <a href="http://code.google.com/apis/maps/documentation/staticmaps/">Static Map API</a>. Initially, we went this route because there was no other option (Google had banned access to their images via BitmapData.draw, and it would throw a SecurityError), but they&#8217;ve since <a href="http://code.google.com/p/gmaps-api-issues/issues/detail?id=545#c26">removed the restriction</a> and added a <a href="http://code.google.com/apis/maps/documentation/flash/reference.html#Map.getPrintableBitmap">getPrintableBitmap</a> function to the API. Still, if you load content into your icons from another domain, or just don&#8217;t want to deal with crossdomain policy files, layering the Static API is a decent solution.</p>
<pre><code>// resolves Error #2121: Security sandbox violation: BitmapData.draw
function saveMapImage () : void
{
  var rect : Rectangle = new Rectangle( 0, 0, Math.min( map.width, 640 ), Math.min( map.height, 640 ) );
  var bmd : BitmapData = new BitmapData( rect.width, rect.height, true, 0x00000000 );
  var mapDisplay : Sprite = Sprite( Sprite( Sprite( map.getDisplayObject() ).getChildAt( 1 ) ).getChildAt( 2 ) );

  // draw custom overlay;
  bmd.draw( mapDisplay, null, null, null, rect, true );

  // encode ByteArray and send to server...
}</code></pre>
<h2 id="custom-amfphp-services">Custom AMFPHP Services</h2>
<p>We&#8217;ve put together an abstract set of <a href="/d/working-with-amfphp-and-the-google-maps-flash-api/classes/amfphp/AMFService.as">AMFService</a> and <a href="/d/working-with-amfphp-and-the-google-maps-flash-api/classes/amfphp/AMFServiceEvent.as">AMFServiceEvent</a> classes to work with AMFPHP. This way you can write a service in PHP, and call its methods directly on an instance of the AMFService class in ActionScript. There are plenty of features that could be added to this implementation (service method and parameter checking, for instance), but for most cases its a clean and flexible approach. If you have a method called getCustomData defined in CustomService.php, setting up an interface is simple:</p>
<pre><code>var customService : AMFService = new AMFService( 'CustomService', '/amfphp/gateway.php' );
customService.addEventListener( AMFServiceEvent.RETURN, onServiceData );
customService.getCustomData();

function onServiceData ( e : AMFServiceEvent ) : void
{
  trace( e.data );
}</code></pre>
<p>Hopefully a few of these techniques save some headaches when working with Google Maps in Flash. Feel free to post a comment with your own solutions.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=0PLZiUCZRtU:2T3dWEj2ISU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=0PLZiUCZRtU:2T3dWEj2ISU:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=0PLZiUCZRtU:2T3dWEj2ISU:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=0PLZiUCZRtU:2T3dWEj2ISU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=0PLZiUCZRtU:2T3dWEj2ISU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=0PLZiUCZRtU:2T3dWEj2ISU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=0PLZiUCZRtU:2T3dWEj2ISU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=0PLZiUCZRtU:2T3dWEj2ISU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=0PLZiUCZRtU:2T3dWEj2ISU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=0PLZiUCZRtU:2T3dWEj2ISU:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/0PLZiUCZRtU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2009/09/25/working-with-amfphp-and-the-google-maps-flash-api/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2009/09/25/working-with-amfphp-and-the-google-maps-flash-api/</feedburner:origLink></item>
		<item>
		<title>Don’t lose your :focus</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/4SyNlhCLnOs/</link>
		<comments>http://labs.findsubstance.com/2009/09/15/dont-lose-your-focus/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 23:21:41 +0000</pubDate>
		<dc:creator>Cory Duncan</dc:creator>
				<category><![CDATA[Accessibility]]></category>
		<category><![CDATA[CSS]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/?p=202</guid>
		<description><![CDATA[CSS resets are great. Without them, our jobs as UI developers would be much more frustrating, or at the least, more tedious. They give us a (mostly) level playing field when building user interfaces that work across multiple browsers. My personal favorite, and probably the most-used reset stylesheet, is the one Eric Meyer has built [...]]]></description>
			<content:encoded><![CDATA[<p><abbr title="Cascading Style Sheets">CSS</abbr> resets are great. Without them, our jobs as <abbr title="User Interface">UI</abbr> developers would be much more frustrating, or at the least, more tedious. They give us a (mostly) level playing field when building user interfaces that work across multiple browsers. My personal favorite, and probably the most-used reset stylesheet, is the one Eric Meyer has <a href="http://meyerweb.com/eric/thoughts/2007/04/18/reset-reasoning/">built</a> and <a href="http://meyerweb.com/eric/tools/css/reset/">maintained</a>. It works great and has <a href="http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/">solid</a> <a href="http://meyerweb.com/eric/thoughts/2008/01/15/resetting-again/">reasoning</a> behind it.</p>
<p>What does this have to do with the focus state? Part of the reset includes resetting the focus state style.</p>
<pre><code>/* remember to define focus styles! */
:focus {
	outline: 0;
}
</code></pre>
<p>Note the comment there&#8230;</p>
<p>Resetting the focus state is fine, I&#8217;d encourage it in fact &#8212; the default browser focus state is ugly! Here&#8217;s an example of what the default focus state for Firefox (3.5 Mac) looks like:</p>
<p><img src="http://labs.findsubstance.com/wp-content/uploads/2009/09/default-focus-state.png" alt="" width="47" height="35" /></p>
<p>Even though Eric explicitly states in his reset CSS to define a focus style, in my experience this step is often neglected. Without a focus style defined, using the keyboard as a navigation device becomes a more difficult task. Keyboard navigation may be an edge case, but a focus state should always be considered. </p>
<p>The simplest solution is to extend the hover style:</p>
<pre><code>a:hover, a:focus {
	color: #666;
	}</code></pre>
<p>With one extra selector, we&#8217;ve made the interface more accessible to keyboard navigation. For more complex interfaces with varying hover styles, you may need to declare more than one focus style, but that&#8217;s a small price to pay for accessibility.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=4SyNlhCLnOs:d9593s2k1fY:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=4SyNlhCLnOs:d9593s2k1fY:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=4SyNlhCLnOs:d9593s2k1fY:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=4SyNlhCLnOs:d9593s2k1fY:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=4SyNlhCLnOs:d9593s2k1fY:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=4SyNlhCLnOs:d9593s2k1fY:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=4SyNlhCLnOs:d9593s2k1fY:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=4SyNlhCLnOs:d9593s2k1fY:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=4SyNlhCLnOs:d9593s2k1fY:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=4SyNlhCLnOs:d9593s2k1fY:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/4SyNlhCLnOs" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2009/09/15/dont-lose-your-focus/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2009/09/15/dont-lose-your-focus/</feedburner:origLink></item>
		<item>
		<title>Fixing the IE8 Form Button with Background Image On Click CSS Bug</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/v8kBiDQuufU/</link>
		<comments>http://labs.findsubstance.com/2009/05/21/ie8-form-button-with-background-image-on-click-css-bug/#comments</comments>
		<pubDate>Thu, 21 May 2009 20:36:06 +0000</pubDate>
		<dc:creator>Cory Duncan</dc:creator>
				<category><![CDATA[CSS]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[ie8]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/?p=107</guid>
		<description><![CDATA[That&#8217;s really the best title I could come up with to describe this head-banger of a bug I&#8217;ve encountered. I searched and scoured the tubes of the Internet, but couldn&#8217;t find anyone talking about it, so I thought I&#8217;d share my experience so far.
From my testing, I&#8217;ve found this is only an issue in Internet [...]]]></description>
			<content:encoded><![CDATA[<p>That&#8217;s really the best title I could come up with to describe this head-banger of a bug I&#8217;ve encountered. I searched and scoured the tubes of the Internet, but couldn&#8217;t find anyone talking about it, so I thought I&#8217;d share my experience so far.</p>
<p>From my testing, I&#8217;ve found this is only an issue in Internet Explorer 8 (hats off to Microsoft for a brand new <abbr title="Cascading Style Sheets">CSS</abbr> bug).</p>
<h2 id="thesetup">The Setup</h2>
<p>The setup for this bug is fairly straightforward. It requires a <code>&lt;button&gt;</code> or submit <code>&lt;input&gt;</code> that has a background image. For this example, I&#8217;ll use the <code>&lt;button&gt;</code> element. I&#8217;ll also be using image replacement to hide the button&#8217;s <abbr title="HyperText Markup Language">HTML</abbr> text. I believe this makes the bug more apparent, though it has nothing to do with the actual bug.</p>
<p>The markup:</p>
<pre><code>&lt;button type="submit"&gt;Submit&lt;/button&gt;</code></pre>
<p>The CSS:</p>
<pre><code>button {
	background: url(button.png) no-repeat 0 0;
	border: 0;
	display: block;
	height: 30px;
	margin: 0;
	padding: 0;
	text-indent: -9999px;
	width: 81px;
	}
button:hover {
	background-position: 0 -30px;
	}</code></pre>
<h2>Experiencing the Bug</h2>
<p>On first glance, it appears that everything is fine in <abbr title="Internet Explorer">IE</abbr>8. The problem occurs when the button is in its active state. Upon clicking the button, the background image shifts -1px to the top and left, though the container of the button stays in the same position. Here&#8217;s a <a href="http://labs.findsubstance.com/d/ie8-form-button-with-background-image-on-click-css-bug/bug.html">demo</a> (view this in IE8) of the bug in action, and here&#8217;s a screenshot (I&#8217;ve added a red outline to help illustrate the background shift):</p>
<p><img src="http://labs.findsubstance.com/d/ie8-form-button-with-background-image-on-click-css-bug/bug.png" alt="" /></p>
<h2>So how do you fix this?</h2>
<p>I was able to find some workarounds for this bug, and though none are completely bulletproof, all are better than the alternative (doing nothing).</p>
<h3>Solution 1: Mo&#8217; Markup + Mo&#8217; CSS (<a href="http://labs.findsubstance.com/d/ie8-form-button-with-background-image-on-click-css-bug/solution1.html">demo</a>)</h3>
<p>One option is to add an extra element within the <code>&lt;button&gt;</code> and target that element for the background-image. We can use the same base CSS from <a href="#thesetup">The Setup</a> with some additional IE-specific CSS.</p>
<p>The markup:</p>
<pre><code>&lt;button type="submit"&gt;&lt;span&gt;Submit&lt;/span&gt;&lt;/button&gt;</code></pre>
<p>The IE-specific (version 8 and below) CSS:</p>
<pre><code>button {
	position: relative;
	}
button span {
	background: url(button.png) no-repeat 0 0;
	height: 30px;
	left: 0;
	position: absolute;
	top: 0;
	width: 100%;
	}
button:hover span {
	background-position: 0 -30px;
	}</code></pre>
<p>There are a number of problems with this solution.</p>
<ol>
<li>Requires extraneous markup.</li>
<li>Will not work for a submit <code>&lt;input&gt;</code> element, as it does not allow for any child elements.</li>
<li>Requires IE specific CSS to absolutely position the extra element &#8211; neglecting to do so will result in an opposite 1px shift to the right and bottom in IE (version 8 and below). If this CSS is not targeted for IE, Mozilla browsers (at least Firefox 2 and 3) exhibit a different bug altogether (a topic for a future post).</li>
</ol>
<p>Because of the problems associated with this solution, I don&#8217;t recommend this approach.</p>
<h3>Solution 2: JavaScript-only</h3>
<p>I&#8217;m sure this could be fixed using IE8-targeted JavaScript, but I&#8217;d rather not rely on it, as it would break down if the browsing device has JavaScript disabled or lacks JavaScript support. Let&#8217;s try a CSS-only method (my preference)&#8230;</p>
<h3>Solution 3: CSS-only (<a href="http://labs.findsubstance.com/d/ie8-form-button-with-background-image-on-click-css-bug/solution3.html">demo</a>)</h3>
<p>With the release of IE8, Microsoft has added several <a href="http://blogs.msdn.com/ie/archive/2008/09/08/microsoft-css-vendor-extensions.aspx" target="_blank">proprietary CSS extensions</a>. Each of these extensions work in IE8, but not in previous IE versions, or any non-IE browsers. Because this bug is isolated to IE8, we can take advantage of these extensions.</p>
<p>The CSS:</p>
<pre><code>button:active {
	-ms-background-position-x: 1px;
	-ms-background-position-y: -29px;
	}</code></pre>
<p>This CSS counters the bug, by positioning the background top and left 1px. This offset is relative to the button’s hover state, using the height dimension to offset the y-axis (in this case 30px height -1px offset results in -29px for the y-axis offset). If your button has no hover state, the offset would be relative to the button&#8217;s default background position. This can be safely included in your main stylesheet without affecting other modern browsers, but as a best practice I&#8217;d recommend including this in a separate IE stylesheet along with any other IE-specific CSS (using <a href="http://quirksmode.org/css/condcom.html" target="_blank">CSS conditional comments</a> to target IE).</p>
<p>As I mentioned, none of the solutions are bulletproof and that includes this one. If you click the button and drag your cursor off the button&#8217;s boundaries, the background shift is visible. I feel that this type of interaction is atypical and most users will click the button without much movement, so this is my recommended approach for the time being.</p>
<h2>In Conclusion</h2>
<p>I&#8217;d love to hear any alternative solutions for this issue. Track and vote for this bug on <a href="https://connect.microsoft.com/onecare/feedback/ViewFeedback.aspx?FeedbackID=455723" target="_blank">Microsoft Connect</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=v8kBiDQuufU:nE3VjPmCejo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=v8kBiDQuufU:nE3VjPmCejo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=v8kBiDQuufU:nE3VjPmCejo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=v8kBiDQuufU:nE3VjPmCejo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=v8kBiDQuufU:nE3VjPmCejo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=v8kBiDQuufU:nE3VjPmCejo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=v8kBiDQuufU:nE3VjPmCejo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=v8kBiDQuufU:nE3VjPmCejo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=v8kBiDQuufU:nE3VjPmCejo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=v8kBiDQuufU:nE3VjPmCejo:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/v8kBiDQuufU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2009/05/21/ie8-form-button-with-background-image-on-click-css-bug/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2009/05/21/ie8-form-button-with-background-image-on-click-css-bug/</feedburner:origLink></item>
		<item>
		<title>SXSWLesson.com</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/D-ClaHIziGw/</link>
		<comments>http://labs.findsubstance.com/2009/03/20/sxswlessoncom/#comments</comments>
		<pubDate>Sat, 21 Mar 2009 00:10:56 +0000</pubDate>
		<dc:creator>Stephen Landau</dc:creator>
				<category><![CDATA[Experiments]]></category>
		<category><![CDATA[Inspiration]]></category>
		<category><![CDATA[SXSW]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/?p=102</guid>
		<description><![CDATA[We have been incredibly inspired by the presentations at South by Southwest (SXSW). More than each individual panel and presentation we attended, we had the opportunity to meet so many smart, thoughtful people to continue our discussions with outside the lecture halls. One of the most interesting aspects of SXSW is the luck, or some [...]]]></description>
			<content:encoded><![CDATA[<p>We have been incredibly inspired by the presentations at South by Southwest (SXSW). More than each individual panel and presentation we attended, we had the opportunity to meet so many smart, thoughtful people to continue our discussions with outside the lecture halls. One of the most interesting aspects of SXSW is the luck, or some might say fate, of meeting different people to join in these conversations.</p>
<h2>So we thought (as we often do), <em>wouldn&#8217;t it be cool to combine the random meeting of people with the lessons learned from SXSW presentations?</em> After some quick emails back to SWHQ to discuss, the idea for <a href="http://sxswlesson.com/" target="_blank">SXSWLesson.com</a> was born.</h2>
<p>We don&#8217;t see <a href="http://sxswlesson.com/" target="_blank">SXSWLesson.com</a> as a comprehensive play-by-play of every panel, but more of a place to capture the insights and nuggets of knowledge. It&#8217;s a way for everyone – panelists, presenters, and attendees – to share the lessons they learned. By adding the <strong><em>#sxswlesson</em></strong> hashtag to your insights via Twitter, you automatically share your wisdom with the crowd via the <a href="http://sxswlesson.com/" target="_blank">SXSWLesson.com</a> site. In turn, people can comment on each insight to continue the conversation. You can browse all of the lessons sequentially, and you can also randomly view the lessons, much in the same way that you randomly come across interesting people around the convention center and out on the streets. You can also follow <a href="http://twitter.com/SXSWLesson" target="_blank">twitter.com/SXSWLesson</a> to receive new ideas right to your Twitter account.</p>
<p>The other thing we implemented on the site is the new <a href="http://apiwiki.twitter.com/OAuth-FAQ" target="_blank">Twitter OAuth</a> into the site, which accesses peoples&#8217; Twitter accounts through the SXSWLesson.com site without them having to share their username/password with us. Basically this allows Twitter users to comment on the site and associate their Twitter profile with their comment, which in turn can increase the level of conversation between people.</p>
<p>As a <a href="http://labs.findsubstance.com/">Substance Labs</a> project, we moved this one through quickly, focusing on the most important task: <strong>helping people share ideas.</strong> Erin, Cory and Eric honed the vision to launch within four days of coming up with the concept. Nothing like rapid prototyping, launching, and seeing what happens.</p>
<p>Hope you enjoy it! Oh, and if you can help spread the word about <a href="http://sxswlesson.com/" target="_blank">SXSWLesson.com</a> and let people know to add the #sxswlesson hashtag, you&#8217;ll be contributing to a richer, deeper conversation. So thanks in advance for that.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=D-ClaHIziGw:ogT-OEPB3fo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=D-ClaHIziGw:ogT-OEPB3fo:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=D-ClaHIziGw:ogT-OEPB3fo:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=D-ClaHIziGw:ogT-OEPB3fo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=D-ClaHIziGw:ogT-OEPB3fo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=D-ClaHIziGw:ogT-OEPB3fo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=D-ClaHIziGw:ogT-OEPB3fo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=D-ClaHIziGw:ogT-OEPB3fo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=D-ClaHIziGw:ogT-OEPB3fo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=D-ClaHIziGw:ogT-OEPB3fo:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/D-ClaHIziGw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2009/03/20/sxswlessoncom/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2009/03/20/sxswlessoncom/</feedburner:origLink></item>
		<item>
		<title>UPDATED: Using AS3 to Upload and Encode Images</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/VEpjPjAFqwQ/</link>
		<comments>http://labs.findsubstance.com/2008/10/24/updated-using-as3-to-upload-and-encode-images/#comments</comments>
		<pubDate>Fri, 24 Oct 2008 18:43:43 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[Experiments]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Research]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/?p=99</guid>
		<description><![CDATA[After many requests, I&#8217;ve updated the demo and source files for the wildly popular labs post Using AS3 to Upload and Encode Images. Hope everyone finds it helpful.
]]></description>
			<content:encoded><![CDATA[<p>After many requests, I&#8217;ve updated the <a href="http://labs.findsubstance.com/d/as3-upload-encode-images/">demo</a> and <a href="http://labs.findsubstance.com/d/as3-upload-encode-images/as3-upload-encode-images.zip">source</a> files for the wildly popular labs post <a href="http://labs.findsubstance.com/2008/04/03/as3-upload-encode-images/">Using AS3 to Upload and Encode Images</a>. Hope everyone finds it helpful.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VEpjPjAFqwQ:qa99_Hy7PW8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VEpjPjAFqwQ:qa99_Hy7PW8:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VEpjPjAFqwQ:qa99_Hy7PW8:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VEpjPjAFqwQ:qa99_Hy7PW8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VEpjPjAFqwQ:qa99_Hy7PW8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VEpjPjAFqwQ:qa99_Hy7PW8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VEpjPjAFqwQ:qa99_Hy7PW8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VEpjPjAFqwQ:qa99_Hy7PW8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VEpjPjAFqwQ:qa99_Hy7PW8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VEpjPjAFqwQ:qa99_Hy7PW8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/VEpjPjAFqwQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2008/10/24/updated-using-as3-to-upload-and-encode-images/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2008/10/24/updated-using-as3-to-upload-and-encode-images/</feedburner:origLink></item>
		<item>
		<title>Dynamic Image Creation with Adobe AIR</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/l_3TIUjSGo0/</link>
		<comments>http://labs.findsubstance.com/2008/10/16/dynamic-image-creation-with-adobe-air/#comments</comments>
		<pubDate>Thu, 16 Oct 2008 22:15:00 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[AIR]]></category>
		<category><![CDATA[AS3]]></category>
		<category><![CDATA[Experiments]]></category>
		<category><![CDATA[Research]]></category>
		<category><![CDATA[image encoding]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/?p=45</guid>
		<description><![CDATA[We&#8217;ve put together a simple AIR application that allows you to load a SWF, select any class, and export a series of PNG or JPEG images. Potential uses for this tool range from photoshop-style batch image creation to randomized image painting ala Erik Natzke.
There&#8217;s a built in help section, but here&#8217;s a short video that [...]]]></description>
			<content:encoded><![CDATA[<p>We&#8217;ve put together a simple <a href="http://get.adobe.com/air/">AIR</a> application that allows you to load a SWF, select any class, and export a series of PNG or JPEG images. Potential uses for this tool range from photoshop-style batch image creation to <a href="http://www.flickr.com/photos/natzke/2924200721/">randomized image painting</a> ala <a href="http://jot.eriknatzke.com/">Erik Natzke</a>.</p>
<p>There&#8217;s a built in help section, but here&#8217;s a short video that outlines the basic idea:</p>
<p><object width="500" height="377"><param name="allowfullscreen" value="true" /><param name="allowscriptaccess" value="always" /><param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=1986693&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=990000&amp;fullscreen=1" /><embed src="http://vimeo.com/moogaloop.swf?clip_id=1986693&amp;server=vimeo.com&amp;show_title=1&amp;show_byline=0&amp;show_portrait=0&amp;color=990000&amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="500" height="377"></embed></object></p>
<p>Since I didn&#8217;t include a voiceover for this example, the basic steps involved are:</p>
<ol>
<li>Export a custom class on an empty symbol.</li>
<li>Write logic to add a text field and draw a circle.</li>
<li>Publish SWF and load into the image encoder.</li>
<li>Create 20 PNG images in the &#8220;output&#8221; folder on the Desktop.</li>
</ol>
<p>Extra notes on functionality:</p>
<ol>
<li>The application attempts to pass in the current serial index to the constructor of the class you&#8217;ve chosen. This has a variety of uses, but is especially good for looking up array data, or directly populating a text field (as in the example above).</li>
<li>Even if you don&#8217;t declare a constructor parameter, the export will still run just fine. This makes it easy to see what any class will look like as an image, or to export a series of images from a <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/Math.html#random()">Math.random</a>-based visualization class.</li>
</ol>
<p>The application is available for download <a href="http://labs.findsubstance.com/d/dynamic-image-creation-with-adobe-air/ImageEncoder.air">here</a>. If you have any questions or requests, post a comment and I&#8217;ll do my best to help out.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=l_3TIUjSGo0:hGcn3l86dts:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=l_3TIUjSGo0:hGcn3l86dts:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=l_3TIUjSGo0:hGcn3l86dts:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=l_3TIUjSGo0:hGcn3l86dts:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=l_3TIUjSGo0:hGcn3l86dts:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=l_3TIUjSGo0:hGcn3l86dts:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=l_3TIUjSGo0:hGcn3l86dts:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=l_3TIUjSGo0:hGcn3l86dts:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=l_3TIUjSGo0:hGcn3l86dts:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=l_3TIUjSGo0:hGcn3l86dts:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/l_3TIUjSGo0" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2008/10/16/dynamic-image-creation-with-adobe-air/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2008/10/16/dynamic-image-creation-with-adobe-air/</feedburner:origLink></item>
		<item>
		<title>Proportional Scaling Techniques in AS3</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/Xz2dyN-k9Nw/</link>
		<comments>http://labs.findsubstance.com/2008/07/07/as3-scaling-techniques/#comments</comments>
		<pubDate>Mon, 07 Jul 2008 14:59:19 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[AS3]]></category>
		<category><![CDATA[Flash]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/2008/07/07/as3-scaling-techniques/</guid>
		<description><![CDATA[The ability to proportionally scale an object to fit within, or fill a region is a powerful technique with a variety of applications. We used this approach on Logobama to allow users to upload any size photo and automatically scale it to fit within the available space, before saving out an image from Flash.
The source [...]]]></description>
			<content:encoded><![CDATA[<p>The ability to proportionally scale an object to fit within, or fill a region is a powerful technique with a variety of applications. We used this approach on <a href="http://logobama.com">Logobama</a> to allow users to upload any size photo and automatically scale it to fit within the available space, before <a href="http://labs.findsubstance.com/2008/04/03/as3-upload-encode-images/">saving out an image from Flash</a>.</p>
<p>The <a href="http://labs.findsubstance.com/d/as3-scaling-techniques/as3-scaling-techniques.zip">source code</a> for this post includes a ScalingImage class that loads an image and responds to any <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/Stage.html#event:resize">stage resize event</a> by proportionally scaling the image to fill the stage. Check out the <a href="http://labs.findsubstance.com/d/as3-scaling-techniques/">demo</a> and try resizing your browser.</p>
<p>The code behind a proportionally scaled full screen image is fairly straightforward:</p>
<pre><code>// set image dimensions to match stage;
image.width = stage.stageWidth;
image.height = stage.stageHeight;

// choose the larger scale property and match the other to it;
( image.scaleX &lt; image.scaleY ) ? image.scaleY = image.scaleX : image.scaleX = image.scaleY;
</code></pre>
<p>Since scaleX and scaleY are percentages, it&#8217;s just a matter of figuring out which property is larger and making the two equal.</p>
<p>By swapping the scale comparison from &#8220;greater than&#8221; to &#8220;less than&#8221;, the object will scale proportionally to fit the larger of the two dimensions given. This kind of calculation is handy when you need to fit items of variable dimensions into a fixed space, such as the flickr photos on the <a href="http://authenticitybook.com/axiom-gallery/">Authenticity Book Axiom Gallery</a>.</p>
<pre><code>// choose the smaller scale property and match the other to it;
( image.scaleX &gt; image.scaleY ) ? image.scaleY = image.scaleX : image.scaleX = image.scaleY;
</code></pre>
<p>There are many applications for this technique, from creating image thumbnails to building a liquid grid layout. We&#8217;d love to see more examples of this approach in action, so feel free to leave a link or two in the comments.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=Xz2dyN-k9Nw:HoQ0_dm7bvI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=Xz2dyN-k9Nw:HoQ0_dm7bvI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=Xz2dyN-k9Nw:HoQ0_dm7bvI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=Xz2dyN-k9Nw:HoQ0_dm7bvI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=Xz2dyN-k9Nw:HoQ0_dm7bvI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=Xz2dyN-k9Nw:HoQ0_dm7bvI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=Xz2dyN-k9Nw:HoQ0_dm7bvI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=Xz2dyN-k9Nw:HoQ0_dm7bvI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=Xz2dyN-k9Nw:HoQ0_dm7bvI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=Xz2dyN-k9Nw:HoQ0_dm7bvI:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/Xz2dyN-k9Nw" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2008/07/07/as3-scaling-techniques/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2008/07/07/as3-scaling-techniques/</feedburner:origLink></item>
		<item>
		<title>Layering Transparent Flash Content over HTML with Scripted Masking</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/VeGunGkajBE/</link>
		<comments>http://labs.findsubstance.com/2008/06/30/transparent-flash-over-html/#comments</comments>
		<pubDate>Mon, 30 Jun 2008 14:59:15 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[Flash]]></category>
		<category><![CDATA[HTML]]></category>
		<category><![CDATA[Research]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/2008/06/30/transparent-flash-over-html/</guid>
		<description><![CDATA[Anyone who has ever tried to display transparent Flash content over HTML knows that getting things to sort properly on the z-index can be frustrating. Flash has an annoying tendency to force itself to render above of all other content  Some browsers have trouble rendering plugin content consistently, which can make HTML stacked below [...]]]></description>
			<content:encoded><![CDATA[<p>Anyone who has ever tried to display <a href="http://labs.findsubstance.com/d/transparent-flash-over-html/">transparent Flash content over <abbr title="Hypertext Markup Language">HTML</abbr></a> knows that getting things to sort properly on the z-index can be frustrating. <del>Flash has an annoying tendency to force itself to render above of all other content</del>  Some browsers have trouble rendering plugin content consistently, which can make HTML stacked below Flash content inaccessible to the user. The technique described below is meant to ensure a consistent cross-browser user experience when it comes to issues with flickering or unwanted re-sorting of transparent Flash content. </p>
<p>We at <a href="http://findsubstance.com">Substance</a> have come across this a number of times, and <a href="http://labs.findsubstance.com/d/transparent-flash-over-html/transparent-flash-over-html.zip">the best solution</a> we have found is to knock out the areas of the Flash movie that require accessible content displayed below. This can be accomplished rather easily with the use of <a href="http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/display/BlendMode.html">layer blend modes</a>. </p>
<p>The first step to making this work is to set <strong>wmode</strong> in your HTML <a href="http://code.google.com/p/swfobject/wiki/SWFObject_2_0_documentation">Flash embed code</a> to <strong>transparent</strong>. After that is done, you can immediately take advantage of this trick:</p>
<ol>
<li>Set the blendMode property in your Document Class to BlendMode.LAYER</li>
<li>Set the blendMode property of your knockout area to BlendMode.ERASE</li>
</ol>
<p>This approach differs from creating a true mask, which acts as a window to the clip being masked, by doing the reverse &ndash; creating a window <em>through</em> the clip being masked, which in this case is the entire SWF.</p>
<p>Here is a quick example ( assuming &#8220;this&#8221; is your document class ):</p>
<pre><code>// set blendMode for Document Class;
this.blendMode = BlendMode.LAYER;

// create knockout area;
var knockout : Sprite = new Sprite();

// draw 50 x 100 px box;
with ( knockout.graphics )
{
	beginFill( 0x000000 );
	drawRect( 0, 0, 50, 100 );
}

// give mask knockout powers;
knockout.blendMode = BlendMode.ERASE;

// add knockout mask to stage;
this.addChild( knockout );</code></pre>
<p>On the <a href="http://arakawagrip.com">Arakawa home page</a>, the Flash area is set to fill the browser window completely. The logo, navigation, and footer are all knocked out, with a listener attached to the stage for Event.RESIZE so that the footer window always remains at the bottom of the file. This is pretty simple, but here&#8217;s a snippet of to show how to keep an item positioned at the bottom of the stage:</p>
<pre><code>// add listener to stage in constructor;
stage.addEventListener( Event.RESIZE, onResize );

// resize listener in class body;
private function onResize () : void
{
	knockout.y = stage.stageHeight - knockout.height;
}
</code></pre>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VeGunGkajBE:VfvuC_ZhsbI:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VeGunGkajBE:VfvuC_ZhsbI:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VeGunGkajBE:VfvuC_ZhsbI:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VeGunGkajBE:VfvuC_ZhsbI:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VeGunGkajBE:VfvuC_ZhsbI:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VeGunGkajBE:VfvuC_ZhsbI:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VeGunGkajBE:VfvuC_ZhsbI:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VeGunGkajBE:VfvuC_ZhsbI:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=VeGunGkajBE:VfvuC_ZhsbI:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=VeGunGkajBE:VfvuC_ZhsbI:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/VeGunGkajBE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2008/06/30/transparent-flash-over-html/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2008/06/30/transparent-flash-over-html/</feedburner:origLink></item>
		<item>
		<title>Recognizing the Unsung Heroes of Spam</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/SRTMaKYp1NU/</link>
		<comments>http://labs.findsubstance.com/2008/06/23/recognizing-the-unsung-heroes-of-spam/#comments</comments>
		<pubDate>Mon, 23 Jun 2008 19:59:50 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[Experiments]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/2008/06/23/recognizing-the-unsung-heroes-of-spam/</guid>
		<description><![CDATA[Spammers commit their lives to ridding the world of overpriced pharma$euticals, embarrassing bedroom s!tuations, and wasted years spent &#8220;earning&#8221; a diplom@. Who can calculate the uncollected overseas lottery winnings, or untold stories of exiled Nigerian royalty the world would suffer without their unwavering dedication?
It&#8217;s time that we recognize the true genius behind a well-crafted piece [...]]]></description>
			<content:encoded><![CDATA[<p>Spammers commit their lives to ridding the world of overpriced pharma$euticals, embarrassing bedroom s!tuations, and wasted years spent &#8220;earning&#8221; a diplom@. Who can calculate the uncollected overseas lottery winnings, or untold stories of exiled Nigerian royalty the world would suffer without their unwavering dedication?</p>
<p>It&#8217;s time that we recognize the true genius behind a well-crafted piece of spam. In support of this worthy cause, we have created <a href="http://spamlets.com">spamlets™</a>, a place where the world can bring the poetry of unrequested badgering to light. Do your part, donate a <a href="http://spamlets.com">spamlet</a> today.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=SRTMaKYp1NU:XBaZl3W3yvw:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=SRTMaKYp1NU:XBaZl3W3yvw:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=SRTMaKYp1NU:XBaZl3W3yvw:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=SRTMaKYp1NU:XBaZl3W3yvw:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=SRTMaKYp1NU:XBaZl3W3yvw:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=SRTMaKYp1NU:XBaZl3W3yvw:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=SRTMaKYp1NU:XBaZl3W3yvw:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=SRTMaKYp1NU:XBaZl3W3yvw:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=SRTMaKYp1NU:XBaZl3W3yvw:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=SRTMaKYp1NU:XBaZl3W3yvw:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/SRTMaKYp1NU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2008/06/23/recognizing-the-unsung-heroes-of-spam/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2008/06/23/recognizing-the-unsung-heroes-of-spam/</feedburner:origLink></item>
		<item>
		<title>Never Get Rickrolled Again</title>
		<link>http://feedproxy.google.com/~r/SubstanceLabs/~3/mIp1QFbimrQ/</link>
		<comments>http://labs.findsubstance.com/2008/06/02/never-get-rickrolled-again/#comments</comments>
		<pubDate>Mon, 02 Jun 2008 17:01:41 +0000</pubDate>
		<dc:creator>Shaun Tinney</dc:creator>
				<category><![CDATA[Experiments]]></category>

		<guid isPermaLink="false">http://labs.findsubstance.com/2008/06/02/never-get-rickrolled-again/</guid>
		<description><![CDATA[We at Substance pride ourselves on constant innovation that has an immediate effect on society as a whole. Fortunately for society, we have focused our efforts on something that will truly change the way you surf the intertubes. With our patented, new, and simultaneously improved RickProof™ Rickroll prevention engine, one need never experience the embarrassment [...]]]></description>
			<content:encoded><![CDATA[<p>We at <a href="http://findsubstance.com">Substance</a> pride ourselves on constant innovation that has an immediate effect on society as a whole. Fortunately for society, we have focused our efforts on something that will truly <strong>change the way you surf the intertubes</strong>. With our patented, new, and simultaneously improved <a href="http://rickproof.com">RickProof™ Rickroll prevention engine</a>, one need never experience the embarrassment of being Rickrolled again. </p>
<p>Just enter any suspect web address into our sniffer at <a href="http://rickproof.com">RickProof.com</a>, and our RickBot™ will assess the risk of a Rickroll. No need to thanks us, we don&#8217;t do this for the fame, we do it for the people.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=mIp1QFbimrQ:OXCmm2BDIJ0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=mIp1QFbimrQ:OXCmm2BDIJ0:D7DqB2pKExk"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=mIp1QFbimrQ:OXCmm2BDIJ0:D7DqB2pKExk" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=mIp1QFbimrQ:OXCmm2BDIJ0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=mIp1QFbimrQ:OXCmm2BDIJ0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=mIp1QFbimrQ:OXCmm2BDIJ0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=mIp1QFbimrQ:OXCmm2BDIJ0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=mIp1QFbimrQ:OXCmm2BDIJ0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/SubstanceLabs?a=mIp1QFbimrQ:OXCmm2BDIJ0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/SubstanceLabs?i=mIp1QFbimrQ:OXCmm2BDIJ0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/SubstanceLabs/~4/mIp1QFbimrQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://labs.findsubstance.com/2008/06/02/never-get-rickrolled-again/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		<feedburner:origLink>http://labs.findsubstance.com/2008/06/02/never-get-rickrolled-again/</feedburner:origLink></item>
	</channel>
</rss><!-- Dynamic page generated in 1.498 seconds. --><!-- Cached page generated by WP-Super-Cache on 2010-03-08 17:23:19 --><!-- Compression = gzip -->
