<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    layout="absolute"
    creationComplete="init()"
    viewSourceURL="srcview/index.html">
<mx:Style source="css/style.css" />    
<mx:Script>
    <![CDATA[
/* -----------------------------------------------------------------------
CUSTOM EASING FUNCTION EXPLORER v 1.0.0 por Raúl Díaz para madeinflex.com
------------------------------------------------------------------------ */

    private var offset:Number;
    private var scale:Number;
        
    private var x1:Number;
    private var x2:Number;
    private var x3:Number;
    private var x4:Number;

    private var g:Graphics;
    
    private var xoffset:Number;
    private var yoffset:Number;
    
    private var activateMove:Boolean=false;

    [Bindable] private var max:Number;
    [Bindable] private var min:Number;
    [Bindable] private var labels:Array;
    [Bindable] private var composedFunction:String;

    [Bindable]
    public var presets:Array = [ 
        {label:"no easing", a:0, b:0, c:0, d:0, e:1},
        {label:"in-out cubic", a:0, b:0, c:-2, d:3, e:0},
        {label:"in-out quintic", a:6, b:-15, c:10, d:0, e:0},
        {label:"in quintic", a:1, b:0, c:0, d:0, e:0},
        {label:"in quartic", a:0, b:1, c:0, d:0, e:0},
        {label:"in cubic", a:0, b:0, c:1, d:0, e:0},
        {label:"in quadratic", a:0, b:0, c:0, d:1, e:0},
        {label:"out quintic", a:1, b:-5, c:10, d:-10, e:5},
        {label:"out quartic", a:0, b:-1, c:4, d:-6, e:4},
        {label:"out cubic", a:0, b:0, c:1, d:-3, e:3},
        {label:"out-in cubic", a:0, b:0, c:4, d:-6, e:3},
        {label:"out-in quartic", a:0, b:0, c:6, d:-9, e:4},
        {label:"back in cubic", a:0, b:0, c:4, d:-3, e:0},
        {label:"back in quartic", a:0, b:2, c:2, d:-3, e:0},
        {label:"out back cubic", a:0, b:0, c:4, d:-9, e:6},
        {label:"out back quartic", a:0, b:-2, c:10, d:-15, e:8},
        {label:"out elastic (small)", a:33, b:-106, c:126, d:-67, e:15},
        {label:"out elastic (big)", a:56, b:-175, c:200, d:-100, e:20},
        {label:"in elastic (small)", a:33, b:-59, c:32, d:-5, e:0},
        {label:"in elastic (big)", a:56, b:-105, c:60, d:-10, e:0}
        ];


    private function init():void{

        max=1000;
        min=max*-1;
        //        labels=[min,max];
        p0.value=max*0.42;
        p1.value=max*0.44;
        p2.value=max*0.44;
        p3.value=max*0.56;
        p4.value=max*0.56;
        p5.value=max*0.58;

        // handles control points location 
        offset=p0.value;
        scale=p5.value-p0.value;
        
        g=gr.graphics;
        xoffset=gr.width/2;
        yoffset=gr.height/2
        
        img.x=this.width-img.width;
        
        drawAxis();
        update();
        
        blurImg.play();
        this.addEventListener(MouseEvent.CLICK,ctlMoveImg);
        genChartData();
        
        presetsCombo.selectedIndex=16;
        reverseUpdate(presetsCombo.selectedItem);
    }
    private function drawAxis(e:Event=null):void{
        xoffset=gr.width/2;
        yoffset=gr.height/2

        var ag:Graphics=axis.graphics;
        ag.clear();
        ag.lineStyle(1);
        ag.moveTo(0,yoffset);
            ag.lineTo(axis.width,yoffset);
        ag.moveTo(xoffset,0);
            ag.lineTo(xoffset,axis.height);
    }
    // update data based on control points location
    private function update():void{

        offset=p0.value;
        scale=p5.value-p0.value;

        // calculate new parameters
        var o:Object = getParameters();
        // update curve
        plot( getBezierFunc(o.a, o.b, o.c, o.d, o.e) );
        composedFunction="function(t:Number, b:Number, c:Number, d:Number):Number {<br>&nbsp;&nbsp;var ts:Number=(t/=d)*t;<br>&nbsp;&nbsp;var tc:Number=ts*t;<br>&nbsp;&nbsp;return b+c*("+Number(a_val.text)+"*tc*ts + "+Number(b_val.text)+"*ts*ts + "+Number(c_val.text)+"*tc + "+Number(d_val.text)+"*ts + "+Number(e_val.text)+"*t);<br>}";
    }
    // update data based on polynomial coefficient
    private function reverseUpdate(o:Object):void{
        x1 = o.e / 5;
        x2 = (o.d+4*o.e)/10;
        x3 = (o.c + 6*o.e + 3*o.d)/10;
        x4 = (o.b + 4*o.e + 3*o.d + 2*o.c)/5;

        p1.value  = (x1 * scale) + offset;
        p2.value  = (x2 * scale) + offset;
        p3.value  = (x3 * scale) + offset;
        p4.value  = (x4 * scale) + offset;

        p1_val.text = x1.toString();
        p2_val.text = x2.toString();
        p3_val.text = x3.toString();
        p4_val.text = x4.toString();

        plot( getBezierFunc(o.a, o.b, o.c, o.d, o.e) );
        composedFunction="function(t:Number, b:Number, c:Number, d:Number):Number {<br>&nbsp;&nbsp;var ts:Number=(t/=d)*t;<br>&nbsp;&nbsp;var tc:Number=ts*t;<br>&nbsp;&nbsp;return b+c*("+Number(a_val.text)+"*tc*ts + "+Number(b_val.text)+"*ts*ts + "+Number(c_val.text)+"*tc + "+Number(d_val.text)+"*ts + "+Number(e_val.text)+"*t);<br>}";
    }
    
    // Dibujar la función
    private function plot(func:Function, mode:Boolean=false):void{
        drawAxis();
        g.clear();
        g.lineStyle(2);
        g.moveTo(xoffset,yoffset);
        for (var x:Number=0; x<1; x+=0.01) {
            x = Math.round(100*x) / 100;
            g.lineTo(x*100 + 1 +xoffset, -func(x+0.01)*100 +yoffset );
            if (mode) x+=0.01;
        }
    }
    private function getParameters():Object{
        x1 = (p1.value - offset) / scale;
        x2 = (p2.value - offset) / scale;
        x3 = (p3.value - offset) / scale;
        x4 = (p4.value - offset) / scale;

        p1_val.text = x1.toString();
        p2_val.text = x2.toString();
        p3_val.text = x3.toString();
        p4_val.text = x4.toString();
    
        return getStdParameters(0, x1, x2, x3, x4, 1);    
    }
    // calculate bezier polynomials based on control points' location
    private function getStdParameters(c0:Number, c1:Number, c2:Number, c3:Number, c4:Number, c5:Number):Object {
        var e:Number = 5 *(c1 - c0);
        var d:Number = 10*(c2 - c0) - 4*e;
        var c:Number = 10*(c3 - c0) + 30*(c1 - c2);
        var b:Number = 5 *(c4 + c0) - 20*(c3 + c1) + 30*c2;
        var a:Number = c5 - c0 - b - c - d - e;
        return {a:a, b:b, c:c, d:d, e:e};
    }
    // return the bezier function to pass to the graph
    private function getBezierFunc(a:Number, b:Number, c:Number, d:Number, e:Number):Function {
        a_val.text = a.toString();
        b_val.text = b.toString();
        c_val.text = c.toString();
        d_val.text = d.toString();
        e_val.text = e.toString();

        return function(t:Number):Number { 
            var ts:Number = t*t;
            var tc:Number = ts*t;
            return a*tc*ts + b*ts*ts + c*tc + d*ts + e*t;
        }
    }
    private function ctlMoveImg(e:MouseEvent):void{
        if( activateMove ){
            moveEffect.xTo=this.mouseX;
            moveEffect.yTo=this.mouseY;
            moveEffect.play();
        }
    }
    private function ctlClickImg(e:MouseEvent):void{
        activateMove=!activateMove;
        if( activateMove ){
            unblurImg.play();
        }else{
            blurImg.play();
        }
        e.stopPropagation();
    }
    private function myEasingFunction(t:Number, b:Number, c:Number, d:Number):Number {
        var ts:Number=(t/=d)*t;
        var tc:Number=ts*t;
        return b+c*( Number(a_val.text)*tc*ts + Number(b_val.text)*ts*ts + Number(c_val.text)*tc + Number(d_val.text)*ts + Number(e_val.text)*t);
    }
// ************************************************************************************************************
    [Bindable] public var dataSet:Array;
    private function genChartData():void
    {
        var newData:Array = [];
        var A:Number = Math.random()*100 - 50;
        var B:Number = A - Math.random() * 10;
        var P:Number = Math.random()*100;
        for(var i:int = 0; i < 20; i++)
        {
            A = A + Math.random() * 10 - 5;
            B = A - Math.random() * 10;
            P = Math.random() * 100;
            newData.push(
            {
                A: A,
                B: B,
                P: P
            }
            );
        }
        dataSet = newData;
    }    
// ************************************************************************************************************
    ]]>
</mx:Script>
<mx:SeriesInterpolate id="seriesEffect" duration="2000" easingFunction="{myEasingFunction}"/>
<mx:Move
    id="moveEffect" 
    target="{img}"
    duration="{effectDuration.value}" 
    easingFunction="myEasingFunction"/>
<mx:Blur id="blurImg" duration="1000" target="{img}"
        blurXFrom="0.0" blurXTo="10.0" 
        blurYFrom="0.0" blurYTo="10.0"/>    
<mx:Blur id="unblurImg" duration="1000" target="{img}"
        blurXFrom="10.0" blurXTo="0.0" 
        blurYFrom="10.0" blurYTo="0.0"/>
<mx:Box
    width="100%"
    height="100%"
    paddingLeft="7"
    paddingRight="7"
    paddingBottom="27">
<!--
**************************************************************************************************************
    HEADER
**************************************************************************************************************
-->        
    <mx:HBox verticalAlign="middle" paddingLeft="10">
        <mx:Image source="@Embed('assets/efeLogo.png')" />
        <mx:Label text="Custom Easing Function Explorer" styleName="efeTitle">
            <mx:filters>
                <flash.filters:DropShadowFilter xmlns:flash.filters="flash.filters.*" angle="90" blurX="5" blurY="5" distance="2" alpha=".3" color="0x000000" />
              </mx:filters>
        </mx:Label>
        <mx:Box height="20" verticalAlign="bottom" >
            <mx:Label text="v 1.0.0" fontFamily="Myriad" color="#FFFFFF" fontSize="8" />    
        </mx:Box>        
        
    </mx:HBox>
<!--
**************************************************************************************************************
    PARAMETERS
**************************************************************************************************************
-->        
    <mx:TabNavigator
        width="100%"
        height="100%">
        <mx:Box    label="Parameters"
            paddingRight="7"
            paddingBottom="7">
            <mx:HBox width="100%">
                <mx:VBox width="100%">
                    <mx:HBox>
                        <mx:Label text="P0"/>
                        <mx:TextInput id="p0_val" enabled="false" text="0"/>
                        <mx:Spacer width="40"/>
                        <mx:TextInput id="a_val" enabled="false"/>
                        <mx:Label text="t5"/>
                    </mx:HBox>
                    <mx:HBox>
                        <mx:Label text="P1"/>
                        <mx:TextInput id="p1_val" enabled="false"/>
                        <mx:Spacer width="40"/>
                        <mx:TextInput id="b_val" enabled="false"/>
                        <mx:Label text="t4"/>
                    </mx:HBox>
                    <mx:HBox>
                        <mx:Label text="P2"/>
                        <mx:TextInput id="p2_val" enabled="false"/>
                        <mx:Spacer width="40"/>
                        <mx:TextInput id="c_val" enabled="false"/>
                        <mx:Label text="t3"/>
                    </mx:HBox>
                    <mx:HBox>
                        <mx:Label text="P3"/>
                        <mx:TextInput id="p3_val" enabled="false"/>
                        <mx:Spacer width="40"/>
                        <mx:TextInput id="d_val" enabled="false"/>
                        <mx:Label text="t2"/>
                    </mx:HBox>
                    <mx:HBox>
                        <mx:Label text="P4"/>
                        <mx:TextInput id="p4_val" enabled="false"/>
                        <mx:Spacer width="40"/>
                        <mx:TextInput id="e_val" enabled="false"/>
                        <mx:Label text="t"/>
                    </mx:HBox>
                </mx:VBox>
                <mx:VBox width="100%" height="100%">
                    <mx:Label text="Custom Easing function:"/>
                    <mx:TextArea
                        id="functionText"
                        width="100%"
                        height="100%"
                        htmlText="{composedFunction}"
                        styleName="functionTextStyle">
                    </mx:TextArea>
                </mx:VBox>
            </mx:HBox>    
            <mx:Box    width="100%">
                <mx:HBox width="100%">
                    <mx:VBox width="50%">
                        <mx:Label text="Effect duration (milliseconds):"/>
                        <mx:HSlider id="effectDuration" width="50%" minimum="100" maximum="10000" value="3000" toolTip="{effectDuration.value} milliseconds"/>
                    </mx:VBox>
                    <mx:VBox width="50%">
                        <mx:Label text="Easing presets:"/>
                        <mx:ComboBox id="presetsCombo" dataProvider="{presets}" width="150" close="reverseUpdate(ComboBox(event.target).selectedItem)"/>
                    </mx:VBox>
                </mx:HBox>        
                <mx:Label text="Control points graphical relative positions:"/>
                <mx:HSlider id="p0" maximum="{max}" minimum="{min}" labels="{labels}" toolTip="offset = {p0.value}" change="update()" tickColor="black" snapInterval="1" tickInterval="10" allowTrackClick="true" liveDragging="true" width="100%"/>
                <mx:HSlider id="p1" maximum="{max}" minimum="{min}" labels="{labels}" toolTip="P1 = {p1.value}" change="update()" tickColor="black" snapInterval="1" tickInterval="10" allowTrackClick="true" liveDragging="true" width="100%"/>
                <mx:HSlider id="p2" maximum="{max}" minimum="{min}" labels="{labels}" toolTip="P2 = {p2.value}" change="update()" tickColor="black" snapInterval="1" tickInterval="10" allowTrackClick="true" liveDragging="true" width="100%"/>
                <mx:HSlider id="p3" maximum="{max}" minimum="{min}" labels="{labels}" toolTip="P3 = {p3.value}" change="update()" tickColor="black" snapInterval="1" tickInterval="10" allowTrackClick="true" liveDragging="true" width="100%"/>
                <mx:HSlider id="p4" maximum="{max}" minimum="{min}" labels="{labels}" toolTip="P4 = {p4.value}" change="update()" tickColor="black" snapInterval="1" tickInterval="10" allowTrackClick="true" liveDragging="true" width="100%"/>
                <mx:HSlider id="p5" maximum="{max}" minimum="{min}" labels="{labels}" toolTip="P5 = {p5.value}" change="update()" tickColor="black" snapInterval="1" tickInterval="10" allowTrackClick="true" liveDragging="true" width="100%"/>
            </mx:Box>
            <mx:Box
                width="100%"
                height="100%"
                id="axis"
                backgroundColor="#E67300"
                backgroundAlpha="0.2">
                <mx:Box
                    width="100%"
                    height="100%"
                    id="gr"/>
        
            </mx:Box>
        </mx:Box>
<!--
**************************************************************************************************************
    EXPLORER
**************************************************************************************************************
-->        
        <mx:Box
            label="Explorer"
            paddingRight="7"
            paddingBottom="7">
                <mx:Panel
                    title="Custom Easing Function on Series Interpolation in a chart"
                    width="100%"
                    height="100%"
                    borderAlpha="0.2"
                    backgroundAlpha="0.2"
                    titleStyleName="panelStyle"
                    color="#B35A00"
                    horizontalAlign="center">
                
                    <mx:Accordion width="100%" height="100%" backgroundAlpha="0" openEasingFunction="{myEasingFunction}" openDuration="1500" creationPolicy="all">
                        <mx:VBox width="100%" height="100%" label="Column">    
                            <mx:ColumnChart width="100%" height="100%" dataProvider="{dataSet}">
                                <mx:series>
                                    <mx:ColumnSeries showDataEffect="{seriesEffect}" yField="A"/>
                                </mx:series>
                            </mx:ColumnChart>
                        </mx:VBox>                
                        <mx:VBox width="100%" height="100%" label="Pie">        
                            <mx:PieChart width="100%" height="100%" dataProvider="{dataSet}">
                                <mx:series>
                                    <mx:PieSeries showDataEffect="{seriesEffect}" field="P"/>
                                </mx:series>
                            </mx:PieChart>
                        </mx:VBox>                
                        <mx:VBox width="100%" height="100%" label="Line">        
                            <mx:LineChart width="100%" height="100%" dataProvider="{dataSet}">
                                <mx:series>
                                    <mx:LineSeries showDataEffect="{seriesEffect}" yField="A"/>
                                </mx:series>
                            </mx:LineChart>
                        </mx:VBox>                
                        <mx:VBox width="100%" height="100%" label="Bubble">        
                            <mx:BubbleChart width="100%" height="100%" dataProvider="{dataSet}">
                                <mx:series>
                                    <mx:BubbleSeries showDataEffect="{seriesEffect}" xField="A" yField="B" radiusField="P"/>
                                </mx:series>
                            </mx:BubbleChart>
                        </mx:VBox>
                    </mx:Accordion>
                    <mx:Button label="Change Data Set" click="genChartData()"/>
                </mx:Panel>
        </mx:Box>
<!--
**************************************************************************************************************
    LINKS
**************************************************************************************************************
-->        
        <mx:Box
            label="Links"
            width="100%"
            height="100%"
            horizontalAlign="center"
            verticalAlign="middle"
            styleName="linksStyle">
            <mx:Label text="This explorer is based on..."/>
            <mx:LinkButton
                label="Easing Funcion Generator by Timothée Groleau" 
                click="navigateToURL(new URLRequest('http://timotheegroleau.com/Flash/experiments/easing_function_generator.htm'));"/>
            <mx:LinkButton
                label="Fun with Easing Functions Demo by James Ward" 
                click="navigateToURL(new URLRequest('http://www.jamesward.org/easingFunctionFun/easingFunctionFun.html'));"/>
            <mx:LinkButton
                label="Creating a custom easing function chapter on Flex 2 Developer's Guide by Adobe" 
                click="navigateToURL(new URLRequest('http://livedocs.adobe.com/flex/201/html/behaviors_068_28.html#218121'));"/>
            <mx:LinkButton
                label="Tutorial de ecuaciones de easing y transiciones de Flash on Cristalab" 
                click="navigateToURL(new URLRequest('http://www.cristalab.com/tutoriales/58/tutorial-de-ecuaciones-de-easing-y-transiciones-de-flash'));"/>

            <mx:Label text="...thanks folks."/>    

        </mx:Box>
    </mx:TabNavigator>    
</mx:Box>    

<mx:Image
    id="img"
    source="@Embed('assets/miflogo.gif')"
    buttonMode="true"
    click="ctlClickImg(event)"
    toolTip="Click to activate/deactivate move effect, when activated: click on any canvas position to start effect."/>
<mx:LinkButton
    bottom="2"
    left="7"
    label="Creado por Raúl Díaz [rdiaz@ccoo-uar.com] para madeinflex.com" 
    click="navigateToURL(new URLRequest('http://www.madeinflex.com/'));"
    styleName="footerLink"
    alpha="0.2"/>
</mx:Application>