
/* ============================================ *
 * Clase: ColorTransition                       *
 * Autor: Luis del Canto                        *
 * Fecha: 23 de Octubre de 2007                 *
 * Finalidad: Implementar transición cromática  *
 *            del color de fondo de un objeto   *
 * Todos los derechos reservados © ESTYGYA 2007 *
 * ============================================ */

// Número de pasos por transición
var STEPS = 20;

// Número de mili-segundos por paso
var MS_PER_STEP = 2;

// Lista de transiciones activas
var currentTx = new Array();


function d2h(d) {
  return d.toString(16);
}

function h2d(h) {
  return parseInt(h,16);
}

function lpad (val, numpos) {
  var ret = val;
  while (ret.length < numpos) {
    ret = '0' + ret;
  }
  return ret;
}

function fitVal (val) {
  var res = parseInt(val);
  if (res < 0) return 0;
  else if (res > 255) return 255;
  else return res;
}


// Constructor de color RGB
function Color (val) {
  this.color = val;
  this.red = -1;
  this.green = -1;
  this.blue = -1;
  
  if (val.indexOf('#') == 0) {
     var decVal = h2d(val.substr(1));
     this.red = parseInt(decVal / 65536);
     var aux = decVal % 65536;
     this.green = parseInt(aux / 256);
     this.blue = aux % 256;
  } else if (val.indexOf('rgb') == 0) {
     eval('this.' + val);
  }
}

// Truco para leer colores en formato rgb(r,g,b)
Color.prototype.rgb = function (r,g,b) {
  this.red = r;
  this.green = g;
  this.blue = b;
}


// Función que convierte a color hexa
function toColor (r,g,b) {
  var ret = '#'
    + lpad(d2h(r), 2)
    + lpad(d2h(g), 2)
    + lpad(d2h(b), 2);
  return ret;
}


// Constructor de la transición de colores
function ColorTransition (o, colorFin) {

  // Si hay transición activa...
  var prevCt = currentTx[o.id];
  if (prevCt != null) {
     // La detenemos
     window.clearInterval(prevCt.intervalo);
  }

  // Obtenemos color inicial del objeto en Hexa
  var colorIni = o.style.backgroundColor;

  // Obtenemos los componentes de color de inicio y fin
  var c_ini = new Color(colorIni);
  var c_fin = new Color(colorFin);

  // Objeto afectado por la transición
  this.componente = o;

  // Color actual
  this.curRed = c_ini.red;
  this.curGreen = c_ini.green;
  this.curBlue = c_ini.blue;

  // Calculamos el valor de paso de cada color
  this.stepRed = (c_fin.red - c_ini.red) / STEPS;
  this.stepGreen = (c_fin.green - c_ini.green) / STEPS;
  this.stepBlue = (c_fin.blue - c_ini.blue) / STEPS;

  // Temporizador
  this.intervalo = -1;

  // Paso actual
  this.numStep = 0;
}


// Metodo de paso de la transición
ColorTransition.prototype.step = function() {

  // Sumamos el paso a cada componente del color actual
  this.curRed += this.stepRed;
  this.curGreen += this.stepGreen;
  this.curBlue += this.stepBlue;

  // Calculamos el color resultante
  var newColor = toColor(fitVal(this.curRed),
			fitVal(this.curGreen),
			fitVal(this.curBlue)
			);

  // Asignamos nuevo color al objeto
  this.componente.style.backgroundColor = newColor;

  // Incrementamos el número de paso
  this.numStep++;

  // Se han hecho todos los paso, paramos intervalo
  if (this.numStep == STEPS) {
     this.stop();
  }
}


// Metodo para saber si quedan pasos
ColorTransition.prototype.hasNext = function() {
  return (this.numStep < STEPS);
}


// Metodo para iniciar la transición
ColorTransition.prototype.start = function() {
  var id = this.componente.id;
  // Añadimos a la lista de transiciones activas
  currentTx[id] = this;
  // Iniciamos temporizador
  this.intervalo = window.setInterval("stepColor('" + id + "')", MS_PER_STEP);
}


// Metodo para detener la transición
ColorTransition.prototype.stop = function() {
  window.clearInterval(this.intervalo);
}


// Callback para la transición
function stepColor (id) {
  
  var ct = currentTx[id];
  if (ct == null) return;

  // Mientras queden pasos
  if (ct.hasNext()) {
     ct.step();
  }
}


