Source: teechart-animations.js

/**
 * @preserve TeeChart(tm) for JavaScript(tm)
 * @fileOverview TeeChart for JavaScript(tm)
 * v1.4 December 2012
 * Copyright(c) 2012 by Steema Software SL. All Rights Reserved.
 * http://www.steema.com
 *
 * Licensed with commercial and non-commercial attributes,
 * specifically: http://www.steema.com/licensing/html5
 *
 * JavaScript is a trademark of Oracle Corporation.
 */

/*global exports */

/**
 * @author <a href="mailto:david@steema.com">Steema Software</a>
 * @version 1.4
 */

/**
 * @namespace TeeChart namespace, contains all classes and methods.
 */
var Tee=Tee || {};

(function() {
 "use strict";

if (typeof exports !== 'undefined') exports.Tee=Tee;

/**
 * @returns {Number} Returns the integer part of value, without decimals, rounded to lower.
 */
function trunc(value) {
  return value | 0;
}

/**
 * @constructor
 * @augments Tee.Tool
 * @class Base abstract class to perform Animations.
 * @property {Number} [duration=500] Duration in milliseconds of the animation.
 * @property {boolean} [running=false] Read-only, returns if the animation is currently running.
 */
 /*
Tee.Animation=function(target, onstep) {
  Tee.Tool.call(this,target);

  this.active=true;
  this.mode="linear";
  this.duration=500;
  this.items=[];
  this.running=false;

  if (target)
    if (target instanceof Tee.Chart)
       this.chart=target;
    else
    if (target instanceof Tee.Animation) {
       this.chart=target.chart;
       target.items.push(this);
    }

  var o=null;

  this.animate=function(chart) {
    if (!this.running) {
      this.running=true;

      if (chart) this.chart=chart;

      this.init=new Date().getTime();

      o=this;

      o.start();
      for(var t=0, i; i=o.items[t++];) if (i.active) { i.chart=o.chart; i.start(); }

      o.chart.draw();
      requestAnimFrame(this.step, this);
    }
  }

  this.start=function() {}
  this.stop=function() {}

  this.doStep=function(f) { if (onstep) onstep(f); }

  this.step=function() {
    var now=new Date().getTime(),
        t, i, tmp=(now-o.init)/o.duration,
        f= o.mode=="linear" ? tmp : Math.pow(2,10*(tmp-1));

    if ((f>=0) && (f<1)) {
      o.doStep(f);

      for(t=0; i=o.items[t++];)
        if (i.active) {
          i.chart=o.chart;
          i.doStep(f);
        }

      o.chart.draw();
      requestAnimFrame(o.step,o);
    }
    else {
      o.stop();
      for(t=0; i=o.items[t++];) if (i.active) { i.chart=o.chart; i.stop(); }

      if (o.onstop) o.onstop(o);

      o.running=false;
      
      o.chart.draw();
    }
  }
}

Tee.Animation.prototype=new Tee.Tool;
*/

/**
 * @constructor
 * @augments Tee.Animation
 * @class Fades in/out chart elements.
 */
Tee.FadeAnimation=function(target) {
  Tee.Animation.call(this,target);

  this.kind="in"; // in, out

  var o=this, fa;

  this.fade={}

  this.setTransp=function(value) {

    if (o.kind=="out") value=1-value;

    if (fa.legend)
        o.chart.legend.format.transparency=value;

    if (fa.walls)
        o.chart.walls.transparency=value;

    if (fa.series)
        o.chart.series.each(function(s) { s.format.transparency=value; });

    if (fa.marks)
        o.chart.series.each(function(s) { s.marks.transparency=value; });

    if (fa.title)
        o.chart.title.format.transparency=value;

    if (fa.axes)
        o.chart.axes.transparency=value;

    if (fa.panel)
        o.chart.panel.format.transparency=value;
  }

  this.start=function() { fa=this.fade; this.setTransp(1); }
  this.stop=function() { this.setTransp(0); }
  this.doStep=function(f) { o.setTransp(1-f); }
}

Tee.FadeAnimation.prototype=new Tee.Animation();

/**
 * @constructor
 * @augments Tee.Animation
 * @class Animates series data
 * @property {Tee.Series} series Optional Tee.Series object to animate. When null, all series and axes are animated.
 * @property {String} [kind="axis"] Animation style. Can be: axis, left, top, right, bottom, x, y, each, all, zoomin, zoomout.
 */
Tee.SeriesAnimation=function(target) {
  Tee.Animation.call(this,target);

  if (target instanceof Tee.Series) {
    this.series=target;
    this.chart=target.chart;
  }
  else
    this.series=null;

  this.oldmin=0;
  this.oldmax=0;
  this.oldauto=true;

  var scaling=1, o=this;

  this.kind="axis"; // "left", "right", "top", "bottom", "axis", "x", "y", "zoomin", "zoomout", "each", "all"

  function changeAxis(o,a,amount) {
    a.automatic=false;
    var mid=(o.oldmin+o.oldmax)*0.5, range=(o.oldmax-o.oldmin)*0.5;
    a.maximum=mid+amount*range;
    a.minimum=mid-amount*range;
  }

 /**
  * @returns {Tee.Axis} Returns the mandatory axis of the animated series, or null
  * if no visible series exist.
  */
  this.getAxis=function() {
    var s=this.series || this.chart.series.firstVisible();
    return s ? s.mandatoryAxis : null;
  }

  this.doStep=function(f) {

    var a=o.getAxis();
    if (a) a.automatic=false;

    if (o.kind=="axis") {
       changeAxis(o,a,1+(1-f)*100);
    }
    else
    o.chart.series.each(function(s) {
      if (o.series && (o.series!==s)) return;

      var v=s.data.values, old=s.data._old, t, len=v.length;

      if (s instanceof Tee.Pie) {
        s.rotation=360*(1-f);
        scaling=f;
      }
      else
      if (o.kind=="each") {
       var stepf=trunc(len*f);

       for(t=0; t<stepf; t++) v[t]=old[t];

       if (stepf<len)
          v[stepf]=old[stepf]*((len*f)-stepf);
      }
      else
      if (o.kind=="all") {
       for(t=0; t<len; t++) v[t]=old[t]*f;
      }
      else
      if (o.kind!="axis") {
        scaling=f;
      }
    });
  }

  this.stop=function() {
    var a=o.getAxis();

    if (a) {
      a.maximum=o.oldmax;
      a.minimum=o.oldmin;
      a.automatic=o.oldauto;
    }

    o.chart.series.each(function(s) {
      if (s.transform)
         s.transform=null;

      if ((o.kind=="each") || (o.kind=="all"))
      if (s.data._old)
      {
         s.data.values=s.data._old;
         s.data._old=null;
      }
    });
  }

  this.start=function() {

    var a=this.getAxis(), c=this.chart, ss=c.series.items,
        w=c.chartRect.width, h=c.chartRect.height, t, s,
        ww=c.bounds.width, hh=c.bounds.height;

    if (ss.length===0)
      return false;

    this.oldmin=a.minimum;
    this.oldmax=a.maximum;
    this.oldauto=a.automatic;

    for (t=0; t<ss.length; t++) {
      s=ss[t];

      if (this.series && (this.series!==s)) continue;

      if (s instanceof Tee.Pie)
        s.transform=function() { this.chart.ctx.scale(scaling, scaling); }
      else
      if ((this.kind=="each") || (this.kind=="all")) {
        var v=s.data.values, tt, len=v.length;
        s.data._old=v.slice(0);
        for(tt=0; tt<len; tt++) v[tt]=0;
        a.automatic=false;
      }
      else
      if (this.kind=="left")
        s.transform=function() { this.chart.ctx.translate(-w*(1-scaling),0); }
      else
      if (this.kind=="right")
        s.transform=function() { this.chart.ctx.translate(w*(1-scaling),0); }
      else
      if (this.kind=="x")
        s.transform=function() { this.chart.ctx.scale(scaling, 1); }
      else
      if (this.kind=="y")
        s.transform=function() { this.chart.ctx.scale(1, scaling); }
      else
      if (this.kind=="top")
         s.transform=function() { this.chart.ctx.translate(0,-h*(1-scaling)); }
      else
      if (this.kind=="bottom")
         s.transform=function() { this.chart.ctx.translate(0,h*(1-scaling)); }
      else
      if (this.kind=="zoomin")
         s.transform=function() {
           var ctx=this.chart.ctx;
           ctx.translate(ww*0.5,hh*0.5);
           ctx.scale(scaling,scaling);
           ctx.translate(-ww*0.5,-hh*0.5);
         }
      else
      if (this.kind="zoomout")
         s.transform=function() {
           var ctx=this.chart.ctx;
           ctx.translate(ww*0.5,hh*0.5);
           ctx.scale(2-scaling,2-scaling);
           ctx.translate(-ww*0.5,-hh*0.5);
         }
    }

    if (this.kind=="axis")
       changeAxis(this,a,100);
  }
}

Tee.SeriesAnimation.prototype=new Tee.Animation();


/**
 * @constructor
 * @augments Tee.Animation
 * @class Animates Series marks items.
 */
Tee.MarksAnimation=function(target) {
  Tee.Animation.call(this,target);

  if (target && (target instanceof Tee.Series)) {
    this.series=target;
    this.chart=target.chart;
  }
  else
    this.series=null;

  this.current=-1;

  var m=this.series.marks, o=this, old;

  function marksText(series,index,result) {
    if (index<=o.current)
       return result;
    else
       return "";
  }

  this.start=function() {
     old=m.ongettext;
     m.ongettext=marksText;
  }

  this.stop=function() {
     m.ongettext=old;
     this.current=-1;
  }

  this.doStep=function(f) {
    o.current=trunc(o.series.data.values.length*f);
  }
}

Tee.MarksAnimation.prototype=new Tee.Animation();

}).call(this);