<?xml version="1.0" encoding="utf-8"?>
<mx:Application
    xmlns:mx="http://www.adobe.com/2006/mxml"
    xmlns="http://www.degrafa.com/2007"
    layout="absolute"
    width="600" height="500" 
    pageTitle="Degrafa Natural Cubic Spline Demo 2"
    applicationComplete="test()" xmlns:degrafa="http://www.degrafa.com/2007" viewSourceURL="srcview/index.html">
    
     <mx:Style source="assets/style/style.css"/>
     <mx:Canvas id="background" x="50" y="90" width="500" height="400" backgroundColor="#FFFFFF" >
          <mx:Button x="10" y="378" label="Animate" id="__animate__" enabled="true" click="__onAnimate()"/>
     </mx:Canvas>
     <mx:Label text="Natural Cubic Spline 2" x="250" y="30" width="300" styleName="title"/>
    
     <mx:Canvas id="gridLayer" />
     <mx:Canvas id="splineLayer" />
     <mx:Canvas id="splineOverlay" />
     <mx:Canvas id="splineAnimation" />
     <mx:Canvas id="knots" />
     
  <NaturalCubicSpline id="cubicSpline" graphicsTarget="{[splineLayer]}" knots="104,299 166,168 217,236 307,225 370,142 440,299 506,309" >
    <stroke> 
     <SolidStroke weight="2" color="#0000FF"/>
    </stroke>
     </NaturalCubicSpline>
    
    <mx:Script>
      <![CDATA[
        import com.degrafa.geometry.splines.QuadData;
        import com.degrafa.core.collections.GraphicPointCollection;
        import com.degrafa.GraphicPoint;
        
        import com.degrafa.events.DegrafaEvent;
        
        private var __count:uint  = 0;
        private var __quads:Array = null;
        
        // this delta is hardcoded to the graph range
        private var __delta:Number = 10;
        private var __curX:Number  = 0;
        
        private function test():void
        {
          // simulate a simple grid and some axes
          __drawGrid();
          
          // access the point collection and highlight the knots
          var points:Array = cubicSpline.points;
          var g:Graphics   = knots.graphics;
          g.lineStyle(1,0x000000);
          g.beginFill(0x00ff00);
          for( var i:uint=0; i<points.length; ++i )
          {
            var p:GraphicPoint = points[i];
            g.drawCircle(p.x, p.y, 4);
          }
          
          // the quad approximation data is not ready until after the spline has been rendered, so wait for it ...
          cubicSpline.addEventListener(DegrafaEvent.RENDER, __onSplineCreation);
        }
        
        private function __onSplineCreation(_event:DegrafaEvent):void
        {
          if( __quads == null )
          {
            __quads = cubicSpline.quadApproximation;
            
            // begin by highlighting the entire area under the graph
            __highlight();
          }
        }
        
        // draw a simple (partial) grid and some axes
        private function __drawGrid():void
        {
          var g:Graphics = gridLayer.graphics;
          g.lineStyle(2,0x000000);
          g.moveTo(60,100);
          g.lineTo(60,450);
       g.lineTo(540,450);          
          
          g.lineStyle(1,0x000000,0.2);
          for( var i:Number=1; i<7; ++i )
          {
            var myX:Number = 60 + i*80;
            g.moveTo(myX,100);
            g.lineTo(myX,450);
          }

       for( i=0; i<7; ++i )
          {
            var myY:Number = 100 + i*50;
            g.moveTo(60 ,myY);
            g.lineTo(540,myY);
          }
        }
        
        // highlight entire area under graph
        private function __highlight():void
        {
          if( __quads == null )
            return;
            
          // this is all hardcoded to the grid lines and specific number of spline sections; typical quick-and-dirty example, so don't change the grid or number of data points
          // and expect it to work :)
          var g:Graphics = splineOverlay.graphics;
          g.clear();
          
          var data:Array    = __quads[0];
          var indices:Array = __quads[1];
           
          __sectionsUpTo(g, data, indices, 6);
        }
        
        private function __sectionsUpTo(_canvas:Graphics, _data:Array, _indices:Array, _section:uint):void
        {
          if( _section == 0 )
            return;
            
          _canvas.lineStyle(1, 0x0000ff);
          _canvas.beginFill(0x0000ff, 0.2);
          
          var total:uint = _data.length;
          var q:QuadData = _data[0];
          _canvas.moveTo(q.x0, q.y0);
       
          for( var i:uint=0; i<_section; ++i )
          {
            var quads:uint = i == 5 ? total - _indices[i] : _indices[i+1]-_indices[i];
            var start:int  = _indices[i];
            for( var j:uint=0; j<quads; ++j )
            {
              q = _data[start+j];
              
              _canvas.curveTo(q.cx, q.cy, q.x1, q.y1);
            }
          }
            
          _canvas.lineTo(q.x1,450);
            
          q = _data[0];
          _canvas.lineTo(q.x0,450);
          _canvas.moveTo(q.x0,100);
            
          _canvas.endFill();
        }
        
        private function __onAnimate():void
        {
          __animate__.enabled = false;
          
          // this is hardcoded to the current knot set - as an exercise, use the points accessor and make it more general-purpose
          __curX = 104;
          knots.addEventListener(Event.ENTER_FRAME, __animateArea);
        }
        
        private function __animateArea(_e:Event):void
        {
          __curX += __delta;
          if( __curX < 506 )
          {
         __drawFill(__curX);
          }
          else
          {
            __drawFill(506);
            
            knots.removeEventListener(Event.ENTER_FRAME, __animateArea);
            __animate__.enabled = true;
          }
        }
        
        private function __drawFill(_x:Number):void
        {
          var q:Array    = cubicSpline.approximateInterval(104, _x);
          var g:Graphics = splineAnimation.graphics;
          g.clear();
          g.lineStyle(2,0x00ff00);
          g.beginFill(0x00ff00,0.8);
            
          var qb:QuadData = q[0];
          var x0:Number   = qb.x0;
          var y0:Number   = qb.y0;
          g.moveTo(x0, y0);
          
          for( var i:uint=0; i<q.length; ++i )
          {
            qb = q[i];
           
            g.curveTo(qb.cx, qb.cy, qb.x1, qb.y1 );
          }
          
          // yikes ... more hardcoding ... time is short :)
          g.lineTo(qb.x1, 450);
          g.lineTo(x0   , 450);
          g.lineTo(x0   , y0 );
          
          g.endFill();
        }
        
      ]]>
    </mx:Script>

</mx:Application>