Top
Home
*** Your Title Here ***

<link href="http://www.jqueryscript.net/css/jquerysctipttop.css" rel="stylesheet" type="text/css">
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<script src="moosespin.js" type="text/javascript"></script>
<style type="text/css">
.spritespin-preload {
background : url('stylesheets/images/ajax-loader.gif') no-repeat 50% 50%;
}
.spritespin-instance {
}
</style>


<div class="jquery-script-clear"></div>
</div>
</div>

<div id="360frames"></div>


<div id="panorama"></div>


<div id="gallery"></div>

<script type="text/javascript">
   $(function(){
     var frames = [
"001.jpg",
"002.jpg",
"003.jpg",
"004.jpg",
"005.jpg",
"006.jpg",
"007.jpg",
"008.jpg",
"009.jpg",
"010.jpg",
"011.jpg",
"012.jpg",
"013.jpg",
"014.jpg",
"015.jpg",
"016.jpg",
"017.jpg",
"018.jpg",
"019.jpg",
"020.jpg",
"021.jpg",
"022.jpg",
"023.jpg",
"024.jpg",
"025.jpg",
"026.jpg",
"027.jpg",
"028.jpg",
"029.jpg",
"030.jpg",
"031.jpg",
"032.jpg",
"033.jpg",
"034.jpg",
"035.jpg",
"036.jpg",
"037.jpg",
"038.jpg",
"039.jpg",
"040.jpg",
"041.jpg",
"042.jpg",
"043.jpg",
"044.jpg",
"045.jpg",
"046.jpg",
"047.jpg",
"048.jpg",
"049.jpg",
"050.jpg",
"051.jpg",
"052.jpg",
"053.jpg",
"054.jpg",
"055.jpg",
"056.jpg",
"057.jpg",
"058.jpg",
"059.jpg",
"060.jpg",
"061.jpg",
"062.jpg",
"063.jpg",
"064.jpg",
"065.jpg",
"066.jpg",
"067.jpg",
"068.jpg",
"069.jpg",
"070.jpg",
"071.jpg",
"072.jpg",
"073.jpg",
"074.jpg",
"075.jpg",
"076.jpg",
"077.jpg",
"078.jpg",
"079.jpg",
"080.jpg",
"081.jpg",
"082.jpg",
"083.jpg",
"084.jpg",
"085.jpg",
"086.jpg",
"087.jpg",
"088.jpg",
"089.jpg",
"090.jpg",
"091.jpg",
"092.jpg",
"093.jpg",
"094.jpg",
"095.jpg",
"096.jpg",
"097.jpg",
"098.jpg",
"099.jpg",
"100.jpg",
"101.jpg",
"102.jpg",
"103.jpg",
"104.jpg",
"105.jpg",
"106.jpg",
"107.jpg",
"108.jpg",
"109.jpg",
"110.jpg",
"111.jpg",
"112.jpg",
"113.jpg",
"114.jpg",
"115.jpg",
"116.jpg",
"117.jpg",
"118.jpg",
"119.jpg",
"120.jpg",
"121.jpg",
"122.jpg",
"123.jpg",
"124.jpg",
"125.jpg",
"126.jpg",
"127.jpg",
"128.jpg",
"129.jpg",
"130.jpg",
"131.jpg",
"132.jpg",
"133.jpg",
"134.jpg",
"135.jpg",
"136.jpg",
"137.jpg",
"138.jpg",
"139.jpg",
"140.jpg",
"141.jpg",
"142.jpg",
"143.jpg",
"144.jpg",
"145.jpg",
"146.jpg",
"147.jpg",
"148.jpg",
"149.jpg",
"150.jpg",
"151.jpg",
"152.jpg",
"153.jpg",
"154.jpg",
"155.jpg",
"156.jpg",
"157.jpg",
"158.jpg",
"159.jpg",
"160.jpg",
"161.jpg",
"162.jpg",
"163.jpg",
"164.jpg",
"165.jpg",
"166.jpg",
"167.jpg",
"168.jpg",
"169.jpg",
"170.jpg",
"171.jpg",
"172.jpg",
"173.jpg",
"174.jpg",
"175.jpg",
"176.jpg",
"177.jpg",
"178.jpg",
"179.jpg",
"180.jpg",
"181.jpg",
"182.jpg",
"183.jpg",
"184.jpg",
"185.jpg",
"186.jpg",
"187.jpg",
"188.jpg",
"189.jpg",
"190.jpg",
"191.jpg",
"192.jpg",
"193.jpg",
"194.jpg",
"195.jpg",
"196.jpg",
"197.jpg",
"198.jpg",
"199.jpg",
"200.jpg",
"201.jpg",
"202.jpg",
"203.jpg",
"204.jpg",
"205.jpg",
"206.jpg",
"207.jpg",
"208.jpg",
"209.jpg",
"210.jpg",
"211.jpg",
"212.jpg",
"213.jpg",
"214.jpg",
"215.jpg",
"216.jpg",
"217.jpg",
"218.jpg",
"219.jpg",
"220.jpg",
"221.jpg",
"222.jpg",
"223.jpg",
"224.jpg",
"225.jpg",
"226.jpg",
"227.jpg",
"228.jpg",
"229.jpg",
"230.jpg",
"231.jpg",
"232.jpg",
"233.jpg",
"234.jpg",
"235.jpg",
"236.jpg",
"237.jpg",
"238.jpg",
"239.jpg",
"240.jpg",
"241.jpg",
"242.jpg",
"243.jpg",
"244.jpg",
"245.jpg",
"246.jpg",
"247.jpg",
"248.jpg",
"249.jpg",
"250.jpg",
"251.jpg",
"252.jpg",
"253.jpg",
"254.jpg",
"255.jpg",
"256.jpg",
"257.jpg",
"258.jpg",
"259.jpg",
"260.jpg",
"261.jpg",
"262.jpg",
"263.jpg",
"264.jpg",
"265.jpg",
"266.jpg",
"267.jpg",
"268.jpg",
"269.jpg",
"270.jpg",
"271.jpg",
"272.jpg",
"273.jpg",
"274.jpg",
"275.jpg",
"276.jpg",
"277.jpg",
"278.jpg",
"279.jpg",
"280.jpg",
"281.jpg",
"282.jpg",
"283.jpg",
"284.jpg",
"285.jpg",
"286.jpg",
"287.jpg",
"288.jpg",
"289.jpg",
"290.jpg",
"291.jpg",
"292.jpg",
"293.jpg",
"294.jpg",
"295.jpg",
"296.jpg",
"297.jpg",
"298.jpg",
"299.jpg",
"300.jpg",
"301.jpg",
"302.jpg",
"303.jpg",
"304.jpg",
"305.jpg",
"306.jpg",
"307.jpg",
"308.jpg",
"309.jpg",
"310.jpg",
"311.jpg",
"312.jpg",
"313.jpg",
"314.jpg",
"315.jpg",
"316.jpg",
"317.jpg",
"318.jpg",
"319.jpg",
"320.jpg",
"321.jpg",
"322.jpg",
"323.jpg",
"324.jpg",
"325.jpg",
"326.jpg",
"327.jpg",
"328.jpg",
"329.jpg",
"330.jpg",
"331.jpg",
"332.jpg",
"333.jpg",
"334.jpg",
"335.jpg",
"336.jpg",
"337.jpg",
"338.jpg",
"339.jpg",
"340.jpg",
"341.jpg",
"342.jpg",
"343.jpg",
"344.jpg",
"345.jpg",
"346.jpg",
"347.jpg",
"348.jpg",
"349.jpg",
"350.jpg",
"351.jpg",
"352.jpg",
"353.jpg",
"354.jpg",
"355.jpg",
"356.jpg",
"357.jpg",
"358.jpg",
"359.jpg",
"360.jpg",
"361.jpg",
"362.jpg",
"363.jpg",
"364.jpg",
"365.jpg",
"366.jpg",
"367.jpg",
"368.jpg",
"369.jpg",
"370.jpg",
"371.jpg",
"372.jpg",
"373.jpg",
"374.jpg",
"375.jpg",
"376.jpg",
"377.jpg",
"378.jpg",
"379.jpg",
"380.jpg",
"381.jpg",
"382.jpg",
"383.jpg",
"384.jpg",
"385.jpg",
"386.jpg",
"387.jpg",
"388.jpg",
"389.jpg",
"390.jpg",
"391.jpg",
"392.jpg",
"393.jpg",
"394.jpg",
"395.jpg",
"396.jpg",
"397.jpg",
"398.jpg",
"399.jpg",
"400.jpg",
"401.jpg",
"402.jpg",
"403.jpg",
"404.jpg",
"405.jpg",
"406.jpg",
"407.jpg",
"408.jpg",
"409.jpg",
"410.jpg",
"411.jpg",
"412.jpg",
"413.jpg",
"414.jpg",
"415.jpg",
"416.jpg",
"417.jpg",
"418.jpg",
"419.jpg",
"420.jpg",
"421.jpg",
"422.jpg",
"423.jpg",
"424.jpg",
"425.jpg",
"426.jpg",
"427.jpg",
"428.jpg",
"429.jpg",
"430.jpg",
"431.jpg",
"432.jpg",
"433.jpg",
"434.jpg",
"435.jpg",
"436.jpg",
"437.jpg",
"438.jpg",
"439.jpg",
"440.jpg",
"441.jpg",
"442.jpg",
"443.jpg",
"444.jpg",
"445.jpg",
"446.jpg",
"447.jpg",
"448.jpg",
"449.jpg",
"450.jpg",
"451.jpg",
"452.jpg",
"453.jpg",
"454.jpg",
"455.jpg",
"456.jpg",
"457.jpg",
"458.jpg",
"459.jpg",
"460.jpg",
"461.jpg",
"462.jpg",
"463.jpg",
"464.jpg",
"465.jpg",
"466.jpg",
"467.jpg",
"468.jpg",
"469.jpg",
"470.jpg",
"471.jpg",
"472.jpg",
"473.jpg",
"474.jpg",
"475.jpg",
"476.jpg",
"477.jpg",
"478.jpg",
"479.jpg",
"480.jpg",
"481.jpg",
"482.jpg",
"483.jpg",
"484.jpg",
"485.jpg",
"486.jpg",
"487.jpg",
"488.jpg",
"489.jpg",
"490.jpg",
"491.jpg",
"492.jpg",
"493.jpg",
"494.jpg",
"495.jpg",
"496.jpg",
"497.jpg",
"498.jpg",
"499.jpg",
"500.jpg",
"501.jpg",
"502.jpg",
"503.jpg",
"504.jpg",
"505.jpg",
"506.jpg",
"507.jpg",
"508.jpg",
"509.jpg",
"510.jpg",
"511.jpg",
"512.jpg",
"513.jpg",
"514.jpg",
"515.jpg",
"516.jpg",
"517.jpg",
"518.jpg",
"519.jpg",
"520.jpg",
"521.jpg",
"522.jpg",
"523.jpg",
"524.jpg",
"525.jpg",
"526.jpg",
"527.jpg",
"528.jpg",
"529.jpg",
"530.jpg",
"531.jpg",
"532.jpg",
"533.jpg",
"534.jpg",
"535.jpg",
"536.jpg",
"537.jpg",
"538.jpg",
"539.jpg",
"540.jpg",
"541.jpg",
"542.jpg",
"543.jpg",
"544.jpg",
"545.jpg",
"546.jpg",
"547.jpg",
"548.jpg",
"549.jpg",
"550.jpg",
"551.jpg",
"552.jpg",
"553.jpg",
"554.jpg",
"555.jpg",
"556.jpg",
"557.jpg",
"558.jpg",
"559.jpg",
"560.jpg",
"561.jpg",
"562.jpg",
"563.jpg",
"564.jpg",
"565.jpg",
"566.jpg",
"567.jpg",
"568.jpg",
"569.jpg",
"570.jpg",
"571.jpg",
"572.jpg",
"573.jpg",
"574.jpg",
"575.jpg",
"576.jpg",
"577.jpg",
"578.jpg",
"579.jpg",
"580.jpg",
"581.jpg",
"582.jpg",
"583.jpg",
"584.jpg",
"585.jpg",
"586.jpg",
"587.jpg",
"588.jpg",
"589.jpg",
"590.jpg",
"591.jpg",
"592.jpg",
"593.jpg",
"594.jpg",
"595.jpg",
"596.jpg",
"597.jpg",
"598.jpg",
"599.jpg",
"600.jpg",
"601.jpg",
"602.jpg",
"603.jpg",
"604.jpg",
"605.jpg",
"606.jpg",
"607.jpg",
"608.jpg",
"609.jpg",
"610.jpg",
"611.jpg",
"612.jpg",
"613.jpg",
"614.jpg",
"615.jpg",
"616.jpg",
"617.jpg",
"618.jpg",
"619.jpg",
"620.jpg",
"621.jpg",
"622.jpg",
"623.jpg",
"624.jpg",
"625.jpg",
"626.jpg",
"627.jpg",
"628.jpg",
"629.jpg",
"630.jpg",
"631.jpg",
"632.jpg",
"633.jpg",
"634.jpg",
"635.jpg",
"636.jpg",
"637.jpg",
"638.jpg",
"639.jpg",
"640.jpg",
"641.jpg",
"642.jpg",
"643.jpg",
"644.jpg",
"645.jpg",
"646.jpg",
"647.jpg",
"648.jpg",
"649.jpg",
"650.jpg",
"651.jpg",
"652.jpg",
"653.jpg",
"654.jpg",
"655.jpg",
"656.jpg",
"657.jpg",
"658.jpg",
"659.jpg",
"660.jpg",
"661.jpg",
"662.jpg",
"663.jpg",
"664.jpg",
"665.jpg",
"666.jpg",
"667.jpg",
"668.jpg",
"669.jpg",
"670.jpg",
"671.jpg",
"672.jpg",
"673.jpg",
"674.jpg",
"675.jpg",
"676.jpg",
"677.jpg",
"678.jpg",
"679.jpg",
"680.jpg",
"681.jpg",
"682.jpg",
"683.jpg",
"684.jpg",
"685.jpg",
"686.jpg",
"687.jpg",
"688.jpg",
"689.jpg",
"690.jpg",
"691.jpg",
"692.jpg",
"693.jpg",
"694.jpg",
"695.jpg",
"696.jpg",
"697.jpg",
"698.jpg",
"699.jpg",
"001.jpg"
       ];

     $("#360frames").spritespin({
       width     : 400,
       height    : 262,
       frames    : frames.length,
       behavior  : "drag", // "hold"
       module    : "360",
       sense     : -1,
       source    : frames,
       animate   : true,
       loop      : true,
       frameWrap : true,
       frameStep : 1,
       frameTime : 180,
       enableCanvas : true
     });
     

     $("#panorama").spritespin({
       width     : 480,
       height    : 327,
       frames    : 2091,
       behavior  : "drag",
       module    : "panorama",
       sense     : -1,
       source    : "001.jpg",
       animate   : true,
       loop      : true,
       frameWrap : true,
       frameTime : 60
     });
     
     $("#gallery").spritespin({
       width     : 480,
       height    : 327,
       frames    : frames.length,
       behavior  : "click", // "swipe"
       module    : "gallery",
       source    : frames,
       animate   : false,
       loop      : true,
       frameWrap : true,
       frameTime : 60
     });
   });
   </script>
</body>
</html>

##################################################################
############################## moosespin.js ###################################
#################################################################


(function () {
 var Loader = this.SpriteLoader = {};
 Loader.preload = function(images, callback){
   if (typeof (images) === "string") { images = [images]; }
   var i, data = {
     callback : callback,
     numLoaded: 0,
     numImages: images.length,
     images   : []
   };
   for (i = 0; i < images.length; i += 1 ) {
     Loader.load(images[i], data);
   }
 };
 Loader.load = function(imageSource, data){
   var image = new Image();
   data.images.push(image);
   image.onload = function(){
     data.numLoaded += 1;
     if (data.numLoaded === data.numImages) {
       data.callback(data.images);
     }
   };
   image.src = imageSource;
 };
}());
(function($, window) {
 var Spin = window.SpriteSpin = {};
 var api = Spin.api = {};
 Spin.modules = {};
 Spin.behaviors = {};
 
 Spin.disableSelection = function(e){
   e.attr('unselectable', 'on')
    .css({
       "-moz-user-select": "none",
       "-khtml-user-select": "none",
       "-webkit-user-select": "none",
       "user-select": 'none'
    })
    .on('selectstart', false);
   return e;
 };

 Spin.updateInput = function(e, data){
   if (e.touches === undefined && e.originalEvent !== undefined){
     // jQuery Event normalization does not preserve the 'event.touches'
     // try to grab touches from the original event
     e.touches = e.originalEvent.touches;
   }
   
   data.oldX = data.currentX;
   data.oldY = data.currentY;
   
   if (e.touches !== undefined && e.touches.length > 0){
     data.currentX = e.touches[0].clientX;
     data.currentY = e.touches[0].clientY;
   } else {
     data.currentX = e.clientX;
     data.currentY = e.clientY;
   }
   
   if (data.startX === undefined || data.startY === undefined){
     data.startX = data.currentX;
     data.startY = data.currentY;
     data.clickframe = data.frame;
   }
   
   if (data.oldX === undefined || data.oldY === undefined){
     data.oldX = data.currentX;
     data.oldY = data.currentY;
   }
   
   // total drag distance
   data.dX = data.currentX - data.startX;
   data.dY = data.currentY - data.startY;
   data.dW = data.dX * data.dragDirX + data.dY * data.dragDirY;
   
   // frame drag distance
   data.ddX = data.currentX - data.oldX;
   data.ddY = data.currentY - data.oldY;
   data.ddW = data.ddX * data.dragDirX + data.ddY * data.dragDirY;
   
   return false;
 };
 
 Spin.resetInput = function(data){
   // initial touch or click position
   data.startX = undefined;
   data.startY = undefined;
   // touch or click position in current frame
   data.currentX = undefined;
   data.currentY = undefined;
   // touch or click position in last frame
   data.oldX = undefined;
   data.oldY = undefined;
   // total drag distance, respecting the start position
   data.dX = 0;
   data.dY = 0;
   data.dW = 0;
   // total drag distance, respecting the last frame position
   data.ddX = 0;
   data.ddY = 0;
   data.ddW = 0;
   
   if (typeof(data.module.resetInput) === "function"){
     data.module.resetInput(data);
   }
 };
 
 Spin.clamp = function(value, min, max){
   return (value > max ? max : (value < min ? min : value));
 };
 
 Spin.wrap = function(value, min, max, size){
   while (value > max){ value -= size; }
   while (value < min){ value += size; }
   return value;
 };
 
 Spin.reload = function(data, andInit){
   if (andInit && data.module.initialize){
     data.module.initialize(data);
   }
   
   Spin.prepareBackground(data);
   Spin.preloadImages(data, function(){
     Spin.rebindEvents(data);
     data.module.reload(data);
     data.target.trigger("onLoad", data);
   });
 };
 
 Spin.preloadImages = function(data, callback) {
   data.preload.fadeIn(250, function(){
     SpriteLoader.preload(data.source, function(images){
       data.preload.fadeOut(250, function() {
           data.preload.hide();
       });
       data.stage.show();
       if (data.canvas){
         data.canvas.show();
       }
       data.images = images;
       callback.apply(data.target, [data]);
     });
   });
 };
 
 Spin.prepareBackground = function(data){
   var w = [data.width, "px"].join("");
   var h = [data.height, "px"].join("");
   
   data.target.css({
     width    : w,
     height   : h,
     position : "relative"
   });
   
   var css = {
     width    : w,
     height   : h,
     top      : "0px",
     left     : "0px",
     position : "absolute"  
   };
   $.extend(css, data.preloadCSS || {});
   data.preload.css(css).html(data.preloadHtml || "").hide();
   
   data.stage.css({
     width    : w,
     height   : h,
     top      : "0px",
     left     : "0px",
     position : "absolute"
   }).hide();
   
   if (data.canvas){
     data.canvas[0].width = data.width;
     data.canvas[0].height = data.height;      
     data.canvas.css({
       width    : w,
       height   : h,
       top      : "0px",
       left     : "0px",
       position : "absolute"
     }).hide();
   }
 };
 
 Spin.draw = function(data){
   data.module.draw(data);
 };
 
 Spin.rebindEvents = function(data){
   var target = data.target;
   // unbind all events
   target.unbind('.spritespin');
 
   // use custom or build in behavior
   var beh = data.behavior;
   if (typeof(data.behavior) === "string"){
     beh = Spin.behaviors[data.behavior];
   }
   beh = beh || {};
   
   var prevent = function(e){
     if (e.cancelable){ e.preventDefault(); }
     return false;
   };
   
   // rebind interaction events
   target.bind('mousedown.spritespin',  beh.mousedown  || $.noop);
   target.bind('mousemove.spritespin',  beh.mousemove  || $.noop);
   target.bind('mouseup.spritespin',    beh.mouseup    || $.noop);
   target.bind('mouseenter.spritespin', beh.mouseenter || $.noop);
   target.bind('mouseover.spritespin',  beh.mouseover  || $.noop);
   target.bind('mouseleave.spritespin', beh.mouseleave || $.noop);
   target.bind('dblclick.spritespin',   beh.dblclick   || $.noop);
   target.bind('onFrame.spritespin',    beh.onFrame    || $.noop);
 
   if (data.touchable){
     target.bind('touchstart.spritespin',  beh.mousedown  || $.noop);
     target.bind('touchmove.spritespin',   beh.mousemove  || $.noop);
     target.bind('touchend.spritespin',    beh.mouseup    || $.noop);
     target.bind('touchcancel.spritespin', beh.mouseleave || $.noop);
     target.bind('click.spritespin',         prevent);
     target.bind('gesturestart.spritespin',  prevent);
     target.bind('gesturechange.spritespin', prevent);
     target.bind('gestureend.spritespin',    prevent);
   }
           
   // disable selection
 target.bind("mousedown.spritespin selectstart.spritespin", prevent);

 target.bind("onFrame.spritespin", function(event, data){
   Spin.draw(data);
 });
 target.bind("onLoad.spritespin", function(event, data){
   data.target.spritespin("animate", data.animate, data.loop);
 });
 
 // bind custom events
 if (typeof(data.onFrame) === "function"){
   target.bind("onFrame.spritespin", data.onFrame);
 }
 if (typeof(data.onLoad) === "function"){
   target.bind("onLoad.spritespin", data.onLoad);
 }
 };

 $.fn.spritespin = function(method) {
   if ( api[method] ) {
     return api[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
   }
   if (typeof(method) === 'object' || !method) {
     return api.init.apply(this, arguments);
   }
   $.error( 'Method ' +  method + ' does not exist on jQuery.spritespin' );
 };

api.init = function(options){
   // Default settings
   var settings = {
     // dimensions
     width             : undefined,              // Window width (or frame width)
     height            : undefined,              // Window height (or frame height)
     frames            : 36,                     // Total number of frames
     frame             : 0,                      // Initial frame number
     module            : "360",
     behavior          : "drag",
     // animation & update
     animate           : true,                   // Run animation when after initialize
     loop              : false,                  // Repeat animation in a loop
     loopFrame         : 0,                      // Indicates the loop start frame
     frameStep         : 1,                      // Number of frames to increment on each animation update
     frameTime         : 36,                     // Time between updates
     frameWrap         : true,                   // Same as 'loob' but for user interaction (behavior)
     reverse           : false,                  // If true animation is played backward
     sense             : 1,                      // Interaction sensitivity used by behavior implementations
     orientation       : "horizontal",
     
     // appearance               
     source            : undefined,              // Stiched source image
     preloadHtml       : undefined,              // Html to appear when images are preloaded
     preloadCSS        : undefined,
     
     // events
     onFrame           : undefined,              // Occurs whe frame has been updated
     onLoad            : undefined,              // Occurs when images are loaded
     touchable         : undefined              // Tells spritespin that it is running on a touchable device
   };
   
   // extending options
   options = (options || {});
   $.extend(settings, options);
   
   return this.each(function(){
     var $this = $(this);
     var data  = $this.data('spritespin');
     
     if (!data){
       // spritespin is not initialized
       
       var images = $this.find("img");
       var i = 0;
       if (images.length > 0){
         settings.source = [];
         for(i = 0; i < images.length; i += 1){
           settings.source.push($(images[i]).attr("src"));
         }
       }
       
       if (typeof(settings.source) === "string"){
         settings.source = [settings.source];
       }
       
       // disable selection & hide overflow
       Spin.disableSelection($this).css({
         overflow : "hidden",
         position : "relative"
       });
       
       // build inner html
       $this.empty();
       $this.append($("<div class='spritespin-stage'/>"));
       $this.append($("<div class='spritespin-preload'/>"));
       $this.addClass("spritespin-instance");

       if (settings.enableCanvas){
         var canvas = $("<canvas class='spritespin-canvas'/>")[0];
         var supported = !!(canvas.getContext && canvas.getContext('2d'));
         if (supported){
           settings.canvas = $(canvas);
           settings.context = canvas.getContext("2d");
           $this.append(settings.canvas);
         }
       }

       // resolve module
       if (typeof(settings.module) === "string"){
         settings.module = SpriteSpin.modules[settings.module];
       }
       
       // build data
       settings.target = $this;
       settings.stage = $this.find(".spritespin-stage");
       settings.preload = $this.find(".spritespin-preload");
       settings.animation = null;
       settings.touchable =(settings.touchable || (/iphone|ipod|ipad|android/i).test(window.navigator.userAgent));
       
       $this.data('spritespin', settings);
       SpriteSpin.reload(settings, true);
     } else {
       // spritespin is initialized.
       $.extend(data, options);

       if (options.source){
         // when images are passed, need to reload the plugin
         SpriteSpin.reload(data);
       } else {
         // otherwise just reanimate spritespin
         $this.spritespin("animate", data.animate, data.loop);
       }
     }
   });
 };
 
api.destroy = function(){
   return this.each(function(){
     var $this = $(this);
     $this.unbind('.spritespin');
     $this.removeData('spritespin');
   });
 };

 // Updates a single frame to the specified frame number. If no value is
 // given this will increment the current frame counter.
 // Triggers the onFrame event
 api.update = function(frame){
   return this.each(function(){
     var $this = $(this);
     var data = $this.data('spritespin');
     
     // update frame counter
     if (frame === undefined){
       data.frame += ((data.animation && data.reverse) ? -data.frameStep : data.frameStep);
     } else {
       data.frame = frame;
     }
     
     // wrap/clamp the frame value to fit in range [0, data.frames]
     if ( data.animation ||                    // wrap frame during animation
         (!data.animation && data.frameWrap)){   // wrap frame during user input
       data.frame = Spin.wrap(data.frame, 0, data.frames - 1, data.frames);
     } else {
       data.frame = Spin.clamp(data.frame, 0, data.frames - 1);
     }

     // stop animation if the loopFrame is reached
     if (!data.loop && data.animation && (data.frame === data.loopFrame)){
       api.animate.apply(data.target, [false]);
     }
     
     data.target.trigger("onFrame", data);
   });
 };

 // Starts or stops the animation depend on the animate paramter.
 // In case when animation is already running pass "false" to stop.
 // In case when animation is not running pass "true" to start.
 // To keep animation running forever pass "true" for the loop parameter.
 // To detect whether the animation is running or not, do not pass any
 // parameters.
 api.animate = function(animate, loop){
   if (animate === undefined){
     return $(this).data('spritespin').animation !== null;
   }
   return this.each(function(){
     var $this = $(this);
     var data = $this.data('spritespin');
     
     // check the loop variable and update settings
     if (typeof(loop) === "boolean"){
       data.loop = loop;
     }
     // toggle and update animation settings
     if (animate === "toggle"){
       data.animate = !data.animate;
     }
     //
     if (typeof(animate) === "boolean"){
       data.animate = animate;
     }
     // stop the running animation
     if (data.animation){
       window.clearInterval(data.animation);
       data.animation = null;
     }
     // start animation
     if (data.animate){
       data.animation = window.setInterval(function(){
         try {
           $this.spritespin("update");
         } catch(err){
           // The try catch block is a hack for Opera Browser
           // Opera sometimes rises an exception here and
           // stops performing the script
         }
       }, data.frameTime);
     }  
   });
 };

 // Gets the current framenumber when no parameter is passed or
 // updates the spinner to the sepcified frame.
 api.frame = function(frame){
   if (frame === undefined){
     return $(this).data('spritespin').frame;
   }
   return this.each(function(){
     $(this).spritespin("update", frame);
   });        
 };

 // Gets or sets a value indicating whether the animation is looped or not.
 // Starts the animation when settings.animate is set to true passed value
 // is defined
 api.loop = function(value){
   if (value === undefined){
     return $(this).data('spritespin').loop;
   }
   return this.each(function(){
     var $this = $(this);
     $this.spritespin("animate", $this.data('spritespin').animate, value);
   });
 };

 api.next = function(){
   return this.each(function(){
     var $this = $(this); $this.spritespin("frame", $this.spritespin("frame") + 1);
   });
 };
 
 api.prev = function(){
   return this.each(function(){
     var $this = $(this); $this.spritespin("frame", $this.spritespin("frame") - 1);
   });
 };
 
 api.animateTo = function(frame){
   return this.each(function(){
     var $this = $(this); $this.spritespin({
       animate : true,
       loop : false,
       loopFrame : frame
     });
   });
 };

 Spin.behaviors.none = {
   name : "none",
   mousedown  : $.noop,
   mousemove  : $.noop,
   mouseup    : $.noop,
   
   mouseenter : $.noop,
   mouseover  : $.noop,
   mouseleave : $.noop,
   dblclick   : $.noop,
   
   onFrame : $.noop
 };
 
}(jQuery, window));
(function($, window, Spin){
 Spin.behaviors.click = {
   name : "click",
   mouseup    : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.updateInput(e, data);
     $this.spritespin("animate", false); // stop animation

     var h, p, o = data.target.offset();
     if (data.orientation == "horizontal"){
       h = data.width / 2;
       p = data.currentX - o.left;
     } else {
       h = data.height / 2;
       p = data.currentY - o.top;        
     }
     if (p > h){
       $this.spritespin("frame", data.frame + 1);
       data.reverse = false;
     } else {
       $this.spritespin("frame", data.frame - 1);
       data.reverse = true;
     }
   }
 };
}(jQuery, window, window.SpriteSpin));
(function($, window, Spin){
 Spin.behaviors.drag = {
   name : "drag",
   mousedown  : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.updateInput(e, data);
     data.onDrag = true;
   },
   mousemove  : function(e){
     var $this = $(this), data = $this.data('spritespin');
     if (data.onDrag){
       Spin.updateInput(e, data);
       
       var d;
       if (data.orientation == "horizontal"){
         d = data.dX / data.width;
       } else {
         d = data.dY / data.height;
       }
     
       var dFrame = d * data.frames * data.sense;
       var frame = Math.round(data.clickframe + dFrame);
       $this.spritespin("update", frame);  // update to frame
       $this.spritespin("animate", false);  // stop animation
     }
   },
   mouseup    : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.resetInput(data);
     data.onDrag = false;
   },
   mouseleave : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.resetInput(data);
     data.onDrag = false;
   }
 };  
}(jQuery, window, window.SpriteSpin));
(function($, window, Spin){
 Spin.behaviors.hold = {
   name : "hold",
   mousedown  : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.updateInput(e, data);
     data.onDrag = true;
     $this.spritespin("animate", true);
   },
   mousemove  : function(e){
     var $this = $(this), data = $this.data('spritespin');
     
     if (data.onDrag){
       Spin.updateInput(e, data);
       
       var h, d, o = data.target.offset();
       if (data.orientation == "horizontal"){
         h = (data.width / 2);
         d = (data.currentX - o.left - h) / h;
       } else {
         h = (data.height / 2);
         d = (data.currentY - o.top - h) / h;
       }
       data.reverse = d < 0;
       d = d < 0 ? -d : d;
       data.frameTime = 80 * (1 - d) + 20;        
     }
   },
   mouseup    : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.resetInput(data);
     data.onDrag = false;
     $this.spritespin("animate", false);
   },
   mouseleave : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.resetInput(data);
     data.onDrag = false;
     $this.spritespin("animate", false);
   },
   onFrame : function(e){
     var $this = $(this);
     $this.spritespin("animate", true);
   }
 };
}(jQuery, window, window.SpriteSpin));
(function($, window, Spin){
 Spin.behaviors.swipe = {
   name : "swipe",
   mousedown  : function(e){
     var $this = $(this), data = $this.data('spritespin');
     Spin.updateInput(e, data);
     data.onDrag = true;
   },
   mousemove  : function(e){
     var $this = $(this), data = $this.data('spritespin');
     if (data.onDrag){
       Spin.updateInput(e, data);
       
       var frame = data.frame;
       var snap = data.snap || 0.25;
       var d, s;
       
       if (data.orientation == "horizontal"){
         d = data.dX;
         s = data.width * snap;
       } else {
         d = data.dY;
         s = data.height * snap;
       }
       
       if (d > s){
         frame = data.frame - 1;       
         data.onDrag = false;
       } else if (d < -s){
         frame = data.frame + 1;
         data.onDrag = false;
       }
       
       $this.spritespin("update", frame);  // update to frame
       $this.spritespin("animate", false); // stop animation
     }
   },
   mouseup    : function(e){
     var $this = $(this), data = $this.data('spritespin');
     data.onDrag = false;
     Spin.resetInput(data);
   },
   mouseleave : function(e){
     var $this = $(this), data = $this.data('spritespin');
     data.onDrag = false;
     Spin.resetInput(data);
   }
 };  
}(jQuery, window, window.SpriteSpin));
(function($, window) {
 
 var Module = window.SpriteSpin.modules["360"] = {};
 
 Module.reload = function(data){
   var images = $(data.images);

   // clear the stage and refill with images
   data.stage.empty()

   // precalculate and cache options for this module
   data.modopts = {
     is_sprite : (data.images.length == 1),
     resX      : (data.resolutionX || data.images[0].width),
     resY      : (data.resolutionY || data.images[0].height),
     offX      : (data.offsetX || 0),
     offY      : (data.offsetY || 0),
     stepX     : (data.stepX || data.width),
     stepY     : (data.stepY || data.height),
     numFramesX: (data.framesX || data.frames),
     oldFrame  : data.frame,
     images    : images
   };

   if (!data.modopts.is_sprite && !data.canvas){
     data.stage.append(images);
   }

   images.css({
     width: data.modopts.resX,
     height: data.modopts.resY
   });

   Module.draw(data);
 };
 
 Module.draw = function(data){    
   if (data.modopts.is_sprite){
     Module.drawSpritesheet(data);
   } else{
     Module.drawImages(data);
   }
 };

 Module.drawSpritesheet = function(data){
   // Assumes all images are batched in a single sprite image

   var opts = data.modopts;
   var image = data.source[0];
   var frameX = (data.frame % opts.numFramesX);
   var frameY = (data.frame / opts.numFramesX)|0;
   var x = opts.offX + frameX * opts.stepX;
   var y = opts.offY + frameY * opts.stepY;

   if (data.canvas){
     data.context.clearRect(0, 0, data.width, data.height);
     data.context.drawImage(data.images[0], x, y, data.width, data.height, 0, 0, data.width, data.height);
     return;
   }

   data.stage.css({
     width      : [data.width, "px"].join(""),
     height     : [data.height, "px"].join(""),
     "background-image"    : ["url('", image, "')"].join(""),
     "background-repeat"   : "no-repeat",
     "background-position" : [-x, "px ", -y, "px"].join(""),
     // Spritesheets may easily exceed the maximum image size for iphones.
     // In this case the browser will scale down the image automaticly and
     // this will break the logic how spritespin works.
     // Here we set the webkit css attribute to display the background in its
     // original dimension even if it has been scaled down.
     "-webkit-background-size" : [opts.resX, "px ", opts.resY, "px"].join("")
   });
 };

 Module.drawImages = function(data){
   var img = data.images[data.frame];
   if (data.canvas){
     data.context.clearRect(0, 0, data.width, data.height);
     data.context.drawImage(img, 0, 0);
     return;
   }

   var frame = data.stage.css({
     width      : [data.width, "px"].join(""),
     height     : [data.height, "px"].join("")
   }).children().hide()[data.frame];
   SpriteSpin.disableSelection($(frame)).show();
 };

}(window.jQuery, window));
(function($, window) {
 var Module = window.SpriteSpin.modules.gallery = {};
 
 Module.reload = function(data){
   data.images = [];
   data.offsets = [];
   data.stage.empty();
   data.speed = 500;
   data.opacity = 0.25;
   data.oldFrame = 0;
   var size = 0, i = 0;
   for(i = 0; i < data.source.length; i+= 1){
     var img = $("<img src='" + data.source[i] + "'/>");
     data.stage.append(img);
     data.images.push(img);
     data.offsets.push(-size + (data.width - img[0].width) / 2);
     size += img[0].width;
     
     img.css({ opacity : 0.25 });
   }
   data.stage.css({ width : size });
   data.images[data.oldFrame].animate({ opacity : 1 }, data.speed);
 };
 
 Module.draw = function(data){
   if ((data.oldFrame != data.frame) && data.offsets){
     data.stage.stop(true, false);
     data.stage.animate({
       "left" : data.offsets[data.frame]
     }, data.speed);
     
     data.images[data.oldFrame].animate({ opacity : data.opacity }, data.speed);
     data.oldFrame = data.frame;
     data.images[data.oldFrame].animate({ opacity : 1 }, data.speed);
   } else {
     //console.log(data.dX);
     data.stage.css({
       "left" : data.offsets[data.frame] + data.dX
     });
   }
 };
 
 Module.resetInput = function(data){
   if (!data.onDrag){
     data.stage.animate({
       "left" : data.offsets[data.frame]
     });
   }
 };
}(jQuery, window));
(function($, window) {  
 var Module = window.SpriteSpin.modules.panorama = {};

 Module.reload = function(data){
   data.stage.empty();             // clear the stage
   var opts = data.modopts = {};   // precalculate and cache options for this module
   opts.resX = (data.resolutionX || data.images[0].width);
   opts.resY = (data.resolutionY || data.images[0].height);
   if (data.orientation == "horizontal"){
     opts.frames = (data.frames || opts.resX);
   } else {
     opts.frames = (data.frames || opts.resY);
   }
   
   Module.drawFirst(data);
 };
 
 // The function was stripped to do only necessary CSS updates
 Module.draw = function(data){      
   var opts = data.modopts;
   var x, y;
      
   if (data.orientation == "horizontal"){
     x = (data.frame % opts.frames);
     y = 0;      
   } else {
     x = 0;
     y = (data.frame % opts.frames);
   }
   data.stage.css({
     "background-position"     : [-x, "px ", -y, "px"].join("")
   });
 };
 
  // Renamed original draw function which is called only once at Load/Reload
 Module.drawFirst = function(data){      
   var opts = data.modopts;
   var x, y;

   if (data.orientation == "horizontal"){
     x = (data.frame % opts.frames);
     y = 0;      
   } else {
     x = 0;
     y = (data.frame % opts.frames);
   }
   data.stage.css({
     width      : [data.width, "px"].join(""),
     height     : [data.height, "px"].join(""),
     "background-image"        : ["url('", data.source[0], "')"].join(""),
     "background-repeat"       : "repeat-both",
     "background-position"     : [-x, "px ", -y, "px"].join(""),
     "-webkit-background-size" : [opts.resX, "px ", opts.resY, "px"].join("")
   });
 };
 
}(window.jQuery, window));