// JavaScript Document
//View image in a different window.


//***************************************************************
//The onclick handler of the thumbnail image creates a new ImageExpander object passing itself and the URL of the full size image as arguments.
//***************************************************************

function ImageExpander(oThumb, sImgSrc)

{

   // store thumbnail image and overwrite its onclick handler.

   this.oThumb = oThumb;

   this.oThumb.expander = this;

   this.oThumb.onclick = function() { this.expander.expand(); }

  

   // record original size

   this.smallWidth = oThumb.offsetWidth;

   this.smallHeight = oThumb.offsetHeight;    

 

   // initial settings

   this.bExpand = true;

   this.bTicks = false;

  

   // insert into self organized list

   if ( !window.aImageExpanders )

      window.aImageExpanders = new Array();

   window.aImageExpanders.push(this);

 

   // create the full sized image and automatically expand when loaded

   this.oImg = new Image();

   this.oImg.expander = this;

   this.oImg.onload = function(){this.expander.onload();}

   this.oImg.src = sImgSrc;

}

//***************************************************************
//Lastly, the full size image is loaded into a new Image object. The onload handler on the image is set to call the onload method on the //ImageExpander.
//The onclick handler of the thumbnail image creates a new ImageExpander object passing itself and the URL of the full size image as arguments.
//***************************************************************
 

ImageExpander.prototype.onload = function()

{

   this.oDiv = document.createElement("div");
 
   document.body.appendChild(this.oDiv);

   this.oDiv.appendChild(this.oImg);

   this.oDiv.style.position = "absolute";

   this.oDiv.expander = this;

   this.oDiv.onclick = function(){this.expander.toggle();};

   this.oImg.title = "Click to reduce.";

   this.bigWidth = this.oImg.width;

   this.bigHeight = this.oImg.height;

  

   if ( this.bExpand )

   {

      this.expand();

   }

   else

   {

      this.oDiv.style.visibility = "hidden";

      this.oImg.style.visibility = "hidden";

   }

}


//***************************************************************
//Now, it is possible that while the image was downloading, the user may have clicked on another thumbnail, so the this.bExpand flag must be //tested to see whether to go on with the expansion. If not, the image and its enclosing <div> are quickly hidden from view.

//The toggle method is called by the onclick handler of the full size image
//***************************************************************
 

ImageExpander.prototype.toggle = function()

{

   this.bExpand = !this.bExpand;

   if ( this.bExpand )

   {

      for ( var i in window.aImageExpanders )

         if ( window.aImageExpanders[i] !== this )

            window.aImageExpanders[i].reduce();

   }

}

//***************************************************************
//The expand method first sets the this.bExpand flag to true so that the animation engine knows which direction it is going and then forces all //other ImageExpander objects to reduce. 
//***************************************************************
ImageExpander.prototype.expand = function()

{

   // set direction of expansion.

   this.bExpand = true;

 

   // set all other images to reduce

   for ( var i in window.aImageExpanders )

      if ( window.aImageExpanders[i] !== this )

         window.aImageExpanders[i].reduce();

 

   // if not loaded, don't continue just yet

   if ( !this.oDiv ) return;

  

   // hide the thumbnail

   this.oThumb.style.visibility = "hidden";

  

   // calculate initial dimensions

   this.x = this.oThumb.offsetLeft;

   this.y = this.oThumb.offsetTop;

   this.w = this.oThumb.clientWidth;

   this.h = this.oThumb.clientHeight;

  

   this.oDiv.style.left = this.x + "px";

   this.oDiv.style.top = this.y + "px";

   this.oImg.style.width = this.w + "px";

   this.oImg.style.height = this.h + "px";

   this.oDiv.style.visibility = "visible";

   this.oImg.style.visibility = "visible";

  

   // start the animation engine.

   if ( !this.bTicks )

   {

      this.bTicks = true;

      var pThis = this;

      window.setTimeout(function(){pThis.tick();},25);    

   }

}

 
 //***************************************************************************
 //All that is needed to reduce an image is to set the this.bExpand flag to false.
 //**************************************************************************
 ImageExpander.prototype.reduce = function()

{

   // set direction of expansion.

   this.bExpand = false;

}

 
//*************************************************************
//The animation engine is contained in a single method of the ImageExpander object called tick. As its name suggests, this function is called //repeatedly at fast enough intervals to make the image movements it controls appear to be smooth.
//************************************************************* 

ImageExpander.prototype.tick = function()

{

   // calculate screen dimensions

   var cw = document.body.clientWidth;

   var ch = document.body.clientHeight;

   var cx = document.body.scrollLeft + cw / 2;

   var cy = document.body.scrollTop + ch / 2;

 
//**************************************************************************
 //If the image is expanding then the original dimensions of the image are taken and then reduced to fit the page if necessary:
//**************************************************************************
 

   // calculate target

   var tw,th,tx,ty;

   if ( this.bExpand )

   {

      // start with the full size dimensions

      tw = this.bigWidth;

      th = this.bigHeight;

 

      // reduce to fit the screen

      if ( tw > cw )

      {

         th *= cw / tw;

         tw = cw;

      } 

      if ( th > ch )

      {

         tw *= ch / th;

         th = ch;

      }

      // then center it on the page

      tx = cx - tw / 2;

      ty = cy - th / 2;

   }

 //Otherwise the current size and location of the thumbnail image are used. Note that if the browser window changes size, then the actual //position of the thumbnail can change accordingly, so this must be calculated for each tick.

   else

   {

      tw = this.smallWidth;

      th = this.smallHeight;

      tx = this.oThumb.offsetLeft;

      ty = this.oThumb.offsetTop;

   }

 
 
//**************************************************************************
//The algorithm below is contained inside a nested function which is assigned to the variable fMove. This function operates on each dimension //and does two things: it calculates the value 10% closer to the target and counts the dimensions that a getting very close to the target value
// – less than three pixels away. This count is declared outside the function but it is still accessible as nested functions have access to the
// context in which they are defined.

 //**************************************************************************

   // move 10% closer to target

   var nHit = 0;

   var fMove = function(n,tn)

   {

      var dn = tn - n;

      if ( Math.abs(dn) < 3 )

      {

         nHit++;

         return tn;

      }

      else

      {

         return n + dn / 10;

      }

   }

   this.x = fMove(this.x, tx);

   this.y = fMove(this.y, ty);

   this.w = fMove(this.w, tw);

   this.h = fMove(this.h, th);

  

   this.oDiv.style.left = this.x + "px";

 //  this.oDiv.style.top = this.y + "px";

   this.oImg.style.width = this.w + "px";

   this.oImg.style.height = this.h + "px";


   // if reducing and size/position is a match, stop the tick   

   if ( !this.bExpand && (nHit == 4) )

   {

      this.oImg.style.visibility = "hidden";

      this.oDiv.style.visibility = "hidden";

      this.oThumb.style.visibility = "visible";

 

      this.bTicks = false;

   }

///Finally, if still active, the animation engine schedules another tick a short time in the future.

   if ( this.bTicks )

   {

      var pThis = this;

      window.setTimeout(function(){pThis.tick();},25);

   }

}
