<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	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/"
	>

<channel>
	<title>Saturnboy &#187; flex</title>
	<atom:link href="http://saturnboy.com/tag/flex/feed/" rel="self" type="application/rss+xml" />
	<link>http://saturnboy.com</link>
	<description>Code, Work, and Life</description>
	<lastBuildDate>Thu, 01 Mar 2012 22:35:28 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Interactive Visualization with Axiis</title>
		<link>http://saturnboy.com/2009/11/interactive-visualization-with-axiis/</link>
		<comments>http://saturnboy.com/2009/11/interactive-visualization-with-axiis/#comments</comments>
		<pubDate>Wed, 04 Nov 2009 21:34:39 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[axiis]]></category>
		<category><![CDATA[data viz]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=785</guid>
		<description><![CDATA[Continuing my Quest for Cool, one of my favorite aspects of data visualization is user interaction. Interactive visualizations are not only cool, but they can be extremely useful getting information to the user. Here is a screenshot from Google Analytics showing the main line chart of visitors: When you rollover one of the points, you [...]]]></description>
			<content:encoded><![CDATA[<p>Continuing my <a href="http://saturnboy.com/2009/10/axiis-quest-for-cool/">Quest for Cool</a>, one of my favorite aspects of data visualization is user interaction.  Interactive visualizations are not only cool, but they can be extremely useful getting information to the user.</p>
<p>Here is a screenshot from <a href="http://www.google.com/analytics/">Google Analytics</a> showing the main line chart of visitors:</p>
<div class="span-14 last" style="min-height:164px;">
<img src="http://saturnboy.com/wp-content/uploads/2009/11/google-analytics-rollover.png" alt="google-analytics" title="google-analytics" width="364" height="144" /></div>
<p>When you rollover one of the points, you get a popup telling you the exact number of visitors on that date.  This simple rollover, while cool, is not particularly useful to me.  If I wanted to know exact numbers, I&#8217;d look at an Excel printout.  Thankfully, we can use <a href="http://www.axiis.org/">Axiis</a> to provide something much better.</p>
<h5>Column Stack Chart</h5>
<p class="bottom">I&#8217;ll use Axiis to show two different visualization options for the same data.  I made some artificial visitor data per day.  Here it is as a vanilla line chart I grabbed from Excel:</p>
<div class="span-14 last" style="min-height:185px;">
<img src="http://saturnboy.com/wp-content/uploads/2009/11/line-chart-data.png" alt="data" title="data" width="494" height="165" /></div>
<p class="bottom">Not very exciting, but the classic weekend lulls make our dataset a little hard to follow.  In XML, it looks like this:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;visitors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;week</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;A&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Sun&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;0.2&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Mon&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;1.6&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Tue&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;2.0&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Wed&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;2.4&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Thu&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;1.8&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Fri&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;1.6&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Sat&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;0.4&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/week<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;week</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;B&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Sun&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;0.3&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Mon&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;1.2&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;day</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;Tue&quot;</span> <span style="color: #000066;">val</span>=<span style="color: #ff0000;">&quot;1.8&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
        ...
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/week<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    ...
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/visitors<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p class="bottom">Since the data per day is a little annoying, let&#8217;s try to smooth it out by collecting up the day data into weeks.  This is easy to do in Axiis by using the <code>ColumnStack</code> layout.  Recall that <code>Layout</code>s in Axiis specify how incoming data will be rendered to the display.  Here&#8217;s an abbreviated snippet of code showing the relevant parts:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:DataCanvas</span> id=<span style="color: #ff0000;">&quot;dc&quot;</span> ...<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:HBoxLayout</span> id=<span style="color: #ff0000;">&quot;myLayout&quot;</span> ...<span style="color: #7400FF;">&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:ColumnStack</span> id=<span style="color: #ff0000;">&quot;myStack&quot;</span> ...</span>
<span style="color: #000000;">                    dataProvider=<span style="color: #ff0000;">&quot;{myLayout.currentDatum.day}&quot;</span></span>
<span style="color: #000000;">                    dataField=<span style="color: #ff0000;">&quot;val&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:drawingGeometries</span> ... <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:HBoxLayout</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:DataCanvas</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>First, we use an <code>HBoxLayout</code> layout to render our weeks into columns (the <code>dataProvider</code> is the <code>visitors.week</code> array), and inside that we use a <code>ColumnStack</code> layout to render our days stacked one on top of another (the <code>dataProvider</code> is the current week&#8217;s <code>day</code> array).</p>
<p class="bottom">Here is the result (view source enabled):</p>
<div id="flashcontent-axiis-column-stack">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p></p>
<p>The column stack chart is nice because it enables us to distinguish the macro trend over the weeks, traffic is obviously dying off from week A to week H.  But it does a poor job illuminating intra-week data.  For example, it&#8217;s hard to tell how Monday of week A compares to Monday of week B.</p>
<h5>Interactive Column-in-Column Chart</h5>
<p>Another option to visualize our simulated visitor data is empower the user.  Start with a super simple column chart of the aggregated week data, and allow the user to drill down into the day data via some interaction.  The implementation I&#8217;ve chosen below uses an inset column chart to show the day data when the user mouses over a week column.</p>
<p class="bottom">In order to display week data, we first need to pre-process our day data to aggregate it into weeks.  Axiis makes this trivial with <code>DataSet</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">var</span> ds:DataSet = <span style="color: #000000; font-weight: bold;">new</span> DataSet<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
ds.<span style="color: #006600;">processXmlString</span><span style="color: #66cc66;">&#40;</span>myXML.<span style="color: #006600;">toXMLString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
ds.<span style="color: #006600;">aggregateData</span><span style="color: #66cc66;">&#40;</span>ds.<span style="color: #0066CC;">data</span>.<span style="color: #0066CC;">object</span>.<span style="color: #006600;">visitors</span>, <span style="color: #ff0000;">&quot;week.day&quot;</span>, <span style="color: #66cc66;">&#91;</span><span style="color: #ff0000;">&quot;val&quot;</span><span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#41;</span>;</pre></div></div>

<p>The <code>aggregateDate()</code> method walks our XML hierarchy and rolls up aggregates of <code>day.val</code> at every level.  When processing is complete, <code>visitors</code> has a new <code>aggregates</code> object that contains <code>day_val_sum</code> (and min, max, and average) for all the days in the entire data set.  And one level down, <code>week</code> also has a new <code>aggregates</code> object that contains <code>day_val_sum</code> for just the days in that week.</p>
<p class="bottom">Next, we construct our visualization using a pair of <code>DataCanvas</code> objects and a pair of <code>BaseLayout</code> layouts, one for the main column chart showing aggregated week data, and the other for an inset column chart showing just the current week&#8217;s day data.  Here I&#8217;m using the same column-chart-the-long-way code as I used <a href="http://saturnboy.com/2009/10/axiis-quest-for-cool/">last post</a>.</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:DataCanvas</span> id=<span style="color: #ff0000;">&quot;dc&quot;</span> ...<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:BaseLayout</span> id=<span style="color: #ff0000;">&quot;myLayout&quot;</span> ...</span>
<span style="color: #000000;">            itemMouseOver=<span style="color: #ff0000;">&quot;mouseOverHandler(event)&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:drawingGeometries</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RegularRectangle</span> id=<span style="color: #ff0000;">&quot;myBar&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RasterText</span> id=<span style="color: #ff0000;">&quot;myBarLabel&quot;</span>... <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:drawingGeometries</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:referenceRepeater</span> ... <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:states</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:State</span></span>
<span style="color: #000000;">                    enterStateEvent=<span style="color: #ff0000;">&quot;mouseOver&quot;</span></span>
<span style="color: #000000;">                    exitStateEvent=<span style="color: #ff0000;">&quot;mouseOut&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:BaseLayout</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:DataCanvas</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:DataCanvas</span> id=<span style="color: #ff0000;">&quot;dc2&quot;</span> ...<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:BaseLayout</span> id=<span style="color: #ff0000;">&quot;myLayout2&quot;</span> ...<span style="color: #7400FF;">&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:drawingGeometries</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RegularRectangle</span> ... <span style="color: #7400FF;">/&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RasterText</span> ... <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:drawingGeometries</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:referenceRepeater</span> ... <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:BaseLayout</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:DataCanvas</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The interaction is achieved by the <code>itemMouseOver</code> event on the main column chart&#8217;s layout.  Note that we are <b>not</b> listening for events on the columns themselves, rather we listen on the parent <code>BaseLayout</code>.  The layout is responsible for attaching individual listeners to all of its children as they are rendered to the display.  Layouts have events for all possible mouse interactions, including click, double-click, mouse over, mouse out, etc.  This is one of the nicest features of Axiis.  Since user interaction is managed by the layout and not by the rendered geometry, I change whatever I want about the geometry or how it is rendered and user interactions are preserved.  The code is also pleasantly clean.</p>
<p>What&#8217;s more, the main column chart uses an Axiis <code>State</code> to create a visual rollover effect on the columns.  The <code>State</code> is used to trigger some visual changes (column stroke weight is increased and label font is bolded) on <code>mouseOver</code> and then reverts the changes on <code>mouseOut</code>.</p>
<p class="bottom">Here is the event handler attached to the <code>itemMouseOver</code> event on the layout:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> mouseOverHandler<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:LayoutItemEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #808080; font-style: italic;">//change dataset to current mouseOver'd column</span>
    myLayout2.<span style="color: #006600;">dataProvider</span> = <span style="color: #0066CC;">e</span>.<span style="color: #006600;">item</span>.<span style="color: #0066CC;">data</span>.<span style="color: #006600;">day</span>;
&nbsp;
    <span style="color: #808080; font-style: italic;">//set color</span>
    <span style="color: #000000; font-weight: bold;">var</span> <span style="color: #0066CC;">color</span>:uint = myPalette.<span style="color: #006600;">colors</span><span style="color: #66cc66;">&#91;</span><span style="color: #0066CC;">e</span>.<span style="color: #006600;">item</span>.<span style="color: #0066CC;">index</span><span style="color: #66cc66;">&#93;</span>;
    myPalette2.<span style="color: #006600;">colorFrom</span> = <span style="color: #0066CC;">color</span>;
    myPalette2.<span style="color: #006600;">colorTo</span> = PaletteUtils.<span style="color: #006600;">darker</span><span style="color: #66cc66;">&#40;</span>PaletteUtils.<span style="color: #006600;">darker</span><span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">color</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
    <span style="color: #808080; font-style: italic;">//hide text</span>
    insetText.<span style="color: #0066CC;">visible</span> = <span style="color: #000000; font-weight: bold;">false</span>;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The <code>LayoutItemEvent</code> event contains all kinds of useful information when it arrives at our handler.  First, we set the <code>dataProvider</code> of our inset chart using the day data from the highlighted week column.  Next, we use some <a href="http://www.degrafa.org/">Degrafa</a> color magic to set the colors of the inset&#8217;s columns from the color of the highlighted week column.  And finally, we hide the reminder text.</p>
<p class="bottom">Here is the result (view source enabled):</p>
<div id="flashcontent-axiis-column-in-column">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p></p>
<p>The end result is a fairly cool visualization that does a good job initially hiding unnecessary information, but later reveals it upon user interaction.  For example, toggle back and forth between week B and week C.  You can easily see a shift in traffic to the first half of week C compared to week B.</p>
<h5>Postscript</h5>
<p>I recently discovered another amazing data visualization framework.  <a href="http://vis.stanford.edu/protovis/">Protovis</a> is an awesome Javascript library created by some <a href="http://vis.stanford.edu/">hella smart dudes</a> at Stanford.  If I ever needed to do any visualizations on the web, and was banned from using Flex, I&#8217;d definitely use Protovis.</p>
<h5 style="padding-top:10px;">Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/axiis/axiis_column_stack/axiis_column_stack.html">AxiisColumnStack</a> (<a href="http://saturnboy.com/proj/axiis/axiis_column_stack/srcview/axiis_column_stack.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/axiis/axiis_column_in_column/axiis_column_in_column.html">AxiisColumnInColumn</a> (<a href="http://saturnboy.com/proj/axiis/axiis_column_in_column/srcview/axiis_column_in_column.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/axiis/axiis_column_stack/axiis_column_stack.swf', 'flashcontent-axiis-column-stack', '440', '230', '9.0.28', 'playerProductInstall.swf', false, { bgColor:'#dddddd', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/axiis/axiis_column_in_column/axiis_column_in_column.swf', 'flashcontent-axiis-column-in-column', '440', '230', '9.0.28', 'playerProductInstall.swf', false, { bgColor:'#dddddd', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/11/interactive-visualization-with-axiis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Axiis and the Quest for Cool</title>
		<link>http://saturnboy.com/2009/10/axiis-quest-for-cool/</link>
		<comments>http://saturnboy.com/2009/10/axiis-quest-for-cool/#comments</comments>
		<pubDate>Tue, 27 Oct 2009 05:50:32 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[axiis]]></category>
		<category><![CDATA[data viz]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=748</guid>
		<description><![CDATA[Axiis is an advanced data visualization framework built on top of Degrafa. And when I say advanced, I mean really advanced. I found my way to Axiis because I wanted the maximum amount of visual control that I could get. Axiis is designed to support any kind of visualization you could possibly imagine, but I [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.axiis.org/">Axiis</a> is an advanced data visualization framework built on top of <a href="http://www.degrafa.org/">Degrafa</a>. And when I say advanced, I mean <a href="http://www.flexjunk.com/examples/SmithChartExample/SmithChartExample.html">really advanced</a>.  I found my way to Axiis because I wanted the maximum amount of visual control that I could get.  Axiis is designed to support any kind of visualization you could possibly imagine, but I don&#8217;t really care about that part of the framework.  Instead, I just want to take your average boring graph and make it way cool.</p>
<p>Lately, I&#8217;ve been working on a project at <a href="http://www.gorillalogic.com/">work</a> that places a real premium on cool.  This post has nothing to do with that project, of course.  It&#8217;s all about the quest for cool and my personal journey with Axiis.</p>
<h5>Simple Ass Column Chart</h5>
<p>In the beginning, I had a simple data set and just wanted create a basic column chart.  I tried to follow the <a href="http://www.insideria.com/2009/07/axiis---an-introduction-and-tu.html">Intro and Tutorial</a>, but I must admit I got a little lost the first time through.  Hopefully, this will be an even easier introduction to the Axiis framework.</p>
<p class="bottom">Here is our data in MXML:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:XML</span> id=<span style="color: #ff0000;">&quot;myXML&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;columns<span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;A&quot;</span> val=<span style="color: #ff0000;">&quot;10&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;B&quot;</span> val=<span style="color: #ff0000;">&quot;9&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;C&quot;</span> val=<span style="color: #ff0000;">&quot;7&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;D&quot;</span> val=<span style="color: #ff0000;">&quot;5.5&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;E&quot;</span> val=<span style="color: #ff0000;">&quot;6&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;F&quot;</span> val=<span style="color: #ff0000;">&quot;3&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;G&quot;</span> val=<span style="color: #ff0000;">&quot;4&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;col label=<span style="color: #ff0000;">&quot;H&quot;</span> val=<span style="color: #ff0000;">&quot;2.5&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;">&lt;/columns<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:XML</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>We want to render this data to the screen as a bunch of columns (aka <code>RegularRectangle</code>s).  So, the next thing that we need to do is process our data and feed it into an Axiis <code>Layout</code>.  A <code>Layout</code> is the main element in any Axiis chart; it takes incoming data and renders it to the display.</p>
<p class="bottom">Here we process our data and set our <code>Layout</code>&#8216;s <code>dataProvider</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> complete<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">var</span> ds:DataSet = <span style="color: #000000; font-weight: bold;">new</span> DataSet<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    ds.<span style="color: #006600;">processXmlString</span><span style="color: #66cc66;">&#40;</span>myXML.<span style="color: #006600;">toXMLString</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
    myLayout.<span style="color: #006600;">dataProvider</span> = ds.<span style="color: #0066CC;">data</span>.<span style="color: #0066CC;">object</span>.<span style="color: #006600;">columns</span>.<span style="color: #006600;">col</span>;
    dc.<span style="color: #006600;">invalidateDisplayList</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p class="bottom">And here is the basic shell of our entire application:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span> ...<span style="color: #7400FF;">&gt;</span></span>
    ...
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:LinearScale</span> id=<span style="color: #ff0000;">&quot;vScale&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:DataCanvas</span> id=<span style="color: #ff0000;">&quot;dc&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:BaseLayout</span> id=<span style="color: #ff0000;">&quot;myLayout&quot;</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:drawingGeometries</span><span style="color: #7400FF;">&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RegularRectangle</span> id=<span style="color: #ff0000;">&quot;myBar&quot;</span>... <span style="color: #7400FF;">/&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RasterText</span> id=<span style="color: #ff0000;">&quot;myBarLabel&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:drawingGeometries</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:referenceRepeater</span><span style="color: #7400FF;">&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:GeometryRepeater</span><span style="color: #7400FF;">&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:geometry</span><span style="color: #7400FF;">&gt;</span></span>
                            <span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:RegularRectangle</span> ... <span style="color: #7400FF;">/&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:geometry</span><span style="color: #7400FF;">&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:modifiers</span><span style="color: #7400FF;">&gt;</span></span>
                            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:PropertyModifier</span> ... <span style="color: #7400FF;">/&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:modifiers</span><span style="color: #7400FF;">&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:GeometryRepeater</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:referenceRepeater</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:BaseLayout</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:layouts</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:backgroundGeometries</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:VAxis</span> ... <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:backgroundGeometries</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:DataCanvas</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom">Stepping through the code element by element, we see:</p>
<ol>
<li><b>LinearScale</b> &#8211;  We use a <code>LinearScale</code> to convert from data values to screen values (aka pixels).  So a data value of 5.5 might translate into 11 pixels, 42 pixels, or 55 pixels depending on the scale.</li>
<li><b>DataCanvas</b> &#8211; The <code>DataCanvas</code> contains all Axiis graph elements.  This is analogous to Flex 4&#8242;s <code>Graphic</code> container for FXG elements, and Degrafa&#8217;s <code>Surface</code> container for drawing elements.</li>
<li><b>Layout</b> &#8211; <code>BaseLayout</code> is the parent of all layouts and the most flexible.</li>
<li><b>drawingGeometries</b> &#8211; We draw each column as a <code>RegularRectangle</code> and each label as a <code>RasterText</code>.  Positioning and sizing is guided by the reference geometry created by the <code>referenceRepeater</code>.  Column height is computed using the current value of the data from the <code>Layout</code> converted to screen coordinates by the <code>LinearScale</code>.</li>
<li><b>referenceRepeater</b> &#8211; The reference geometry and repeated property combine to <i>create</i> a visualization for the data.  So, repeating rectangles horizontally gives a column chart, repeating rectangles vertically gives a bar chart, repeating line segments horizontally given a line chart, etc.</li>
<li><b>VAxis</b> &#8211; Draw a vertical axis underneath our graph layer by using the <code>backgroundGeometries</code> layer of the <code>DataCanvas</code>.  I like to use a negative x value to shift the axis left to get it out from underneath the chart (and compensate by shifting the entire <code>DataCanvas</code> right with a positive x value).</li>
</ol>
<p>That&#8217;s it for the high-level stuff, the dirty little details are in the code.  A little trial-and-error went a long way to teach me what the hell each of the various parameters actually did.  The <a href="http://www.insideria.com/2009/07/axiis---an-introduction-and-tu.html">Intro and Tutorial</a> article does a good job covering some of the details and tricks like the vertical flip trick, and I also recommend <a href="http://www.twgonzalez.com/blog/?p=267">Tom&#8217;s session</a> from AdobeMAX.</p>
<h5>User Interaction Coolness</h5>
<p>Last, we&#8217;ll add a little dash of coolness to our application with a simple rollover effect on our columns.  Using an Axiis <code>State</code>, we modify a few properties of our <code>drawingGeometries</code> on the <code>mouseOver</code> event to create a rollover effect.</p>
<p class="bottom">The <code>State</code> code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:BaseLayout</span> id=<span style="color: #ff0000;">&quot;myLayout&quot;</span> ...<span style="color: #7400FF;">&gt;</span></span>
    ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:State</span> enterStateEvent=<span style="color: #ff0000;">&quot;mouseOver&quot;</span></span>
<span style="color: #000000;">                exitStateEvent=<span style="color: #ff0000;">&quot;mouseOut&quot;</span></span>
<span style="color: #000000;">                targets=<span style="color: #ff0000;">&quot;{[barFill,barStroke,myBarLabel]}&quot;</span></span>
<span style="color: #000000;">                properties=<span style="color: #ff0000;">&quot;{['alpha','weight','fontWeight']}&quot;</span></span>
<span style="color: #000000;">                values=<span style="color: #ff0000;">&quot;{[1,2,'bold']}&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:states</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/axiis:BaseLayout</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<h5>Cool Colors</h5>
<p>Using Degrafa geometry to build our chart gives us total control of the shape and design, but if we really want something cool, we need to use color.  For our column chart, we&#8217;ll use an Axiis <code>LayoutAutoPalette</code> element to create a smooth color gradient for each bar.</p>
<p class="bottom">Here is the code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;axiis:LayoutAutoPalette</span> id=<span style="color: #ff0000;">&quot;myPalette&quot;</span> layout=<span style="color: #ff0000;">&quot;{myLayout}&quot;</span></span>
<span style="color: #000000;">        colorFrom=<span style="color: #ff0000;">&quot;0xFF99FF&quot;</span></span>
<span style="color: #000000;">        colorTo=<span style="color: #ff0000;">&quot;0x6699FF&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;degrafa:SolidFill</span> id=<span style="color: #ff0000;">&quot;barFill&quot;</span> color=<span style="color: #ff0000;">&quot;{myPalette.currentColor}&quot;</span> <span style="color: #7400FF;">/&gt;</span></span></pre></div></div>

<p>The <code>LayoutAutoPalette</code> interpolates from a starting color to an ending color for each data value in the <code>Layout</code>.  We then feed the palette&#8217;s current color into a standard Degrafa <code>SolidFill</code>.  Lastly, the fill is applied to the <code>RegularRectangle</code> in the <code>drawingGeometries</code> section of our <code>Layout</code> to create a pretty gradient of bars from left to right.  Note that color is <i>not</i> proportional to the data value, but Axiis certainly provides the functionality to make a column chart with bars colored by height.</p>
<h5>The Result</h5>
<p class="bottom">Here it is, rollover effect and all (view source enabled):</p>
<div id="flashcontent-axiis-simple-column">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5 style="padding-top:10px;">Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/axiis/axiis_simple_column/axiis_simple_column.html">AxiisSimpleColumn</a> (<a href="http://saturnboy.com/proj/axiis/axiis_simple_column/srcview/axiis_simple_column.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/axiis/axiis_simple_column/axiis_simple_column.swf', 'flashcontent-axiis-simple-column', '440', '230', '9.0.28', 'playerProductInstall.swf', false, { bgColor:'#dddddd', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/10/axiis-quest-for-cool/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>SVG Primer for Flex</title>
		<link>http://saturnboy.com/2009/06/svg-primer-for-flex/</link>
		<comments>http://saturnboy.com/2009/06/svg-primer-for-flex/#comments</comments>
		<pubDate>Thu, 11 Jun 2009 04:30:46 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[fxg]]></category>
		<category><![CDATA[svg]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=551</guid>
		<description><![CDATA[The dream of SVG was probably born sometime in the late 90&#8242;s. Version 1.0 arrived in 2001, followed by the current version, SVG 1.1, in 2003. For anyone keeping score at home, that&#8217;s over 6 years ago, which is like 120 years ago in internet dog years. Also for those at home, SVG is a [...]]]></description>
			<content:encoded><![CDATA[<p>The dream of SVG was probably born sometime in the late 90&#8242;s.  Version 1.0 arrived in 2001, followed by the <i>current</i> version, <a href="http://www.w3.org/TR/SVG/">SVG 1.1</a>, in 2003.  For anyone keeping score at home, that&#8217;s over 6 years ago, which is like 120 years ago in internet dog years.  Also for those at home, SVG is a portable XML-based vector graphics format (it also does raster graphics), but you&#8217;d probably not be reading this if you didn&#8217;t already know.</p>
<p>Nowadays, I&#8217;m finally seeing some SVG in use.  It works natively in all the real browsers (obviously not IE, which requires a plugin), and even on some mobile devices.  But most importantly to me, I see it in my day-to-day work in <a href="http://www.degrafa.org/">Degrafa</a>, and with the beta release of Flex 4, in <a href="http://labs.adobe.com/technologies/flashcatalyst/">Catalyst</a> and <a href="http://opensource.adobe.com/wiki/display/flexsdk/FXG+1.0+Specification">FXG</a>.</p>
<p>The vast majority of my experience in SVG is with paths (<a href="http://www.w3.org/TR/SVG/paths.html">SVG Spec, &sect; 8</a>) and to a lesser extent Transforms (<a href="http://www.w3.org/TR/SVG/coords.html">&sect; 7</a>) and Filters (<a href="http://www.w3.org/TR/SVG/filters.html">&sect; 15</a>).  Thankfully, these are some of the most useful and important pieces of SVG, and they all have nice one-to-one mappings to components in Degrafa and FXG.</p>
<h5>SVG Path Primer</h5>
<p>In SVG, a <b>path</b> is the outline of some object.  It is described as a series of segments, where each segment can be different, either a line, curve, or arc.  Path data is most often given in shorthand syntax as a series of commands followed by coordinates (we&#8217;ll ignore the long form for now).  Let&#8217;s illuminate the discussion with some examples.</p>
<p class="bottom"><b>SVG</b>:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;?xml</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.0&quot;</span> <span style="color: #000066;">standalone</span>=<span style="color: #ff0000;">&quot;no&quot;</span><span style="color: #000000; font-weight: bold;">?&gt;</span></span>
<span style="color: #00bbdd;">&lt;!DOCTYPE svg PUBLIC &quot;-//W3C//DTD SVG 1.1//EN&quot;</span>
<span style="color: #00bbdd;">    &quot;http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd&quot;&gt;</span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;svg</span> <span style="color: #000066;">xmlns</span>=<span style="color: #ff0000;">&quot;http://www.w3.org/2000/svg&quot;</span> <span style="color: #000066;">version</span>=<span style="color: #ff0000;">&quot;1.1&quot;</span></span>
<span style="color: #009900;">    <span style="color: #000066;">width</span>=<span style="color: #ff0000;">&quot;200&quot;</span> <span style="color: #000066;">height</span>=<span style="color: #ff0000;">&quot;200&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;path</span> <span style="color: #000066;">d</span>=<span style="color: #ff0000;">&quot;M 0,0 L 100,0 L 100,100 L 0,100 z&quot;</span></span>
<span style="color: #009900;">      <span style="color: #000066;">fill</span>=<span style="color: #ff0000;">&quot;#EECCEE&quot;</span></span>
<span style="color: #009900;">      <span style="color: #000066;">stroke</span>=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span></span>
<span style="color: #009900;">      <span style="color: #000066;">stroke-width</span>=<span style="color: #ff0000;">&quot;3&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/svg<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p class="bottom"><b>Degrafa</b> in Flex 3:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span></span>
<span style="color: #000000;">        xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        xmlns:Degrafa=<span style="color: #ff0000;">&quot;http://www.degrafa.com/2007&quot;</span></span>
<span style="color: #000000;">        layout=<span style="color: #ff0000;">&quot;absolute&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:GeometryComposition</span> graphicsTarget=<span style="color: #ff0000;">&quot;{[cnv]}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:Path</span> data=<span style="color: #ff0000;">&quot;M 0,0 L 100,0 L 100,100 L 0,100 z&quot;</span><span style="color: #7400FF;">&gt;</span></span>
	        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
	            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidFill</span> color=<span style="color: #ff0000;">&quot;#EECCEE&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
	        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
	        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
	            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;3&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
	        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:Path</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:GeometryComposition</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> id=<span style="color: #ff0000;">&quot;cnv&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom"><b>MXML Graphics</b> (aka FXG) in Flex 4:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Application</span></span>
<span style="color: #000000;">        xmlns:fx=<span style="color: #ff0000;">&quot;http://ns.adobe.com/mxml/2009&quot;</span></span>
<span style="color: #000000;">        xmlns:s=<span style="color: #ff0000;">&quot;library://ns.adobe.com/flex/spark&quot;</span></span>
<span style="color: #000000;">        xmlns:mx=<span style="color: #ff0000;">&quot;library://ns.adobe.com/flex/halo&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Graphic</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Path</span> data=<span style="color: #ff0000;">&quot;M 0,0 L 100,0 L 100,100 L 0,100 z&quot;</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:fill</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:SolidColor</span> color=<span style="color: #ff0000;">&quot;#EECCEE&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:fill</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:stroke</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:SolidColorStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;3&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:stroke</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Path</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Graphic</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The examples above use the shorthand path syntax to draw a 100px square that starts at the coordinate origin (0,0), which is the upper left corner in SVG and Flex.  Beware the coordinate origin when translating <a href="http://saturnboy.com/2009/06/inkscape-svg-degrafa-path/">Inkscape SVG to Flex</a>. The other interesting thing to note is the amazing similarity between Degrafa and FXG.  Who knew all my time learning Degrafa will instantly translate to Flex 4 and FXG?  Awesome!</p>
<h5>SVG Path Shorthand</h5>
<p class="bottom">Here&#8217;s a quick overview of shorthand syntax for SVG path data:</p>
<hr class="bottom" style="height: 3px;" />
<div class="span-3"><b>Move</b></div>
<div class="span-4"><b>M</b> &lt;x,y&gt;</div>
<div class="span-6 last">Move the pen to the given point.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Line</b></div>
<div class="span-4"><b>L</b> &lt;x,y&gt;+</div>
<div class="span-6 last">Draw a line to given point.  Multiple points may be specified to draw polyline.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Horizontal Line</b></div>
<div class="span-4"><b>H</b> &lt;x&gt;</div>
<div class="span-6 last">Draw a horizontal line to given coordinate.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Vertical Line</b></div>
<div class="span-4"><b>V</b> &lt;y&gt;</div>
<div class="span-6 last">Draw a vertical line to given coordinate.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Quadratic Bezier</b></div>
<div class="span-4"><b>Q</b> &lt;cx,cy x,y&gt;+</div>
<div class="span-6 last">Draw a quadratic Bezier curve to given coordinate using a control point.  Multiple Beziers may be specified to draw polycurve.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Cubic Bezier</b></div>
<div class="span-4"><b>C</b> &lt;cx1,cy1 cx2,cy2 x,y&gt;+</div>
<div class="span-6 last">Draw a cubic Bezier curve to given coordinate using two control points.  Multiple Beziers may be specified to draw a polycurve.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Arc</b></div>
<div class="span-4"><b>A</b> &lt;rx,ry rot,lrg,swp x,y&gt;</div>
<div class="span-6 last">Draw elliptical arc to the given point.</div>
<hr style="background-color:#aaa;" class="bottom" />
<div class="span-3"><b>Close</b></div>
<div class="span-4"><b>Z</b></div>
<div class="span-6 last">Close the path.</div>
<hr style="height: 3px;" />
<p>Alas, the beta version of FXG does not support the Arc segment type, which I suspect is due to lack of support for arbitrary arcs in the underlying Flash Player rendering engine but I don&#8217;t know for sure.  Thankfully, Degrafa offers full arc support (<i>thanks Greg!</i>).  If you really need to draw arcs in FXG, for stuff like pie wedges, and are unafraid of getting into a cage match with your trigonometry textbook, you can do a good job approximating arcs with cubic Bezier curves.  Alternately, you can just use Degrafa once it gets ported to Flex 4.  Lastly, using uppercase for the segment type specifies absolute coordinates.  This is the format commonly used by Illustrator and <a href="http://www.inkscape.org/">Inkscape</a> when exporting drawings to SVG.  One can easily switch to relative coordinates by just switching the commands to lowercase, but I would try to avoid it if at all possible as it tends to make one&#8217;s head hurt.</p>
<h5>The Many Shapes of a Square</h5>
<p class="bottom">All of the squares above, use this shorthand data:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">M 0,0 L 100,0 L 100,100 L 0,100 z</pre></div></div>

<p>First, a <b>M</b>ove to set the pen at the origin.  Then, a <b>L</b>ine right to (100,0), followed by a <b>L</b>ine down to (100,100), followed by a <b>L</b>ine left to (0,100).  Then, a close (<b>z</b>) to return to the origin.</p>
<p class="bottom">I can drop the commas if I want:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">M 0 0 L 100 0 L 100 100 L 0 100 z</pre></div></div>

<p class="bottom">Or drop all but the first <b>L</b>ine to make a polyline:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">M 0,0 L 100,0 100,100 0,100 z</pre></div></div>

<p class="bottom">Or use <b>H</b>orizontal Line and <b>V</b>ertical Line:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">M 0,0 H 100 V 100 H 0 z</pre></div></div>

<p class="bottom">Or even use relative coordinate (which makes my head hurt a little):</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">m 0,0 l 100,0 l 0,100 l -100,0 z</pre></div></div>

<h5>Curves</h5>
<p class="bottom">Straight lines are cool, but the real fun in life lies in the curves.  Cubic Bezier curves should be very familiar to anyone who&#8217;s used a vector drawing program.  Let&#8217;s replace the first segment in our square with a cubic Bezier segment.  Now, the SVG shorthand becomes:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">M 0,0 C 25,-25 50,25 100,0 L 100,100 L 0,100 z</pre></div></div>

<p class="bottom">When rendered, we get this:</p>
<div class="span-14 top bottom last" style="min-height:325px;">
<img src="http://saturnboy.com/wp-content/uploads/2009/06/square-funny.png" alt="square-funny" title="square-funny" width="408" height="315" />
</div>
<p>The shorthand command says curve to (100,0), but start out heading towards control point #1 at (25,-25) and end up coming in from control point #2 at (50,25).  </p>
<h5>Arcs</h5>
<p class="bottom">Again, let&#8217;s replace the first segment in our square with an arc segment.  Now, the SVG shorthand becomes:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;">M 0,0 A 50,25 0 0,1 100,0 L 100,100 L 0,100 z</pre></div></div>

<p class="bottom">When rendered, we get this:</p>
<div class="span-14 top bottom last" style="min-height:325px;">
<img src="http://saturnboy.com/wp-content/uploads/2009/06/square-arc.png" alt="square-arc" title="square-arc" width="408" height="315" />
</div>
<p>The shorthand command says arc to (100,0), with an x-radius of 50 and a y-radius of 25, with a rotation of 0.  The large-arc and sweep flags are a little confusing so you&#8217;ll want to review the <a href="http://www.w3.org/TR/SVG11/paths.html#PathDataEllipticalArcCommands">SVG Spec, &sect; 8.3.8</a> if you need to get down and dirty with arcs.  </p>
<h5>Conclusion</h5>
<p>I&#8217;m a firm believer in &#8220;right tool for the job.&#8221;  So, when in comes to getting SVG path data into Flex, I&#8217;m definitely going to use Illustrator or Inkscape as much as possible, and in the future I might just use Catalyst for everything.  But there are a few important situations where the Flex developer absolutely must know SVG.  First, if you want to do any kind of path morphing (<a href="http://www.degrafa.org/blog/2009/06/say-hello-to-supershape2d/">like this</a>), you&#8217;ll need precision control over your path segments.   And second, if you want to do any dynamic path generation (like building a multi-level radial menu on the fly &ndash; which sounds like a good topic for a future post), you&#8217;ll need to manually construct your SVG paths.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/wp-content/uploads/2009/06/square-path.svg">square-path.svg</a></li>
<li><a href="http://saturnboy.com/wp-content/uploads/2009/06/square-curve.svg">square-curve.svg</a></li>
<li><a href="http://saturnboy.com/wp-content/uploads/2009/06/square-arc.svg">square-arc.svg</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/06/svg-primer-for-flex/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Inkscape SVG to Degrafa Path</title>
		<link>http://saturnboy.com/2009/06/inkscape-svg-degrafa-path/</link>
		<comments>http://saturnboy.com/2009/06/inkscape-svg-degrafa-path/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 03:44:44 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[inkscape]]></category>
		<category><![CDATA[svg]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=528</guid>
		<description><![CDATA[Going from SVG data to a Degrafa Path couldn&#8217;t be easier: just copy &#38; paste. You can watch this video tutorial or you can check out this demo. But there is one trick for Inkscape: even though the coordinate origin on the Inkscape document is the normal cartesian origin in the bottom left and the [...]]]></description>
			<content:encoded><![CDATA[<p>Going from <a href="http://www.w3.org/TR/SVG/">SVG</a> data to a <a href="http://www.degrafa.org/">Degrafa</a> <code>Path</code> couldn&#8217;t be easier: just copy &amp; paste.  You can watch <a href="http://www.vimeo.com/1223682">this video tutorial</a> or you can check out <a href="http://www.degrafa.org/source/Car/Car.html">this demo</a>.</p>
<p><b>But there is one trick for <a href="http://www.inkscape.org/">Inkscape</a></b>: even though the coordinate origin on the Inkscape document is the normal cartesian origin in the bottom left and the y-axis points up, the SVG output always uses the upper left corner of the document as the origin and the y-axis points down (per the <a href="http://www.w3.org/TR/SVG/coords.html#InitialCoordinateSystem">SVG Spec, &sect; 7.3</a>).</p>
<p class="bottom">To demonstrate, I created a new document in Inkscape, set my dimensions to 500 x 500, and placed a simple path (which happens to be a square) in the upper left corner:</p>
<div class="span-14 top bottom last" style="min-height:453px;">
<img src="http://saturnboy.com/wp-content/uploads/2009/06/square.png" alt="square" title="square" width="459" height="443" />
</div>
<p>You can see by the rulers in Inkscape that the square&#8217;s origin is at (0,500).</p>
<p class="bottom">If we save our square and examine the SVG output, we see:</p>

<div class="wp_syntax"><div class="code"><pre class="xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;svg</span> ...<span style="color: #000000; font-weight: bold;">&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;g</span> ...<span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;path</span> <span style="color: #000066;">d</span>=<span style="color: #ff0000;">&quot;M 0,0 L 100,0 L 100,100 L 0,100 L 0,0 z&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
  <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/g<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/svg<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>If we ignore everything in the file except the relevant path data, we can see the very first path command is <code>M 0,0</code> which is path-speak for move to (0,0).  This is exactly as expected from the SVG spec: upper left <b>is</b> the coordinate origin.  <b>The cartesian origin in Inkscape is bogus!</b></p>
<p class="bottom">Next, we can just copy the path data from the SVG file and paste it into the <code>data</code> attribute of a Degrafa <code>Path</code> component.</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:Path</span> data=<span style="color: #ff0000;">&quot;M 0,0 L 100,0 L 100,100 L 0,100 L 0,0 z&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidFill</span> color=<span style="color: #ff0000;">&quot;#EECCEE&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;3&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:Path</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Give it a fill color and a stroke color, and we get a <a href="http://saturnboy.com/proj/degrafa_svg/degrafa_square/degrafa_square.html">pretty purple square</a>.  Now I know my Degrafa <code>Path</code> component will have a square in the upper left, because I know my square was in the upper left in Inkscape.  Nice and easy.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/wp-content/uploads/2009/06/square.svg">square.svg</a></li>
<li><a href="http://saturnboy.com/proj/degrafa_svg/degrafa_square/degrafa_square.html">Square</a> (<a href="http://saturnboy.com/proj/degrafa_svg/degrafa_square/srcview/degrafa_square.zip">download</a>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/06/inkscape-svg-degrafa-path/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Degrafa Video Player, Part 2</title>
		<link>http://saturnboy.com/2009/06/degrafa-video-player-2/</link>
		<comments>http://saturnboy.com/2009/06/degrafa-video-player-2/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 10:00:57 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[inkscape]]></category>
		<category><![CDATA[open video player]]></category>
		<category><![CDATA[skinning]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=503</guid>
		<description><![CDATA[The plan is simple, take the nice Degrafa-skinned components from Part 1 and assemble them into a video player powered by the OvpNetStream class from the Open Video Player project. Design I knew right away that the design was not going to have any right angles, but I also didn&#8217;t want to go with rounded [...]]]></description>
			<content:encoded><![CDATA[<p>The plan is simple, take the nice <a href="http://www.degrafa.org/">Degrafa</a>-skinned components from <a href="http://saturnboy.com/2009/05/degrafa-video-player-1/">Part 1</a> and assemble them into a video player powered by the <code>OvpNetStream</code> class from the <a href="http://www.openvideoplayer.com/">Open Video Player</a> project.</p>
<h5>Design</h5>
<p class="bottom">I knew right away that the design was not going to have any right angles, but I also didn&#8217;t want to go with rounded rectangles everywhere.  Modern TVs tend to have a lot of soft rounded edges, so I decided to go with a more vintage look.  So I fired up <a href="http://www.inkscape.org/">Inkscape</a> and got to work:</p>
<div class="span-14 top bottom" style="min-height:232px; text-align:center;">
<img src="http://saturnboy.com/wp-content/uploads/2009/06/tv.png" alt="tv" title="tv" width="176" height="222" />
</div>
<p class="bottom">Implementing the video player design above in Degrafa, the cabinet mapped to a <code>RoundedRectangle</code>, and the screen &#038; antenna became <code>Path</code>s.  You can read more about about translating SVG to Degrafa in my <a href="http://saturnboy.com/2009/06/inkscape-svg-degrafa-pathinkscape-svg-degrafa-path/">Inkscape SVG to Degrafa Path</a> article.  But for now, let&#8217;s focus on the resulting Degrafa code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span></span>
<span style="color: #000000;">        xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        xmlns:Degrafa=<span style="color: #ff0000;">&quot;http://www.degrafa.com/2007&quot;</span></span>
<span style="color: #000000;">        layout=<span style="color: #ff0000;">&quot;absolute&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:GeometryComposition</span> graphicsTarget=<span style="color: #ff0000;">&quot;{[box]}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- Antenna --&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:Path</span> data=<span style="color: #ff0000;">&quot;...path data...&quot;</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:transform</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:TranslateTransform</span> x=<span style="color: #ff0000;">&quot;15&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:transform</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:Path</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- TV cabinet --&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:RoundedRectangle</span> y=<span style="color: #ff0000;">&quot;144&quot;</span> width=<span style="color: #ff0000;">&quot;350&quot;</span> height=<span style="color: #ff0000;">&quot;300&quot;</span></span>
<span style="color: #000000;">                cornerRadius=<span style="color: #ff0000;">&quot;20&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidFill</span> color=<span style="color: #ff0000;">&quot;#333333&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;4&quot;</span> alpha=<span style="color: #ff0000;">&quot;0.4&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:GeometryComposition</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- TV Screen --&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:GeometryComposition</span> graphicsTarget=<span style="color: #ff0000;">&quot;{[tvscreen]}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:Path</span> data=<span style="color: #ff0000;">&quot;...path data...&quot;</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidFill</span> color=<span style="color: #ff0000;">&quot;#FF99FF&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;2&quot;</span> alpha=<span style="color: #ff0000;">&quot;0.4&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:filters</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:GlowFilter</span> color=<span style="color: #ff0000;">&quot;#EEEEEE&quot;</span> alpha=<span style="color: #ff0000;">&quot;0.2&quot;</span> blurX=<span style="color: #ff0000;">&quot;16&quot;</span> blurY=<span style="color: #ff0000;">&quot;16&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:filters</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:Path</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:GeometryComposition</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> width=<span style="color: #ff0000;">&quot;350&quot;</span> height=<span style="color: #ff0000;">&quot;444&quot;</span></span>
<span style="color: #000000;">            horizontalCenter=<span style="color: #ff0000;">&quot;0&quot;</span> verticalCenter=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> id=<span style="color: #ff0000;">&quot;box&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> x=<span style="color: #ff0000;">&quot;50&quot;</span> y=<span style="color: #ff0000;">&quot;174&quot;</span> id=<span style="color: #ff0000;">&quot;tvscreen&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>I ended up using a pair of <code>GeometryComposition</code>s to wrap my three shapes to help keep my fills, strokes, and filters organized.  It made sense to do it this way, but I won&#8217;t claim it&#8217;s the best way.  Throw the control bar on below the TV screen, and the design is done.</p>
<h5>Backend</h5>
<p>The backend is build on the <code>OvpNetStream</code> class provided by the Open Video Player project.  <code>OvpNetStream</code> extends <code>NetStream</code> and smooths out some of the rough edges as I <a href="http://saturnboy.com/2009/04/open-video-player-air/">discussed</a> previously.  Basically, it provides a sane interface (no need to construct a dynamic object with function callbacks) and useful events (like metadata and progress events).</p>
<p class="bottom">For this demo, we simply instantiate <code>OvpNetStream</code> on <code>creationComplete</code> and wire up all the event handlers:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> complete<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    nc = <span style="color: #000000; font-weight: bold;">new</span> OvpConnection<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    nc.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #0066CC;">ERROR</span>, errorHandler<span style="color: #66cc66;">&#41;</span>;
    nc.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>NetStatusEvent.<span style="color: #006600;">NET_STATUS</span>, connStatusHandler<span style="color: #66cc66;">&#41;</span>;
    nc.<span style="color: #0066CC;">connect</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">null</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
    ns = <span style="color: #000000; font-weight: bold;">new</span> OvpNetStream<span style="color: #66cc66;">&#40;</span>nc<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #0066CC;">ERROR</span>, errorHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>NetStatusEvent.<span style="color: #006600;">NET_STATUS</span>, streamStatusHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #006600;">NETSTREAM_METADATA</span>, streamMetadataHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #006600;">PROGRESS</span>, streamProgressHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #006600;">COMPLETE</span>, streamCompleteHandler<span style="color: #66cc66;">&#41;</span>;
&nbsp;
    vid = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #0066CC;">Video</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    vid.<span style="color: #006600;">attachNetStream</span><span style="color: #66cc66;">&#40;</span>ns<span style="color: #66cc66;">&#41;</span>;
    vidContainer.<span style="color: #006600;">addChild</span><span style="color: #66cc66;">&#40;</span>vid<span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The most interesting events are the metadata and progress events.  The metadata event delivers the duration of the video and its size.  The progress event arrives periodically (theoretically every 100ms by default, but in reality I see them come in just a couple of times per second) and delivers the current video time.</p>
<h5>Control Bar</h5>
<p>The control bar consists of three components: a play-pause button, a scrubber, and a volume slider.  They were skinned using Degrafa in <a href="http://saturnboy.com/2009/05/degrafa-video-player-1/">Part 1</a>.  In order to control video playback, we need to wire the control bar components to the instance of <code>OvpNetStream</code> created above.</p>
<p class="bottom">Here are the event handlers for the three control bar components:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">// PlayPause event handler</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> playPauseClick<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>first<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        first = <span style="color: #000000; font-weight: bold;">false</span>;
        ns.<span style="color: #0066CC;">play</span><span style="color: #66cc66;">&#40;</span>filename<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span>
        ns.<span style="color: #006600;">togglePause</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
     <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">// Scrub event handlers</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> scrubPress<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #0066CC;">pause</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    playPause.<span style="color: #006600;">selected</span> = <span style="color: #000000; font-weight: bold;">false</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> scrubDrag<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #0066CC;">seek</span><span style="color: #66cc66;">&#40;</span>scrub.<span style="color: #006600;">value</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> scrubRelease<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #006600;">togglePause</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    playPause.<span style="color: #006600;">selected</span> = <span style="color: #000000; font-weight: bold;">true</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">// Volume event handler</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> volumeChange<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #006600;">volume</span> = volume.<span style="color: #006600;">value</span>;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>In the <code>playPauseHandler()</code>, the initial click calls <code>play()</code> which actually <i>loads</i> the video (and then starts playback), all subsequent clicks just toggle between play or pause.  For the scrubber handlers, I chose to break them up into three separate steps: on mouse down pause the video, on mouse up restart playback, and on drag attempt to seek to the to the new time.</p>
<p class="bottom">That&#8217;s it.  Here is the resulting Degrafa-skinned video player (view source enabled):</a></p>
<div id="flashcontent-degrafa-videoplayer">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p>Click <b>Play</b> to start playing <a href="http://www.elephantsdream.org/">Elephants Dream</a> (which is the &#8220;world&#8217;s first open movie,&#8221; and pretty cool too).  Right away you&#8217;ll notice some visual issues because the dimensions of the video are unknown until the metadata arrives.  Also, scrubbing has some problems which I believe are related to cue points in progressive downloads.  Lastly, I didn&#8217;t implement any indicators for buffering or download progress, so you&#8217;ll need to be patient.  Since this is just a demo, I&#8217;ll have to leave fixing those bugs as an exercise for the reader.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/degrafa_videoplayer/degrafa_videoplayer.html">Video Player</a> (<a href="http://saturnboy.com/proj/degrafa_videoplayer/srcview/degrafa_videoplayer.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_videoplayer/degrafa_videoplayer.swf', 'flashcontent-degrafa-videoplayer', '500', '460', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/06/degrafa-video-player-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Degrafa Video Player, Part 1</title>
		<link>http://saturnboy.com/2009/05/degrafa-video-player-1/</link>
		<comments>http://saturnboy.com/2009/05/degrafa-video-player-1/#comments</comments>
		<pubDate>Wed, 27 May 2009 05:42:47 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[open video player]]></category>
		<category><![CDATA[skinning]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=472</guid>
		<description><![CDATA[I&#8217;m going to combine my earlier Degrafa skinning efforts with my more recent video work to create a Degrafa-skinned video player. In this post, I&#8217;ll build out all the components required for a video player control bar. And in Part 2, I&#8217;ll weld the control bar to an Open Video Player OvpNetStream backend. Button To [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to combine my earlier <a href="http://www.degrafa.org/">Degrafa</a> <a href="http://saturnboy.com/2009/03/degrafa-button-explorer/">skinning</a> <a href="http://saturnboy.com/2009/04/more-degrafa-skins/">efforts</a> with my more recent <a href="http://saturnboy.com/2009/04/open-video-player-air/">video work</a> to create a Degrafa-skinned video player.  In this post, I&#8217;ll build out all the components required for a video player control bar.  And in <a href="http://saturnboy.com/2009/06/degrafa-video-player-2/">Part 2</a>, I&#8217;ll weld the control bar to an <a href="http://www.openvideoplayer.com/">Open Video Player</a> OvpNetStream backend.</p>
<h5>Button</h5>
<p class="bottom">To get started, I built out a simple button skin with a slight shine on the top half.  I also added rounded corners to give the classic web 2.0 look-and-feel.  There&#8217;s really not much to look at:</p>
<div id="flashcontent-degrafa-videoplayer-button">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Play-Pause Button</h5>
<p class="bottom">I&#8217;m using a toggleable Button component as the base of my Play-Pause button.  By leveraging Degrafa&#8217;s stateful skins, I simply change the visibility of the Play and Pause geometry depending on the skin&#8217;s state.  Here&#8217;s a snippet from the <code>states</code> block of the skin:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;states<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;State name=<span style="color: #ff0000;">&quot;upSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{rect}&quot;</span> name=<span style="color: #ff0000;">&quot;fill&quot;</span> value=<span style="color: #ff0000;">&quot;{upFill}&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{play}&quot;</span> name=<span style="color: #ff0000;">&quot;visible&quot;</span> value=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;">&lt;/State<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;State name=<span style="color: #ff0000;">&quot;selectedUpSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{rect}&quot;</span> name=<span style="color: #ff0000;">&quot;fill&quot;</span> value=<span style="color: #ff0000;">&quot;{upFill}&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{play}&quot;</span> name=<span style="color: #ff0000;">&quot;visible&quot;</span> value=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;">&lt;/State<span style="color: #7400FF;">&gt;</span></span>
    ...
<span style="color: #000000;">&lt;/states<span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom">Additionally, the play arrow and pause bars are dynamically sized based on the button height, so they readily scale to any size.  The result:</p>
<div id="flashcontent-degrafa-videoplayer-playpause">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Scrubber</h5>
<p class="bottom">Getting total control over a Slider skin is not easy in Flex 3.  There are two issue that I find quite annoying: the thumb size is hard-coded into the class and the highlight skin is offset from the track.  Fortunately, the web is full of workarounds for the <a href="http://blog.flexexamples.com/2007/09/12/changing-a-slider-controls-thumb-skin/">thumb size issue</a>, but for this skin I only needed to hard-code an offset (+6,+6) to bring the thumb&#8217;s origin to (0,0) and make all my geometry line up correctly.  Similarly, I added a 1 pixel offset to the highlight skin to bring its origin to (0,0) to match the track.  The result:</p>
<div id="flashcontent-degrafa-videoplayer-scrub">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Volume Slider</h5>
<p class="bottom">For consistency, the Volume slider re-uses the Scrubber&#8217;s thumb skin, but the track and highlight are wedges (<code>Polygon</code>&#8216;s in Degrafa).  The only clever piece of code is the highlight skin&#8217;s overridden <code>updateDisplayList()</code> function:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript3" style="font-family:monospace;">override <span style="color: #0033ff; font-weight: bold;">protected</span> <span style="color: #339966; font-weight: bold;">function</span> updateDisplayList<span style="color: #000000;">&#40;</span>unscaledWidth<span style="color: #000066; font-weight: bold;">:</span><span style="color: #004993;">Number</span><span style="color: #000066; font-weight: bold;">,</span> unscaledHeight<span style="color: #000066; font-weight: bold;">:</span><span style="color: #004993;">Number</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">:</span><span style="color: #0033ff; font-weight: bold;">void</span> <span style="color: #000000;">&#123;</span>
    <span style="color: #0033ff; font-weight: bold;">super</span><span style="color: #000066; font-weight: bold;">.</span>updateDisplayList<span style="color: #000000;">&#40;</span>unscaledWidth<span style="color: #000066; font-weight: bold;">,</span> unscaledHeight<span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span>
    awidth = unscaledWidth<span style="color: #000066; font-weight: bold;">;</span>
    aheight = unscaledHeight<span style="color: #000066; font-weight: bold;">;</span>
&nbsp;
    <span style="color: #0033ff; font-weight: bold;">if</span> <span style="color: #000000;">&#40;</span><span style="color: #0033ff; font-weight: bold;">this</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">hasOwnProperty</span><span style="color: #000000;">&#40;</span><span style="color: #990000;">'parent'</span><span style="color: #000000;">&#41;</span> <span style="color: #000066; font-weight: bold;">&amp;&amp;</span>
             <span style="color: #0033ff; font-weight: bold;">this</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">hasOwnProperty</span><span style="color: #000000;">&#40;</span><span style="color: #990000;">'parent'</span><span style="color: #000000;">&#41;</span> <span style="color: #000066; font-weight: bold;">&amp;&amp;</span>
             <span style="color: #0033ff; font-weight: bold;">this</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">hasOwnProperty</span><span style="color: #000000;">&#40;</span><span style="color: #990000;">'width'</span><span style="color: #000000;">&#41;</span> <span style="color: #000066; font-weight: bold;">&amp;&amp;</span>
             <span style="color: #0033ff; font-weight: bold;">this</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">width</span> <span style="color: #000066; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight:bold;">0</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
        _ratio = awidth <span style="color: #000066; font-weight: bold;">/</span> <span style="color: #0033ff; font-weight: bold;">this</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">parent</span><span style="color: #000066; font-weight: bold;">.</span><span style="color: #004993;">width</span><span style="color: #000066; font-weight: bold;">;</span>
    <span style="color: #000000;">&#125;</span> <span style="color: #0033ff; font-weight: bold;">else</span> <span style="color: #000000;">&#123;</span>
        _ratio = <span style="color: #000000; font-weight:bold;">0.00001</span><span style="color: #000066; font-weight: bold;">;</span>
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p class="bottom">In order to correctly draw the highlight wedge, we first need to know the dimensions of the track.  For simplicity, the Volume track height is hard-coded in both the track skin and highlight skin, but the width of the track is variable.  In this case, the width of the track is the same as the width of the <code>HSlider</code> component itself.  So in the <code>updateDisplayList()</code> code above, the track width is found and used to compute the ratio of widths.  This ratio is later used to draw the highlight geometry.  The end result:</p>
<div id="flashcontent-degrafa-videoplayer-volume">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>The Full Control Bar</h5>
<p class="bottom">Just displaying all the components side-by-side gives us the beginnings of a video player control bar:</p>
<div id="flashcontent-degrafa-videoplayer-controlbar">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p>Not too shabby.  In <a href="http://saturnboy.com/2009/06/degrafa-video-player-2/">Part 2</a>, I&#8217;ll assemble the final video player frontend including the pretty control bar components above, and weld it to an OvpNetStream-powered backend.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_button/degrafa_videoplayer_button.html">Button</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_button/srcview/degrafa_videoplayer_button.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_playpause/degrafa_videoplayer_playpause.html">Play-Pause Button</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_playpause/srcview/degrafa_videoplayer_playpause.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_scrub/degrafa_videoplayer_scrub.html">Scrubber</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_scrub/srcview/degrafa_videoplayer_scrub.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_volume/degrafa_videoplayer_volume.html">Volume Slider</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_volume/srcview/degrafa_videoplayer_volume.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_controlbar/degrafa_videoplayer_controlbar.html">The Full Control Bar</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_controlbar/srcview/degrafa_videoplayer_controlbar.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_button/degrafa_videoplayer_button.swf', 'flashcontent-degrafa-videoplayer-button', '500', '40', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_playpause/degrafa_videoplayer_playpause.swf', 'flashcontent-degrafa-videoplayer-playpause', '500', '120', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_scrub/degrafa_videoplayer_scrub.swf', 'flashcontent-degrafa-videoplayer-scrub', '500', '50', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_volume/degrafa_videoplayer_volume.swf', 'flashcontent-degrafa-videoplayer-volume', '500', '50', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_controlbar/degrafa_videoplayer_controlbar.swf', 'flashcontent-degrafa-videoplayer-controlbar', '500', '40', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/05/degrafa-video-player-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Nested SWF communication</title>
		<link>http://saturnboy.com/2009/04/nested-swf-communication/</link>
		<comments>http://saturnboy.com/2009/04/nested-swf-communication/#comments</comments>
		<pubDate>Tue, 28 Apr 2009 04:45:34 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[swfloader]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=437</guid>
		<description><![CDATA[The ability to split up a large application in smaller, more manageable chunks is one of the pillars of enterprise development. The flash platform is littered with examples: AS3 is OO language, MXML components, SWCs, RSLs, SWFLoader, ExternalInterface, etc. In this post, I&#8217;m going to focus on using nested SWFs via SWFLoader. There a few [...]]]></description>
			<content:encoded><![CDATA[<p>The ability to split up a large application in smaller, more manageable chunks is one of the pillars of enterprise development.  The flash platform is littered with examples: AS3 is OO language, MXML components, SWCs, RSLs, SWFLoader, ExternalInterface, etc.  In this post, I&#8217;m going to focus on using nested SWFs via <code>SWFLoader</code>.  There a <a href="http://rahulmainkar.blogspot.com/2007/11/swfloader-and-nested-application.html">few other</a> <a href="http://flexdevtips.blogspot.com/2009/02/calling-functions-on-applications.html">good posts</a> out there, plus the <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=controls_15.html">Adobe docs</a>, but I&#8217;ll try to tie everything together in one place.</p>
<p>My main interest in the nested SWFs approach is for performance reasons, both the reduced initial download size and the ability to defer component creation can make a big difference in the real world.  And secondarily for testing reasons, because it&#8217;s just awesome to see a big enterprise app wired up via <a href="https://hudson.dev.java.net/">hudson</a> with <a href="http://code.google.com/p/flexmonkey/">FlexMonkey</a> and <a href="http://code.google.com/p/fluint/">Fluint</a> tests.</p>
<p>None of this would be very interesting without the ability to communicated between SWFs.  Thankfully, there are a few good options when talking between Flash 9 SWFs, because they run together inside Flash Player in AVM2.  Talking between Flash 9 or newer and Flash 8 or older is still possible, but because of the AVM1/AVM2 split you need to use <code>LocalConnection</code> which I&#8217;m not going to get into.</p>
<h5>Child Application</h5>
<p class="bottom">How does SWF to SWF communication work?  First, let&#8217;s start with a simple child app:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span> xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">        &lt;![CDATA[</span>
<span style="color: #339933;">            [Bindable] public var myProp:String = 'foo';</span>
&nbsp;
<span style="color: #339933;">            private function btnClick():void {</span>
<span style="color: #339933;">                dispatchEvent(new Event('child'));</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">            public function myFunc(color:uint):void {</span>
<span style="color: #339933;">                setStyle('backgroundColor', color);</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">            public function myFuncReturn(i:int, j:int):int {</span>
<span style="color: #339933;">                return i + j;</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">        ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> text=<span style="color: #ff0000;">&quot;{'myProp = ' + myProp}&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;dispatch event&quot;</span> click=<span style="color: #ff0000;">&quot;btnClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The child app exposes one public property <code>myProp</code>, two public functions <code>myFunc</code> and <code>myFuncReturn</code>, and a <i>custom</i> event.</p>
<h5>Main Application</h5>
<p class="bottom">The main app exercises all four options in the child SWF.  But in an effort to mimic reality, I&#8217;m imposing the additional constraint that while the child&#8217;s API is known, the actual MXML is unavailable.</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span> xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span> verticalGap=<span style="color: #ff0000;">&quot;12&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">        &lt;![CDATA[</span>
<span style="color: #339933;">            import mx.controls.Alert;</span>
<span style="color: #339933;">            import mx.events.FlexEvent;</span>
<span style="color: #339933;">            import mx.managers.SystemManager;</span>
&nbsp;
<span style="color: #339933;">            private var childApp:Application;</span>
&nbsp;
<span style="color: #339933;">            private function init():void {</span>
<span style="color: #339933;">                SystemManager(loader.content).addEventListener(</span>
<span style="color: #339933;">                        FlexEvent.APPLICATION_COMPLETE, childReady);</span>
<span style="color: #339933;">              }</span>
&nbsp;
<span style="color: #339933;">              private function childReady(e:FlexEvent):void {</span>
<span style="color: #339933;">                  childApp = e.target.application as Application;</span>
<span style="color: #339933;">                  childApp.addEventListener('child', childEventHandler);</span>
<span style="color: #339933;">              }</span>
<span style="color: #339933;">              private function childEventHandler(e:Event):void {</span>
<span style="color: #339933;">                  Alert.show('got child event');</span>
<span style="color: #339933;">              }</span>
&nbsp;
<span style="color: #339933;">              private function setChildProp():void {</span>
<span style="color: #339933;">                  if (childApp.hasOwnProperty('myProp')) {</span>
<span style="color: #339933;">                      childApp['myProp'] = 'bar';</span>
<span style="color: #339933;">                  }</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">            private function callChildFunc():void {</span>
<span style="color: #339933;">                if (childApp.hasOwnProperty('myFunc') &amp;&amp;</span>
<span style="color: #339933;">                        childApp['myFunc'] is Function) {</span>
<span style="color: #339933;">                    childApp['myFunc'](0xFF00FF);</span>
<span style="color: #339933;">                }</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">            private function callChildFuncReturn():void {</span>
<span style="color: #339933;">                if (childApp.hasOwnProperty('myFuncReturn') &amp;&amp;</span>
<span style="color: #339933;">                        childApp['myFuncReturn'] is Function) {</span>
<span style="color: #339933;">                    var val:int = childApp['myFuncReturn'](13, 4);</span>
<span style="color: #339933;">                    Alert.show('13 + 4 = ' + val);</span>
<span style="color: #339933;">                }</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">        ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Panel</span> title=<span style="color: #ff0000;">&quot;Child&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:SWFLoader</span> id=<span style="color: #ff0000;">&quot;loader&quot;</span> source=<span style="color: #ff0000;">&quot;test_child.swf&quot;</span> complete=<span style="color: #ff0000;">&quot;init()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Panel</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;set child property&quot;</span> click=<span style="color: #ff0000;">&quot;setChildProp()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;call child func&quot;</span> click=<span style="color: #ff0000;">&quot;callChildFunc()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;call child func return&quot;</span> click=<span style="color: #ff0000;">&quot;callChildFuncReturn()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom">In the main app, the child SWF is loaded via the <code>SWFLoader</code> MXML tag, which calls the <code>init()</code> function on completion.  Then we wait for the child SWF to finish loading before casting it to an <code>Application</code> and wiring up a handler for our <i>custom</i> event.  The other three child-to-parent communication options are exercised by the three button click callback functions.  In each callback, we first check to see if the child property exists, and in the case of the two function calls, if it can be cast to a <code>Function</code>.  In the <a href="http://livedocs.adobe.com/flex/3/html/help.html?content=controls_15.html">Adobe docs</a>, because the child MXML code is in the same folder as the parent MXML, they just use a simple cast prior to invoking functions:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript3" style="font-family:monospace;">FlexApp<span style="color: #000000;">&#40;</span>loadedSM<span style="color: #000066; font-weight: bold;">.</span>application<span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">.</span>setVarOne<span style="color: #000000;">&#40;</span><span style="color: #990000;">&quot;Updated varOne!&quot;</span><span style="color: #000000;">&#41;</span><span style="color: #000066; font-weight: bold;">;</span></pre></div></div>

<p>Which is great for them because they control both the parent and the child SWFs, but doesn&#8217;t really work when you have some 3rd party SWF you need to use or Creative lobs some crazy flash animation grenade into your cube at 5:15pm with a nice note to send over a working solution before you go home for the evening.  Yep, that <i>never</i> happens.</p>
<p>There is another point that I often forget about MXML: instantiation via tags creates a public instance of the component.  So for example, if we added id attributes to the child label and child button, then they would be directly accessible in the parent via <code>childApp['childLabel'].text</code> or <code>childApp['childButton'].addEventListener(...)</code>.  I find my sense of API cleanliness is deeply offend by this manner of communication, so I tend to stick with one of the four options I described above (probably why I always forget).</p>
<p>Here is the final product:</p>
<p class="large">&nbsp;&raquo;&nbsp;&nbsp;<a href="http://saturnboy.com/proj/test_parent_child/test_parent/test_parent.html" target="_blank">Main App</a></p>
<blockquote class="deeper"><p><b>Digging Deeper:</b> If you really want to maximize client-side performance, you might find yourself loading and unloading child SWFs.  In such a situation, it is important to <a href="http://joshblog.net/2009/04/23/unloading-child-swfs-in-flash/">be a good citizen</a> and make sure your child SWFs clean up after themselves.</p></blockquote>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/test_parent_child/test_child/test_child.html">Child App</a> (<a href="http://saturnboy.com/proj/test_parent_child/test_child/srcview/test_child.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/test_parent_child/test_parent/test_parent.html">Parent App</a> (<a href="http://saturnboy.com/proj/test_parent_child/test_parent/srcview/test_parent.zip">download</a>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/04/nested-swf-communication/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Open Video Player in AIR</title>
		<link>http://saturnboy.com/2009/04/open-video-player-air/</link>
		<comments>http://saturnboy.com/2009/04/open-video-player-air/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 05:09:57 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[AIR]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[open video player]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=413</guid>
		<description><![CDATA[Recently, I&#8217;ve been doing quite a bit of video work in Flex and AIR. My main gripe (that I&#8217;ll try to rectify below) is that there sure is a lot of info around the web about streaming, FMS, and friends, but almost none about playing local video. Even the Adobe Media Player, which is a [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been doing quite a bit of video work in Flex and AIR.  My main gripe (that I&#8217;ll try to rectify below) is that there sure is a lot of info around the web about streaming, FMS, and friends, but almost none about playing local video.  Even the <a href="http://www.adobe.com/go/mp">Adobe Media Player</a>, which is a really nice AIR app, is all about streaming content from the web.</p>
<p>And like <a href="http://www.brooksandrus.com/blog/2008/11/05/3-years-later-netstream-still-sucks/">those before me</a>, I&#8217;ve come to the same conclusion about video in Flash: it&#8217;s pretty cool, but I sure wish it was better.  Enter the <a href="http://www.openvideoplayer.com/">Open Video Player</a> as the answer to some of <code>NetStream</code>&#8216;s woes.  Alas, all of the OVP docs and samples are, once again, all about streaming, Akamai, bandwidth, etc.</p>
<p>The elephant in the room for an AIR video player: What if I&#8217;m offline?</p>
<h5>The Easy Way: VideoDisplay</h5>
<p class="bottom">I gonna get started with the easiest possible local video player, which in Flex means using <code>VideoDisplay</code>.  Here&#8217;s a simple AIR app that allows you to open a FLV file and play it:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:WindowedApplication</span> xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        width=<span style="color: #ff0000;">&quot;700&quot;</span> height=<span style="color: #ff0000;">&quot;500&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">        &lt;![CDATA[</span>
<span style="color: #339933;">            [Bindable] private var filename:String = '';</span>
&nbsp;
<span style="color: #339933;">            private function openVideo():void {</span>
<span style="color: #339933;">                if (vd.playing) {</span>
<span style="color: #339933;">                    vd.pause();</span>
<span style="color: #339933;">                    playPause.label = 'PLAY';</span>
<span style="color: #339933;">                }</span>
&nbsp;
<span style="color: #339933;">                var docs:File = File.documentsDirectory;</span>
<span style="color: #339933;">                docs.browseForOpen('Select a Video', [new FileFilter(&quot;Video&quot;, &quot;*.flv&quot;)]);</span>
<span style="color: #339933;">                docs.addEventListener(Event.SELECT, openFileHandler);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function openFileHandler(e:Event):void {</span>
<span style="color: #339933;">                var f:File = e.target as File;</span>
<span style="color: #339933;">                filename = f.name;</span>
&nbsp;
<span style="color: #339933;">                vd.source = 'file://' + f.nativePath;</span>
<span style="color: #339933;">                vd.play();</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function stopClick():void {</span>
<span style="color: #339933;">                vd.stop();</span>
<span style="color: #339933;">                playPause.label = 'PLAY';</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function toggleClick():void {</span>
<span style="color: #339933;">                if (vd.playing) {</span>
<span style="color: #339933;">                	vd.pause();</span>
<span style="color: #339933;">                	playPause.label = 'PLAY';</span>
<span style="color: #339933;">                } else {</span>
<span style="color: #339933;">                	vd.play();</span>
<span style="color: #339933;">                	playPause.label = 'PAUSE';</span>
<span style="color: #339933;">                } </span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">        ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:ApplicationControlBar</span> dock=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;Open Video&quot;</span> click=<span style="color: #ff0000;">&quot;openVideo()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> text=<span style="color: #ff0000;">&quot;{filename}&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:ApplicationControlBar</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> height=<span style="color: #ff0000;">&quot;100%&quot;</span> backgroundColor=<span style="color: #ff0000;">&quot;#000000&quot;</span> backgroundAlpha=<span style="color: #ff0000;">&quot;0.1&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    	<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:VideoDisplay</span> id=<span style="color: #ff0000;">&quot;vd&quot;</span> autoPlay=<span style="color: #ff0000;">&quot;false&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> id=<span style="color: #ff0000;">&quot;playPause&quot;</span> label=<span style="color: #ff0000;">&quot;PAUSE&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> click=<span style="color: #ff0000;">&quot;toggleClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;STOP&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> click=<span style="color: #ff0000;">&quot;stopClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:WindowedApplication</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The only real magic is the <code>vd.source = 'file://' + f.nativePath</code> line.  Apparently, <code>source</code> wants a URL even for a local file, so just prepend <code>file://</code> and everything works fine.</p>
<h5>Getting Fancy with NetStream</h5>
<p class="bottom">As far as I can tell, no one actually uses <code>VideoDisplay</code> at the core of a video player component in a production system.  The <i>many</i> benefits of <code>NetStream</code> are not really clear to me, but it is the darling of production systems.  Thankfully, despite its name, <code>NetStream</code> is perfectly happy playing local video.  Rebuilding the above example yields:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:WindowedApplication</span> xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        width=<span style="color: #ff0000;">&quot;700&quot;</span> height=<span style="color: #ff0000;">&quot;500&quot;</span></span>
<span style="color: #000000;">        applicationComplete=<span style="color: #ff0000;">&quot;complete()&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">        &lt;![CDATA[</span>
<span style="color: #339933;">            [Bindable] private var filename:String = '';</span>
<span style="color: #339933;">            private var nc:NetConnection;</span>
<span style="color: #339933;">            private var ns:NetStream;</span>
<span style="color: #339933;">            private var vid:Video;</span>
<span style="color: #339933;">            private var t:Timer;</span>
&nbsp;
<span style="color: #339933;">            private function complete():void {</span>
<span style="color: #339933;">                nc = new NetConnection();</span>
<span style="color: #339933;">                nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);</span>
<span style="color: #339933;">                nc.addEventListener(NetStatusEvent.NET_STATUS, connStatusHandler);</span>
<span style="color: #339933;">                nc.connect(null);</span>
&nbsp;
<span style="color: #339933;">                ns = new NetStream(nc); </span>
<span style="color: #339933;">                ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, errorHandler);</span>
<span style="color: #339933;">                ns.addEventListener(NetStatusEvent.NET_STATUS, streamStatusHandler);</span>
<span style="color: #339933;">                ns.client = { onMetaData:streamMetadataHandler };</span>
&nbsp;
<span style="color: #339933;">                t = new Timer(300);</span>
<span style="color: #339933;">                t.addEventListener(TimerEvent.TIMER, streamProgressHandler);</span>
&nbsp;
<span style="color: #339933;">                vid = new Video();</span>
<span style="color: #339933;">                uic.addChild(vid);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function openVideo():void {</span>
<span style="color: #339933;">                if (ns) {</span>
<span style="color: #339933;">                    ns.pause();</span>
<span style="color: #339933;">                    playPause.label = 'PLAY';</span>
<span style="color: #339933;">                }</span>
&nbsp;
<span style="color: #339933;">                var docs:File = File.documentsDirectory;</span>
<span style="color: #339933;">                docs.addEventListener(Event.SELECT, openFileHandler);</span>
<span style="color: #339933;">                docs.browseForOpen('Select a Video', [new FileFilter(&quot;Video&quot;, &quot;*.flv&quot;)]);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function openFileHandler(e:Event):void {</span>
<span style="color: #339933;">                var f:File = e.target as File;</span>
<span style="color: #339933;">                filename = f.name;</span>
&nbsp;
<span style="color: #339933;">                ns.play('file://' + f.nativePath);</span>
<span style="color: #339933;">                playPause.label = 'PAUSE';</span>
&nbsp;
<span style="color: #339933;">                vid.attachNetStream(ns);</span>
&nbsp;
<span style="color: #339933;">                t.start();</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function errorHandler(e:AsyncErrorEvent):void {</span>
<span style="color: #339933;">                trace('ERROR: ' + e.text);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function connStatusHandler(e:NetStatusEvent):void {</span>
<span style="color: #339933;">                trace('CONN_STATUS: ' + e.info.code);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function streamStatusHandler(e:NetStatusEvent):void {</span>
<span style="color: #339933;">                trace('STREAM_STATUS: ' + e.info.code);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function streamMetadataHandler(info:Object):void {</span>
<span style="color: #339933;">                for (var key:String in info) {</span>
<span style="color: #339933;">                    trace(&quot;STREAM_METADATA: &quot; + key + &quot;=&quot; + info[key]);</span>
<span style="color: #339933;">                }</span>
<span style="color: #339933;">                uic.width = info.width;</span>
<span style="color: #339933;">                uic.height = info.height;</span>
&nbsp;
<span style="color: #339933;">                vid.width = info.width;</span>
<span style="color: #339933;">                vid.height = info.height;</span>
<span style="color: #339933;">                vid.x = 0;</span>
<span style="color: #339933;">                vid.y = 0;</span>
&nbsp;
<span style="color: #339933;">                len.text = parseFloat(info.duration).toFixed(1);    </span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function streamProgressHandler(e:TimerEvent):void {</span>
<span style="color: #339933;">                   timer.text = ns.time.toFixed(1);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function stopClick():void {</span>
<span style="color: #339933;">                ns.pause();</span>
<span style="color: #339933;">                ns.seek(0);</span>
<span style="color: #339933;">                playPause.label = 'PLAY';</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function toggleClick():void {</span>
<span style="color: #339933;">                ns.togglePause();</span>
<span style="color: #339933;">                playPause.label = (playPause.label == 'PAUSE' ? 'PLAY' : 'PAUSE');</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">        ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:ApplicationControlBar</span> dock=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;Open Video&quot;</span> click=<span style="color: #ff0000;">&quot;openVideo()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> text=<span style="color: #ff0000;">&quot;{filename}&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;timer&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;len&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:ApplicationControlBar</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> height=<span style="color: #ff0000;">&quot;100%&quot;</span> backgroundColor=<span style="color: #ff0000;">&quot;#000000&quot;</span> backgroundAlpha=<span style="color: #ff0000;">&quot;0.1&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:UIComponent</span> id=<span style="color: #ff0000;">&quot;uic&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> height=<span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> id=<span style="color: #ff0000;">&quot;playPause&quot;</span> label=<span style="color: #ff0000;">&quot;PAUSE&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> click=<span style="color: #ff0000;">&quot;toggleClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;STOP&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> click=<span style="color: #ff0000;">&quot;stopClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:WindowedApplication</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p><code>NetStream</code> is a wonder of engineering.  Basic usage is understandable, just feed in <code>null</code> to the <code>NetConnection</code> to switch to <i>progressive download mode</i>, and use the same <code>file://</code> trick above to play a local video.  But after that, things get weird fast.  First, the metadata handling to totally backwards: you have to create a dynamic object with a <code>onMetaData</code> property that maps to a callback function.  My guess would be that there is some legacy bullshit going on that breaks <code>addEventListener</code>.  Second, you can&#8217;t tell if a video is playing or not.  Third, the lack of progress event means you need to use a timer to track playhead time.  Add it up &ndash; <b>LAME</b>.</p>
<h5>Reaching for the Grail: Open Video Player</h5>
<p class="bottom">According to their website, it&#8217;s <a href="http://www.openvideoplayer.com/">Open Video Player</a> to the rescue.  And I&#8217;ll have to agree that it fixes many of <code>NetStream</code> issues.  Swaping in <code>OvpNetStream</code> yields:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:WindowedApplication</span> xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        width=<span style="color: #ff0000;">&quot;700&quot;</span> height=<span style="color: #ff0000;">&quot;500&quot;</span></span>
<span style="color: #000000;">        applicationComplete=<span style="color: #ff0000;">&quot;complete()&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">        &lt;![CDATA[</span>
<span style="color: #339933;">            import org.openvideoplayer.net.OvpConnection;</span>
<span style="color: #339933;">            import org.openvideoplayer.net.OvpNetStream;</span>
<span style="color: #339933;">            import org.openvideoplayer.events.OvpEvent;</span>
&nbsp;
<span style="color: #339933;">            [Bindable] private var filename:String = '';</span>
<span style="color: #339933;">            private var nc:OvpConnection;</span>
<span style="color: #339933;">            private var ns:OvpNetStream;</span>
<span style="color: #339933;">            private var vid:Video;</span>
&nbsp;
<span style="color: #339933;">            private function complete():void {</span>
<span style="color: #339933;">                nc = new OvpConnection();</span>
<span style="color: #339933;">                nc.addEventListener(OvpEvent.ERROR, errorHandler);</span>
<span style="color: #339933;">                nc.addEventListener(NetStatusEvent.NET_STATUS, connStatusHandler);</span>
<span style="color: #339933;">                nc.connect(null);</span>
&nbsp;
<span style="color: #339933;">                ns = new OvpNetStream(nc);</span>
<span style="color: #339933;">                ns.addEventListener(OvpEvent.ERROR, errorHandler);</span>
<span style="color: #339933;">                ns.addEventListener(NetStatusEvent.NET_STATUS, streamStatusHandler);</span>
<span style="color: #339933;">                ns.addEventListener(OvpEvent.NETSTREAM_METADATA, streamMetadataHandler);</span>
<span style="color: #339933;">                ns.addEventListener(OvpEvent.PROGRESS, streamProgressHandler);</span>
&nbsp;
<span style="color: #339933;">                vid = new Video();</span>
<span style="color: #339933;">                uic.addChild(vid);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function openVideo():void {</span>
<span style="color: #339933;">                if (ns) {</span>
<span style="color: #339933;">                    ns.pause();</span>
<span style="color: #339933;">                    playPause.label = 'PLAY';</span>
<span style="color: #339933;">                }</span>
&nbsp;
<span style="color: #339933;">                var docs:File = File.documentsDirectory;</span>
<span style="color: #339933;">                docs.addEventListener(Event.SELECT, openFileHandler);</span>
<span style="color: #339933;">                docs.browseForOpen('Select a Video', [new FileFilter(&quot;Video&quot;, &quot;*.flv&quot;)]);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function openFileHandler(e:Event):void {</span>
<span style="color: #339933;">                var f:File = e.target as File;</span>
<span style="color: #339933;">                filename = f.name;</span>
&nbsp;
<span style="color: #339933;">                ns.play('file://' + f.nativePath);</span>
<span style="color: #339933;">                playPause.label = 'PAUSE';</span>
&nbsp;
<span style="color: #339933;">                vid.attachNetStream(ns);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function errorHandler(e:OvpEvent):void {</span>
<span style="color: #339933;">                trace('ERROR: ' + e.data.errorNumber + ': ' + e.data.errorDescription);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function connStatusHandler(e:NetStatusEvent):void {</span>
<span style="color: #339933;">                trace('CONN_STATUS: ' + e.info.code);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function streamStatusHandler(e:NetStatusEvent):void {</span>
<span style="color: #339933;">                trace('STREAM_STATUS: ' + e.info.code);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function streamMetadataHandler(e:OvpEvent):void {</span>
<span style="color: #339933;">                for (var key:String in e.data) {</span>
<span style="color: #339933;">                    trace(&quot;STREAM_METADATA: &quot; + key + &quot;=&quot; + e.data[key]);</span>
<span style="color: #339933;">                }</span>
<span style="color: #339933;">                uic.width = e.data.width;</span>
<span style="color: #339933;">                uic.height = e.data.height;</span>
&nbsp;
<span style="color: #339933;">                vid.width = e.data.width;</span>
<span style="color: #339933;">                vid.height = e.data.height;</span>
<span style="color: #339933;">                vid.x = 0;</span>
<span style="color: #339933;">                vid.y = 0;</span>
&nbsp;
<span style="color: #339933;">                len.text = nc.streamLengthAsTimeCode(e.data.duration);</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function streamProgressHandler(e:OvpEvent):void {</span>
<span style="color: #339933;">                   timer.text = ns.timeAsTimeCode;</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function stopClick():void {</span>
<span style="color: #339933;">                ns.pause();</span>
<span style="color: #339933;">                ns.seek(0);</span>
<span style="color: #339933;">                playPause.label = 'PLAY';</span>
<span style="color: #339933;">            }</span>
&nbsp;
<span style="color: #339933;">            private function toggleClick():void {</span>
<span style="color: #339933;">                ns.togglePause();</span>
<span style="color: #339933;">                playPause.label = (playPause.label == 'PAUSE' ? 'PLAY' : 'PAUSE');</span>
<span style="color: #339933;">            }</span>
<span style="color: #339933;">        ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:ApplicationControlBar</span> dock=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;Open Video&quot;</span> click=<span style="color: #ff0000;">&quot;openVideo()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> text=<span style="color: #ff0000;">&quot;{filename}&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;timer&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;len&quot;</span> fontSize=<span style="color: #ff0000;">&quot;14&quot;</span> fontWeight=<span style="color: #ff0000;">&quot;bold&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:ApplicationControlBar</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> height=<span style="color: #ff0000;">&quot;100%&quot;</span> backgroundColor=<span style="color: #ff0000;">&quot;#000000&quot;</span> backgroundAlpha=<span style="color: #ff0000;">&quot;0.1&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:UIComponent</span> id=<span style="color: #ff0000;">&quot;uic&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> height=<span style="color: #ff0000;">&quot;100&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> id=<span style="color: #ff0000;">&quot;playPause&quot;</span> label=<span style="color: #ff0000;">&quot;PAUSE&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> click=<span style="color: #ff0000;">&quot;toggleClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Button</span> label=<span style="color: #ff0000;">&quot;STOP&quot;</span> width=<span style="color: #ff0000;">&quot;100&quot;</span> click=<span style="color: #ff0000;">&quot;stopClick()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:WindowedApplication</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>It&#8217;s not a revolution because <code>OvpNetStream</code> just extends <code>NetStream</code>, but we instantly get standard events thrown for progress ticks and metadata, and also some pretty time formatting as a bonus.  The OVP also does about a hundred other things related to streaming, streaming servers, and Akamai.  That&#8217;s about all I know about video right now, so before I can post again I&#8217;ll need to learn something new&#8230;</p>
<h5>Files</h5>
<p class="bottom">Just tarballs (it&#8217;s an AIR app after all):</p>
<ul>
<li><a href="http://saturnboy.com/proj/test_vid/test_vid.tgz">test_vid.tgz</a> (using VideoDisplay)</li>
<li><a href="http://saturnboy.com/proj/test_vid/test_vid_stream.tgz">test_vid_stream.tgz</a> (using NetStream)</li>
<li><a href="http://saturnboy.com/proj/test_vid/test_vid_ovp.tgz">test_vid_ovp.tgz</a> (using Open Video Player)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/04/open-video-player-air/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>More Degrafa skins</title>
		<link>http://saturnboy.com/2009/04/more-degrafa-skins/</link>
		<comments>http://saturnboy.com/2009/04/more-degrafa-skins/#comments</comments>
		<pubDate>Mon, 06 Apr 2009 22:43:46 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=371</guid>
		<description><![CDATA[Before I dig too deep trying to create a Degrafa Skin Explorer (the idea) as an evolution of the Degrafa Button Explorer, I thought it would be a good idea to spend some more time with some basic Degrafa skinning. I managed to create a few button skins previously, but this time around I wanted [...]]]></description>
			<content:encoded><![CDATA[<p>Before I dig too deep trying to create a Degrafa Skin Explorer (<a href="http://groups.google.com/group/degrafa/browse_thread/thread/3041beeb5c4a92ee">the idea</a>) as an evolution of the <a href="http://saturnboy.com/2009/03/degrafa-button-explorer/">Degrafa Button Explorer</a>, I thought it would be a good idea to spend some more time with some basic <a href="http://www.degrafa.org/">Degrafa</a> skinning.  I managed to create a few button skins <a href="http://saturnboy.com/2009/03/degrafa-button-explorer/">previously</a>, but this time around I wanted something more involved.</p>
<h5>ButtonBar</h5>
<p class="bottom">First, I built out a pair of ButtonBar skins (view source enabled):</p>
<div id="flashcontent-degrafa-buttonbars">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>ToggleButtonBar</h5>
<p class="bottom">Next, I augmented the my basic ButtonBar skins with the various required selected skins (<code>selectedUpSkin</code>, <code>selectedDownSkin</code>, etc.) to create a pair of ToggleButtonBar skins (view source enabled):</p>
<div id="flashcontent-degrafa-tabs">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>iPhone Theme</h5>
<p class="bottom">Lastly, I dissected the <a href="http://www.degrafa.org/source/iPhoneSkin/iPhoneSkin.html">iPhone-esque theme</a> sample from the <a href="http://www.degrafa.org/samples/">Degrafa Samples</a> page, and created my own bastardized iPhone theme.  I factored out a <i>theme color</i> from each component into a CSS style called <code>mainColor</code> to allow the skin to be tweaked.  Check it out (view source enabled):</p>
<div id="flashcontent-degrafa-iphone">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Conclusions</h5>
<p>I learned a couple of things during my skinning exercise, but probably the most important came to me in an amazing &#8220;A-Duh&#8221; moment: <a href="http://www.degrafa.org/">Degrafa</a> is <b>really</b> powerful.  This is probably the same as saying MXML is a high-level language with a lot of leverage, but the Degrafa team has done a great job bringing this leverage to bear on skinning and graphics in Flex.  At this point, I find it hard to imagine creating a style without it.</p>
<p class="bottom">Secondly, semantic naming is a must inside a stateful skin.  So, I replaced any names like <code>darkFill</code> or <code>lightStroke</code>, with nice semantic names like <code>overFill</code> and <code>selectedStroke</code>.  So if I look at a chunk of code like this:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;State name=<span style="color: #ff0000;">&quot;downSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{rect}&quot;</span> name=<span style="color: #ff0000;">&quot;fill&quot;</span> value=<span style="color: #ff0000;">&quot;{overFill}&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;">&lt;/State<span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>I can immediately know that my <code>downSkin</code> state is using a fill from my <code>overSkin</code> state, and probably implies the states are the same.</p>
<p>Lastly, always resist the temptation to re-use/re-purpose the CSS style from the underlying component in a skin.  For example, the iPhone theme above uses a <i>theme color</i> which I intentionally named <code>mainColor</code>.  I could easily have used Button&#8217;s aptly-named <code>themeColor</code> style (inherited down from UIComponent).  But this would dangerously overload the meaning of <code>themeColor</code>, because while it normally controls the Button&#8217;s border color it would now control the body color in my iPhone button skin.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_buttonbars/degrafa_buttonbars.html">ButtonBar</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_buttonbars/srcview/degrafa_buttonbars.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_tabs/degrafa_tabs.html">ToggleButtonBar</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_tabs/srcview/degrafa_tabs.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_iphone/degrafa_iphone.html">iPhone Theme</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_iphone/srcview/degrafa_iphone.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_buttonbars/degrafa_buttonbars.swf', 'flashcontent-degrafa-buttonbars', '400', '70', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_tabs/degrafa_tabs.swf', 'flashcontent-degrafa-tabs', '500', '320', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_iphone/degrafa_iphone.swf', 'flashcontent-degrafa-iphone', '420', '216', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/04/more-degrafa-skins/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Degrafa Button Explorer</title>
		<link>http://saturnboy.com/2009/03/degrafa-button-explorer/</link>
		<comments>http://saturnboy.com/2009/03/degrafa-button-explorer/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 22:50:58 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=332</guid>
		<description><![CDATA[Recently, I&#8217;ve been playing around with Degrafa in preparation for actually using it on an upcoming project at work. For those that aren&#8217;t in the know, Degrafa is a badass graphics framework for Flex. One of my favorite parts so far is the amazing leverage it brings to building custom-styled components. It&#8217;s terse and powerful, [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been playing around with <a href="http://www.degrafa.org/">Degrafa</a> in preparation for actually using it on an upcoming project at <a href="http://www.gorillalogic.com/">work</a>.  For those that aren&#8217;t in the know, Degrafa is a badass graphics framework for Flex.  One of my favorite parts so far is the amazing leverage it brings to building custom-styled components.  It&#8217;s terse and powerful, just the way I like it.</p>
<h5>Building Buttons</h5>
<p class="bottom">With a very minimal amount of effort, I was able to create a few &#8220;web 2.0&#8243; button skins.  I just followed one of the millions of glass button photoshop tutorials, but did the work in mxml code using Degrafa&#8217;s declarative syntax.  Here are my results (view source enabled):</p>
<div class="span-14 top bottom" style="text-align:center;">
<div id="flashcontent-degrafa-buttons">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
</div>
<h5>Button Explorer</h5>
<p>But then I decided to take it a step further and build out a Degrafa Button Explorer (with a small tip of the hat to the original <a href="http://examples.adobe.com/flex3/consulting/styleexplorer/Flex3StyleExplorer.html">Flex Style Explorer</a>).  The Degrafa Button Explorer allows you to adjust a bunch of properties and colors for all three buttons styles.  It goes a step further than the original and provides not only the CSS, but also the full code of the stateful Degrafa-powered button components.</p>
<p class="large">&nbsp;&raquo;&nbsp;&nbsp;<a href="http://saturnboy.com/proj/degrafa_button_explorer/" target="_blank">Degrafa Button Explorer</a></p>
<blockquote class="deeper"><p><b>Digging Deeper:</b> I&#8217;ve been following the skinning performance issues discovered by the <a href="http://behindtheui.blogspot.com/2009/03/flex-component-kit-cpu-black-hole.html">guys</a> at <a href="http://www.effectiveui.com/">EffectiveUI</a>.  <a href="http://patrickhansen.com/blog/index.php/2009/03/25/stateful-vs-stateless-now-vs-degrafa/">The most recent benchmarks</a> appear to show that stateful Degrafa skins (like those produced by the Degrafa Button Explorer) are safe to use.</p>
</blockquote>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_buttons/degrafa_buttons.swf', 'flashcontent-degrafa-buttons', '300', '90', '9.0.28', 'expressInstall.swf', false, { 'bgColor':'#ffffff', 'base':'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/03/degrafa-button-explorer/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
	</channel>
</rss>

