` prefferably) anywhere in the DOM,\r\n // assign it __class name__ `\"reel-annotation\"`, an unique __`id` attribute__\r\n // and add configuration __data attributes__.\r\n //\r\n //
\r\n // Whatever HTML I'd like to have in the annotation\r\n //
\r\n //\r\n // Most important is the `data-for` attribute, which references target Reel instance by `id`.\r\n //\r\n // ---\r\n\r\n //\r\n // Responsible for discovery and subsequent conversion of data-configured Reel images is\r\n // `$.reel.scan()` method, which is being called automagically when the DOM becomes ready.\r\n // Under normal circumstances you don't need to scan by yourself.\r\n //\r\n // It however comes in handy to re-scan when you happen to inject a data-configured Reel `
![]()
`\r\n // into already ready DOM.\r\n //\r\n // ---\r\n\r\n // ### `$.reel.scan()` Method ######\r\n // [NEW] returns `jQuery`, since 1.3\r\n //\r\n scan: function(){\r\n return $(dot(klass)+':not('+dot(overlay_klass)+' > '+dot(klass)+')').each(function(ix, image){\r\n var\r\n $image= $(image),\r\n options= $image.data(),\r\n images= options.images= soft_array(options.images),\r\n annotations= {}\r\n $(dot(annotation_klass)+'[data-for='+$image.attr(_id_)+']').each(function(ix, annotation){\r\n var\r\n $annotation= $(annotation),\r\n def= $annotation.data(),\r\n x= def.x= numerize_array(soft_array(def.x)),\r\n y= def.y= numerize_array(soft_array(def.y)),\r\n id= $annotation.attr(_id_),\r\n node= def.node= $annotation.removeData()\r\n annotations[id] = def;\r\n });\r\n options.annotations = annotations;\r\n $image.removeData().reel(options);\r\n });\r\n },\r\n\r\n // -------\r\n // Methods\r\n // -------\r\n //\r\n // Reel's methods extend jQuery core functions with members of its `$.reel.fn` object. Despite Reel\r\n // being a typical one-method plug-in with its `.reel()` function, for convenience it also offers\r\n // its bipolar twin `.unreel()`.\r\n //\r\n // ---\r\n\r\n // ### `$.reel.fn` ######\r\n // returns `Object`, since 1.1\r\n //\r\n fn: {\r\n // ------------\r\n // Construction\r\n // ------------\r\n //\r\n // `.reel()` method is the core of Reel and similar to some jQuery functions, it has adaptive interface.\r\n // It either builds, [reads & writes data](#Data) or [causes events](#Control-Events).\r\n //\r\n // ---\r\n\r\n // ### `.reel( [options] )` Method ######\r\n // returns `jQuery`, since 1.0\r\n //\r\n reel: function(){\r\n var\r\n args= arguments,\r\n t= $(this),\r\n data= t.data(),\r\n name= args[0] || {},\r\n value= args[1]\r\n\r\n // The main [core of this procedure](#Construction-Core) is rather bulky, so let's skip it for now\r\n // and instead let me introduce the other uses first.\r\n\r\n // --------------------\r\n // [NEW] Control Events\r\n // --------------------\r\n //\r\n // [Event][1] messages are what ties and binds all Reel's internal working components together.\r\n // Besides being able to binding to any of these events from your script and react on Reel status changes\r\n // (e.g. position), you can also trigger some of them in order to control Reel's attitude.\r\n //\r\n // You can:\r\n //\r\n // * control the playback of animated Reels with [`play`](#play-Event), [`pause`](#pause-Event)\r\n // or [`stop`](#stop-Event)\r\n // * step the Reel in any direction with [`stepRight`](#stepRight-Event), [`stepLeft`](#stepLeft-Event),\r\n // [`stepUp`](#stepUp-Event), [`stepDown`](#stepDown-Event), \r\n // * reach certain frame with [`reach`](#reach-Event)\r\n //\r\n // Triggering Reel's control event is as simple as passing the desired event name to `.reel()`.\r\n //\r\n // _**Example:** Stop the animation in progress:_\r\n //\r\n // .reel(':stop')\r\n //\r\n // Think of `.reel()` as a convenient shortcut to and synonym for [`.trigger()`][2], only prefix\r\n // the event name with `:`. Of course you can use simple `.trigger()` instead and without the colon.\r\n //\r\n //\r\n // [1]:http://api.jquery.com/category/events/event-object/\r\n // [2]:http://api.jquery.com/trigger\r\n //\r\n // ---\r\n\r\n // #### `.reel( event, [arguments] )` ######\r\n // returns `jQuery`, since 1.3\r\n //\r\n if (typeof name != 'object'){\r\n\r\n if (name.slice(0, 1) == ':'){\r\n return t.trigger(name.slice(1), value);\r\n }\r\n\r\n // ----\r\n // Data\r\n // ----\r\n //\r\n // Reel stores all its inner state values with the standard DOM [data interface][1] interface\r\n // while adding an additional change-detecting event layer, which makes Reel entirely data-driven.\r\n //\r\n // [1]:http://api.jquery.com/data\r\n //\r\n // _**Example:** Find out on what frame a Reel instance currently is:_\r\n //\r\n // .reel('frame') // Returns the frame number\r\n //\r\n // This time think of `.reel(data)` as a synonym for `.data()`. Note, that you can therefore easily\r\n // inspect the entire datastore with `.data()` (without arguments). Use it for debugging only.\r\n // For real-time data watch use [`monitor`](#Monitor) option instead of manually hooking into\r\n // the data.\r\n //\r\n // ---\r\n\r\n // #### `.reel( data )` ######\r\n // can return anything, since 1.2\r\n //\r\n else{\r\n if (args.length == 1){\r\n return data[name]\r\n }\r\n\r\n // ### Write Access ###\r\n //\r\n // You can store any value the very same way by passing the value as the second function\r\n // argument.\r\n //\r\n // _**Example:** Jump to frame 12:_\r\n //\r\n // .reel('frame', 12)\r\n //\r\n // Only a handful of data keys is suitable for external manipulation. These include `area`,\r\n // `backwards`, `brake`, __`fraction`__, __`frame`__, `playing`, `reeling`, __`row`__, `speed`,\r\n // `stopped`, `velocity` and `vertical`. Use the rest of the keys for reading only, you can\r\n // mess up easily changing them.\r\n //\r\n // ---\r\n\r\n // #### `.reel( data, value )` ######\r\n // returns `jQuery`, since 1.2\r\n //\r\n else{\r\n if (value !== undefined){\r\n reel.normal[name] && (value= reel.normal[name](value, data));\r\n\r\n // ### Changes ######\r\n //\r\n // Any value that does not equal (`===`) the old value is considered _new value_ and\r\n // in such a case Reel will trigger a _change event_ to announce the change. The event\r\n // type takes form of _`key`_`Change`, where _`key`_ will be the data key/name you've\r\n // just assigned.\r\n //\r\n // _**Example:** Setting `\"frame\"` to `12` in the above example will trigger\r\n // `\"frameChange\"`._\r\n //\r\n // Some of these _change events_ (like `frame` or `fraction`) have a\r\n // default handler attached.\r\n //\r\n // You can easily bind to any of the data key change with standard event\r\n // binding methods.\r\n //\r\n // _**Example:** React on instance being manipulated or not:_\r\n //\r\n // .bind('reelingChange', function(evnt, nothing, reeling){\r\n // if (reeling) console.log('Rock & reel!')\r\n // else console.log('Not reeling...')\r\n // })\r\n //\r\n // ---\r\n\r\n // The handler function will be executed every time the value changes and\r\n // it will be supplied with three arguments. First one is the event object\r\n // as usual, second is `undefined` and the third will be the actual value.\r\n // In this case it was a boolean type value.\r\n // If the second argument is not `undefined` it is the backward compatible\r\n // \"before\" event triggered from outside Reel.\r\n //\r\n if (data[name] === undefined) data[name]= value\r\n else if (data[name] !== value) t.trigger(name+'Change', [ undefined, data[name]= value ]);\r\n }\r\n return t\r\n }\r\n }\r\n }\r\n\r\n //\r\n // -----------------\r\n // Construction Core\r\n // -----------------\r\n //\r\n // Now, back to the procedure of [constructing](#Construction) a Reel instance\r\n // and binding its event handlers.\r\n //\r\n // Establish local `opt` object made by extending the defaults.\r\n //\r\n else{\r\n\r\n var\r\n opt= $.extend({}, reel.def, name),\r\n // Limit the given jQuery collection to just `
![]()
` tags with `src` attribute\r\n // and dimensions defined.\r\n applicable= t.filter(_img_).unreel().filter(function(){\r\n var\r\n $this= $(this),\r\n attr= opt.attr,\r\n src= attr.src || $this.attr(_src_),\r\n width= attr.width || $this.attr(_height_) || $this.width(),\r\n height= attr.height || $this.attr(_width_) || $this.height()\r\n if (!src) return error('`src` attribute missing on target image');\r\n if (!width || !height) return error('Dimension(s) of the target image unknown');\r\n return true;\r\n }),\r\n instances= []\r\n\r\n applicable.each(function(){\r\n var\r\n t= $(this),\r\n\r\n // Quick data interface\r\n set= function(name, value){ return t.reel(name, value) && get(name) },\r\n get= function(name){ return t.data(name) },\r\n\r\n on= {\r\n\r\n // --------------\r\n // Initialization\r\n // --------------\r\n //\r\n // This internally called private pseudo-handler:\r\n //\r\n // - initiates all data store keys,\r\n // - binds to ticker\r\n // - and triggers `\"setup\"` Event when finished.\r\n //\r\n setup: function(e){\r\n if (t.hasClass(klass) && t.parent().hasClass(overlay_klass)) return;\r\n set(_options_, opt);\r\n var\r\n attr= {\r\n src: t.attr(_src_),\r\n width: t.attr(_width_) || null,\r\n height: t.attr(_height_) || null,\r\n style: t.attr(_style_) || null,\r\n 'class': t.attr(_class_) || null\r\n },\r\n src= t.attr(opt.attr).attr(_src_),\r\n id= set(_id_, t.attr(_id_) || t.attr(_id_, klass+'-'+(+new Date())).attr(_id_)),\r\n data= $.extend({}, t.data()),\r\n images= set(_images_, opt.images || []),\r\n stitched= set(_stitched_, opt.stitched),\r\n is_sprite= !images.length || stitched,\r\n responsive= set(_responsive_, opt.responsive && (knows_background_size ? true : !is_sprite)),\r\n truescale= set(_truescale_, {}),\r\n loops= opt.loops,\r\n orbital= opt.orbital,\r\n revolution= opt.revolution,\r\n rows= opt.rows,\r\n footage= set(_footage_, min(opt.footage, opt.frames)),\r\n spacing= set(_spacing_, opt.spacing),\r\n width= set(_width_, +t.attr(_width_) || t.width()),\r\n height= set(_height_, +t.attr(_height_) || t.height()),\r\n shy= set(_shy_, opt.shy),\r\n frames= set(_frames_, orbital && footage || rows <= 1 && images.length || opt.frames),\r\n multirow= rows > 1 || orbital,\r\n revolution_x= set(_revolution_, axis('x', revolution) || stitched / 2 || width * 2),\r\n revolution_y= set(_revolution_y_, !multirow ? 0 : (axis('y', revolution) || (rows > 3 ? height : height / (5 - rows)))),\r\n rows= stitched ? 1 : ceil(frames / footage),\r\n stitched_travel= set(_stitched_travel_, stitched - (loops ? 0 : width)),\r\n stitched_shift= set(_stitched_shift_, 0),\r\n stage_id= hash(id+opt.suffix),\r\n img_class= t.attr(_class_),\r\n classes= !img_class ? __ : img_class+___,\r\n $overlay= $(tag(_div_), { id: stage_id.substr(1), 'class': classes+___+overlay_klass+___+frame_klass+'0' }),\r\n $instance= t.wrap($overlay.addClass(opt.klass)).addClass(klass),\r\n instances_count= instances.push(add_instance($instance)[0]),\r\n $overlay= $instance.parent().bind(on.instance)\r\n set(_image_, images.length ? __ : opt.image || src.replace(reel.re.image, '$1' + opt.suffix + '.$2'));\r\n set(_cache_, $(tag(_div_), { 'class': cache_klass }).appendTo('body'));\r\n set(_area_, $()),\r\n set(_cached_, []);\r\n set(_frame_, null);\r\n set(_fraction_, null);\r\n set(_row_, opt.row);\r\n set(_tier_, 0);\r\n set(_rows_, rows);\r\n set(_rowlock_, opt.rowlock);\r\n set(_framelock_, opt.framelock);\r\n set(_departure_, set(_destination_, set(_distance_, 0)));\r\n set(_bit_, 1 / frames);\r\n set(_stage_, stage_id);\r\n set(_backwards_, set(_speed_, opt.speed) < 0);\r\n set(_loading_, false);\r\n set(_velocity_, 0);\r\n set(_vertical_, opt.vertical);\r\n set(_preloaded_, 0);\r\n set(_cwish_, negative_when(1, !opt.cw && !stitched));\r\n set(_clicked_location_, {});\r\n set(_clicked_, false);\r\n set(_clicked_on_, set(_clicked_tier_, 0));\r\n set(_lo_, set(_hi_, 0));\r\n set(_reeling_, false);\r\n set(_reeled_, false);\r\n set(_opening_, false);\r\n set(_brake_, opt.brake);\r\n set(_center_, !!orbital);\r\n set(_tempo_, opt.tempo / (reel.lazy? opt.laziness : 1));\r\n set(_opening_ticks_, -1);\r\n set(_ticks_, -1);\r\n set(_annotations_, opt.annotations || $overlay.unbind(dot(_annotations_)) && {});\r\n set(_ratio_, 1);\r\n set(_backup_, {\r\n attr: attr,\r\n data: data\r\n });\r\n opt.steppable || $overlay.unbind('up.steppable');\r\n opt.indicator || $overlay.unbind('.indicator');\r\n css(__, { overflow: _hidden_, position: 'relative' });\r\n responsive || css(__, { width: width, height: height });\r\n responsive && $.each(responsive_keys, function(i, key){ truescale[key]= get(key) });\r\n css(____+___+dot(klass), { display: _block_ });\r\n css(dot(cache_klass), { position: 'fixed', left: px(-100), top: px(-100) }, true);\r\n css(dot(cache_klass)+___+_img_, { position: _absolute_, width: 10, height: 10 }, true);\r\n pool.bind(on.pool);\r\n t.trigger(shy ? 'prepare' : 'setup')\r\n },\r\n\r\n // ------\r\n // Events\r\n // ------\r\n //\r\n // Reel is completely event-driven meaning there are many events, which can be called\r\n // (triggered). By binding event handler to any of the events you can easily hook on to any\r\n // event to inject your custom behavior where and when this event was triggered.\r\n //\r\n // _**Example:** Make `#image` element reel and execute some code right after the newly\r\n // created instance is initialized and completely loaded:_\r\n //\r\n // $(\"#image\")\r\n // .reel()\r\n // .bind(\"loaded\", function(ev){\r\n // // Your code\r\n // })\r\n //\r\n\r\n // Events bound to all individual instances.\r\n //\r\n instance: {\r\n\r\n // ### `teardown` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // This event does do how it sounds like. It will teardown an instance with all its\r\n // belongings leaving no trace.\r\n //\r\n // - It reconstructs the original `
![]()
` element,\r\n // - wipes out the data store,\r\n // - removes instance stylesheet\r\n // - and unbinds all its events.\r\n //\r\n teardown: function(e){\r\n var\r\n backup= t.data(_backup_)\r\n t.parent().unbind(on.instance);\r\n if (get(_shy_)) t.parent().unbind(_click_, shy_setup)\r\n else get(_style_).remove() && get(_area_).unbind(ns);\r\n get(_cache_).empty();\r\n clearTimeout(delay);\r\n clearTimeout(gauge_delay);\r\n $(window).unbind(_resize_, slow_gauge);\r\n $(window).unbind(ns);\r\n pool.unbind(on.pool);\r\n pools.unbind(pns);\r\n t.siblings().unbind(ns).remove();\r\n no_bias();\r\n t.removeAttr('onloaded');\r\n remove_instance(t.unbind(ns).removeData().unwrap().attr(backup.attr).data(backup.data));\r\n t.attr(_style_) == __ && t.removeAttr(_style_);\r\n },\r\n\r\n // ### `setup` Event ######\r\n // `Event`, since 1.0\r\n //\r\n // `\"setup\"` Event continues with what has been started by the private `on.setup()`\r\n // handler.\r\n //\r\n // - It prepares all additional on-stage DOM elements\r\n // - and cursors for the instance stylesheet.\r\n //\r\n setup: function(e){\r\n var\r\n $overlay= t.parent().append(preloader()),\r\n $area= set(_area_, $(opt.area || $overlay )),\r\n multirow= opt.rows > 1,\r\n cursor= opt.cursor,\r\n cursor_up= cursor == _hand_ ? drag_cursor : cursor || reel_cursor,\r\n cursor_down= cursor == _hand_ ? drag_cursor_down+___+'!important' : undefined\r\n css(___+dot(klass), { MozUserSelect: _none_, WebkitUserSelect: _none_, MozTransform: 'translateZ(0)' });\r\n t.unbind(_click_, shy_setup);\r\n $area\r\n .bind(_touchstart_, press)\r\n .bind(opt.clickfree ? _mouseenter_ : _mousedown_, press)\r\n .bind(opt.wheelable ? _mousewheel_ : null, wheel)\r\n .bind(_dragstart_, function(){ return false })\r\n css(__, { cursor: cdn(cursor_up) });\r\n css(dot(loading_klass), { cursor: 'wait' });\r\n css(dot(panning_klass)+____+dot(panning_klass)+' *', { cursor: cdn(cursor_down || cursor_up) }, true);\r\n if (get(_responsive_)){\r\n css(___+dot(klass), { width: '100%', height: _auto_ });\r\n $(window).bind(_resize_, slow_gauge);\r\n }\r\n function press(e){ return t.trigger('down', [pointer(e).clientX, pointer(e).clientY, e]) && e.give }\r\n function wheel(e, delta){ return !delta || t.trigger('wheel', [delta, e]) && e.give }\r\n opt.hint && $area.attr('title', opt.hint);\r\n opt.indicator && $overlay.append(indicator('x'));\r\n multirow && opt.indicator && $overlay.append(indicator('y'));\r\n opt.monitor && $overlay.append($monitor= $(tag(_div_), { 'class': monitor_klass }))\r\n && css(___+dot(monitor_klass), { position: _absolute_, left: 0, top: 0 });\r\n },\r\n\r\n // ### `preload` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // Reel keeps a cache of all images it needs for its operation. Either a sprite or all\r\n // sequence images. It first determines the order of requesting the images and then\r\n // asynchronously loads all of them.\r\n //\r\n // - It preloads all frames and sprites.\r\n //\r\n preload: function(e){\r\n var\r\n $overlay= t.parent(),\r\n images= get(_images_),\r\n is_sprite= !images.length,\r\n order= reel.preload[opt.preload] || reel.preload[reel.def.preload],\r\n preload= is_sprite ? [get(_image_)] : order(images.slice(0), opt, get),\r\n to_load= preload.length,\r\n preloaded= set(_preloaded_, is_sprite ? 0.5 : 0),\r\n simultaneous= 0,\r\n $cache= get(_cache_).empty(),\r\n uris= []\r\n $overlay.addClass(loading_klass);\r\n // It also finalizes the instance stylesheet and prepends it to the head.\r\n set(_style_, get(_style_) || $('<'+_style_+' type=\"text/css\">'+css.rules.join('\\n')+''+_style_+'>').prependTo(_head_));\r\n set(_loading_, true);\r\n t.trigger('stop');\r\n opt.responsive && gauge();\r\n t.trigger('resize', true);\r\n while(preload.length){\r\n var\r\n uri= reel.substitute(opt.path+preload.shift(), get),\r\n $img= $(tag(_img_)).data(_src_, uri).appendTo($cache)\r\n // Each image, which finishes the load triggers `\"preloaded\"` Event.\r\n $img.bind('load error abort', function(e){\r\n e.type != 'load' && t.trigger(e.type);\r\n return !detached($overlay) && t.trigger('preloaded') && load() && false;\r\n });\r\n uris.push(uri);\r\n }\r\n setTimeout(function(){ while (++simultaneous < reel.concurrent_requests) load(); }, 0);\r\n set(_cached_, uris);\r\n set(_shy_, false);\r\n function load(){\r\n var\r\n $img= $cache.children(':not([src]):first')\r\n return $img.attr(_src_, $img.data(_src_))\r\n }\r\n },\r\n\r\n // ### `preloaded` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // This event is fired by every preloaded image and adjusts the preloader indicator's\r\n // target position. Once all images are preloaded, `\"loaded\"` Event is triggered.\r\n //\r\n preloaded: function(e){\r\n var\r\n images= get(_images_).length || 1,\r\n preloaded= set(_preloaded_, min(get(_preloaded_) + 1, images))\r\n if (preloaded === 1) var\r\n frame= t.trigger('frameChange', [undefined, get(_frame_)])\r\n if (preloaded === images){\r\n t.parent().removeClass(loading_klass);\r\n t.trigger('loaded');\r\n }\r\n },\r\n\r\n // ### `loaded` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // `\"loaded\"` Event is the one announcing when the instance is \"locked and loaded\".\r\n // At this time, all is prepared, preloaded and configured for user interaction\r\n // or animation.\r\n //\r\n loaded: function(e){\r\n get(_images_).length > 1 || t.css({ backgroundImage: url(reel.substitute(opt.path+get(_image_), get)) }).attr({ src: cdn(transparent) });\r\n get(_stitched_) && t.attr({ src: cdn(transparent) });\r\n get(_reeled_) || set(_velocity_, opt.velocity || 0);\r\n set(_loading_, false);\r\n loaded= true;\r\n },\r\n\r\n // ### `prepare` Event ######\r\n // [NEW] `Event`, since 1.3\r\n //\r\n // In case of `shy` activation, `\"prepare\"` event is called instead of the full `\"setup\"`.\r\n // It lefts the target image untouched waiting to be clicked to actually setup.\r\n //\r\n prepare: function(e){\r\n t.css('display', _block_).parent().one(_click_, shy_setup);\r\n },\r\n\r\n // ----------------\r\n // Animation Events\r\n // ----------------\r\n //\r\n // ### `opening` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // When [opening animation](#Opening-Animation) is configured for the instance, `\"opening\"`\r\n // event engages the animation by pre-calculating some of its properties, which will make\r\n // the tick handler\r\n //\r\n opening: function(e){\r\n /*\r\n - initiates opening animation\r\n - or simply plays the reel when without opening\r\n */\r\n if (!opt.opening) return t.trigger('openingDone');\r\n var\r\n opening= set(_opening_, true),\r\n stopped= set(_stopped_, !get(_speed_)),\r\n speed= opt.entry || opt.speed,\r\n end= get(_fraction_),\r\n duration= opt.opening,\r\n start= set(_fraction_, end - speed * duration),\r\n ticks= set(_opening_ticks_, ceil(duration * leader(_tempo_)))\r\n },\r\n\r\n // ### `openingDone` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // `\"openingDone\"` is fired onceWhen [opening animation](#Opening-Animation) is configured for the instance, `\"opening\"`\r\n // event engages the animation by pre-calculating some of its properties, which will make\r\n // the tick handler\r\n //\r\n openingDone: function(e){\r\n var\r\n playing= set(_playing_, false),\r\n opening= set(_opening_, false),\r\n evnt= _tick_+dot(_opening_)\r\n pool.unbind(evnt, on.pool[evnt]);\r\n opt.orientable && $(window).bind(_deviceorientation_, orient);\r\n if (opt.delay > 0) delay= setTimeout(function(){ t.trigger('play') }, opt.delay * 1000)\r\n else t.trigger('play');\r\n function orient(e){ return t.trigger('orient', [gyro(e).alpha, gyro(e).beta, gyro(e).gamma, e]) && e.give }\r\n },\r\n\r\n // -----------------------\r\n // Playback Control Events\r\n // -----------------------\r\n //\r\n // ### `play` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // `\"play\"` event can optionally accept a `speed` parameter (in Hz) to change the animation\r\n // speed on the fly.\r\n //\r\n play: function(e, speed){\r\n var\r\n speed= speed ? set(_speed_, speed) : (get(_speed_) * negative_when(1, get(_backwards_))),\r\n duration= opt.duration,\r\n ticks= duration && set(_ticks_, ceil(duration * leader(_tempo_))),\r\n backwards= set(_backwards_, speed < 0),\r\n playing= set(_playing_, !!speed),\r\n stopped= set(_stopped_, !playing)\r\n idle();\r\n },\r\n\r\n // ### `reach` Event ######\r\n // [NEW] `Event`, since 1.3\r\n //\r\n // Use this event to instruct Reel to play and reach a given frame. `\"reach\"` event requires\r\n // `target` parameter, which is the frame to which Reel should animate to and stop.\r\n // Optional `speed` parameter allows for custom speed independent on the regular speed.\r\n //\r\n reach: function(e, target, speed){\r\n if (target == get(_frame_)) return;\r\n var\r\n frames= get(_frames_),\r\n row= set(_row_, ceil(target / frames)),\r\n departure= set(_departure_, get(_frame_)),\r\n target= set(_destination_, target),\r\n shortest = set(_distance_, reel.math.distance(departure, target, frames)),\r\n speed= abs(speed || get(_speed_)) * negative_when(1, shortest < 0)\r\n t.trigger('play', speed);\r\n },\r\n\r\n // ### `pause` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // Triggering `\"pause\"` event will halt the playback for a time period designated\r\n // by the `timeout` option. After this timenout, the playback is resumed again.\r\n //\r\n pause: function(e){\r\n unidle();\r\n },\r\n\r\n // ### `stop` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // After `\"stop\"` event is triggered, the playback stops and stays still until `\"play\"`ed again.\r\n //\r\n stop: function(e){\r\n var\r\n stopped= set(_stopped_, true),\r\n playing= set(_playing_, !stopped)\r\n },\r\n\r\n // ------------------------\r\n // Human Interaction Events\r\n // ------------------------\r\n //\r\n // ### `down` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // Marks the very beginning of touch or mouse interaction. It receives `x` and `y`\r\n // coordinates in arguments.\r\n //\r\n // - It calibrates the center point (origin),\r\n // - considers user active not idle,\r\n // - flags the `` tag with `.reel-panning` class name\r\n // - and binds dragging events for move and lift. These\r\n // are usually bound to the pool (document itself) to get a consistent treating regardless\r\n // the event target element. However in click-free mode, it binds directly to the instance.\r\n //\r\n down: function(e, x, y, ev){\r\n if (!opt.clickfree && ev && ev.button !== undefined && ev.button != DRAG_BUTTON) return;\r\n if (opt.draggable){\r\n var\r\n clicked= set(_clicked_, get(_frame_)),\r\n clickfree= opt.clickfree,\r\n velocity= set(_velocity_, 0),\r\n $area= clickfree ? get(_area_) : pools,\r\n origin= last= recenter_mouse(get(_revolution_), x, y)\r\n unidle();\r\n no_bias();\r\n panned= 0;\r\n $(_html_, pools).addClass(panning_klass);\r\n $area\r\n .bind(_touchmove_+___+_mousemove_, drag)\r\n .bind(_touchend_+___+_touchcancel_, lift)\r\n .bind(clickfree ? _mouseleave_ : _mouseup_, lift)\r\n }\r\n function drag(e){ return t.trigger('pan', [pointer(e).clientX, pointer(e).clientY, e]) && e.give }\r\n function lift(e){ return t.trigger('up', [e]) && e.give }\r\n },\r\n\r\n // ### `up` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // This marks the termination of user's interaction. She either released the mouse button\r\n // or lift the finger of the touch screen. This event handler:\r\n //\r\n // - calculates the velocity of the drag at that very moment,\r\n // - removes the `.reel-panning` class from ``\r\n // - and unbinds dragging events from the pool.\r\n //\r\n up: function(e, ev){\r\n var\r\n clicked= set(_clicked_, false),\r\n reeling= set(_reeling_, false),\r\n throwable = opt.throwable,\r\n biases= abs(bias[0] + bias[1]) / 60,\r\n velocity= set(_velocity_, !throwable ? 0 : throwable === true ? biases : min(throwable, biases)),\r\n brakes= braking= velocity ? 1 : 0\r\n unidle();\r\n no_bias();\r\n $(_html_, pools).removeClass(panning_klass);\r\n (opt.clickfree ? get(_area_) : pools).unbind(pns);\r\n },\r\n\r\n // ### `pan` Event ######\r\n // [RENAMED] `Event`, since 1.2\r\n //\r\n // Regardles the actual source of movement (mouse or touch), this event is always triggered\r\n // in response and similar to the `\"down\"` Event it receives `x` and `y` coordinates\r\n // in arguments and in addition it is passed a reference to the original browser event.\r\n // This handler:\r\n //\r\n // - syncs with timer to achieve good performance,\r\n // - calculates the distance from drag center and applies graph on it to get `fraction`,\r\n // - recenters the drag when dragged over limits,\r\n // - detects the direction of the motion\r\n // - and builds up inertial motion bias.\r\n //\r\n // Historically `pan` was once called `slide` (conflicted with Mootools - [GH-51][1])\r\n // or `drag` (that conflicted with MSIE).\r\n //\r\n // [1]:https://github.com/pisi/Reel/issues/51\r\n //\r\n pan: function(e, x, y, ev){\r\n if (opt.draggable && slidable){\r\n slidable= false;\r\n unidle();\r\n var\r\n rows= opt.rows,\r\n orbital= opt.orbital,\r\n scrollable= !get(_reeling_) && rows <= 1 && !orbital && opt.scrollable,\r\n delta= { x: x - last.x, y: y - last.y },\r\n abs_delta= { x: abs(delta.x), y: abs(delta.y) }\r\n if (ev && scrollable && abs_delta.x < abs_delta.y) return ev.give = true;\r\n if (abs_delta.x > 0 || abs_delta.y > 0){\r\n ev && (ev.give = false);\r\n panned= max(abs_delta.x, abs_delta.y);\r\n last= { x: x, y: y };\r\n var\r\n revolution= get(_revolution_),\r\n origin= get(_clicked_location_),\r\n vertical= get(_vertical_)\r\n if (!get(_framelock_)) var\r\n fraction= set(_fraction_, graph(vertical ? y - origin.y : x - origin.x, get(_clicked_on_), revolution, get(_lo_), get(_hi_), get(_cwish_), vertical ? y - origin.y : x - origin.x)),\r\n reeling= set(_reeling_, get(_reeling_) || get(_frame_) != get(_clicked_)),\r\n motion= to_bias(vertical ? delta.y : delta.x || 0),\r\n backwards= motion && set(_backwards_, motion < 0)\r\n if (orbital && get(_center_)) var\r\n vertical= set(_vertical_, abs(y - origin.y) > abs(x - origin.x)),\r\n origin= recenter_mouse(revolution, x, y)\r\n if (rows > 1 && !get(_rowlock_)) var\r\n revolution_y= get(_revolution_y_),\r\n start= get(_clicked_tier_),\r\n lo= - start * revolution_y,\r\n tier= set(_tier_, reel.math.envelope(y - origin.y, start, revolution_y, lo, lo + revolution_y, -1))\r\n if (!(fraction % 1) && !opt.loops) var\r\n origin= recenter_mouse(revolution, x, y)\r\n }\r\n }\r\n },\r\n\r\n // ### `wheel` Event ######\r\n // `Event`, since 1.0\r\n //\r\n // Maps Reel to mouse wheel position change event which is provided by a nifty plug-in\r\n // written by Brandon Aaron - the [Mousewheel plug-in][1], which you will need to enable\r\n // the mousewheel wheel for reeling. You can also choose to use [Wheel Special Event\r\n // plug-in][2] by Three Dub Media instead. Either way `\"wheel\"` Event handler receives\r\n // the positive or negative wheeled distance in arguments. This event:\r\n //\r\n // - calculates wheel input delta and adjusts the `fraction` using the graph,\r\n // - recenters the \"drag\" each and every time,\r\n // - detects motion direction\r\n // - and nullifies the velocity.\r\n //\r\n // [1]:https://github.com/brandonaaron/jquery-mousewheel\r\n // [2]:http://blog.threedubmedia.com/2008/08/eventspecialwheel.html\r\n //\r\n wheel: function(e, distance, ev){\r\n if (!distance) return;\r\n wheeled= true;\r\n var\r\n delta= ceil(math.sqrt(abs(distance)) / 2),\r\n delta= negative_when(delta, distance > 0),\r\n revolution= 0.0833 * get(_revolution_), // Wheel's revolution is 1/12 of full revolution\r\n origin= recenter_mouse(revolution),\r\n backwards= delta && set(_backwards_, delta < 0),\r\n velocity= set(_velocity_, 0),\r\n fraction= set(_fraction_, graph(delta, get(_clicked_on_), revolution, get(_lo_), get(_hi_), get(_cwish_)))\r\n ev && ev.preventDefault();\r\n ev && (ev.give = false);\r\n unidle();\r\n t.trigger('up', [ev]);\r\n },\r\n\r\n // ### `orient` Event ######\r\n // [NEW] `Event`, since 1.3\r\n //\r\n // Maps Reel to device orientation event which is provided by some touch enabled devices\r\n // with gyroscope inside. Event handler receives all three device orientation angles \r\n // in arguments. This event:\r\n //\r\n // - maps alpha angle directly to `fraction`\r\n //\r\n orient: function(e, alpha, beta, gamma, ev){\r\n if (!slidable || operated) return;\r\n oriented= true;\r\n var\r\n alpha_fraction= alpha / 360\r\n fraction= set(_fraction_, +((opt.stitched || opt.cw ? 1 - alpha_fraction : alpha_fraction)).toFixed(2))\r\n slidable = false;\r\n },\r\n\r\n // ------------------\r\n // Data Change Events\r\n // ------------------\r\n //\r\n // Besides Reel being event-driven, it also is data-driven respectively data-change-driven\r\n // meaning that there is a mechanism in place, which detects real changes in data being\r\n // stored with `.reel(name, value)`. Learn more about [data changes](#Changes).\r\n //\r\n // These data change bindings are for internal use only and you don't ever trigger them\r\n // per se, you change data and that will trigger respective change event. If the value\r\n // being stored is the same as the one already stored, nothing will be triggered.\r\n //\r\n // _**Example:** Change Reel's current `frame`:_\r\n //\r\n // .reel(\"frame\", 15)\r\n //\r\n // Change events always receive the actual data key value in the third argument.\r\n //\r\n // _**Example:** Log each viewed frame number into the developers console:_\r\n //\r\n // .bind(\"frameChange\", function(e, d, frame){\r\n // console.log(frame)\r\n // })\r\n //\r\n // ---\r\n\r\n // ### `fractionChange` Event ######\r\n // `Event`, since 1.0\r\n //\r\n // Internally Reel doesn't really work with the frames you set it up with. It uses\r\n // __fraction__, which is a numeric value ranging from 0.0 to 1.0. When `fraction` changes\r\n // this handler basically calculates and sets new value of `frame`.\r\n //\r\n fractionChange: function(e, nil, fraction){\r\n if (nil !== undefined) return;\r\n var\r\n frame= 1 + floor(fraction / get(_bit_)),\r\n multirow= opt.rows > 1,\r\n orbital= opt.orbital,\r\n center= set(_center_, !!orbital && (frame <= orbital || frame >= get(_footage_) - orbital + 2))\r\n if (multirow) var\r\n frame= frame + (get(_row_) - 1) * get(_frames_)\r\n var\r\n frame= set(_frame_, frame)\r\n },\r\n\r\n // ### `tierChange` Event ######\r\n // `Event`, since 1.2\r\n //\r\n // The situation of `tier` is very much similar to the one of `fraction`. In multi-row\r\n // movies, __tier__ is an internal value for the vertical axis. Its value also ranges from\r\n // 0.0 to 1.0. Handler calculates and sets new value of `frame`.\r\n //\r\n tierChange: function(e, nil, tier){\r\n if (nil === undefined) var\r\n row= set(_row_, round(interpolate(tier, 1, opt.rows))),\r\n frames= get(_frames_),\r\n frame= get(_frame_) % frames || frames,\r\n frame= set(_frame_, frame + row * frames - frames)\r\n },\r\n\r\n // ### `rowChange` Event ######\r\n // `Event`, since 1.1\r\n //\r\n // The physical vertical position of Reel is expressed in __rows__ and ranges\r\n // from 1 to the total number of rows defined with [`rows`](#rows-Option). This handler\r\n // only converts `row` value to `tier` and sets it.\r\n //\r\n rowChange: function(e, nil, row){\r\n if (nil === undefined) var\r\n tier= may_set(_tier_, undefined, row, opt.rows)\r\n },\r\n\r\n // ### `frameChange` Event ######\r\n // `Event`, since 1.0\r\n //\r\n // The physical horizontal position of Reel is expressed in __frames__ and ranges\r\n // from 1 to the total number of frames configured with [`frames`](#frames-Option).\r\n // This handler converts `row` value to `tier` and sets it. This default handler:\r\n //\r\n // - flags the instance's outter wrapper with `.frame-X` class name\r\n // (where `X` is the actual frame number),\r\n // - calculates and eventually sets `fraction` (and `tier` for multi-rows) from given frame,\r\n // - for sequences, it switches the `
![]()
`'s `src` to the right frame\r\n // - and for sprites it recalculates sprite's 'background position shift and applies it.\r\n //\r\n frameChange: function(e, nil, frame){\r\n if (nil !== undefined) return;\r\n this.className= this.className.replace(reel.re.frame_klass, frame_klass + frame);\r\n var\r\n frames= get(_frames_),\r\n rows= opt.rows,\r\n path= opt.path,\r\n base= frame % frames || frames,\r\n frame_row= (frame - base) / frames + 1,\r\n frame_tier= (frame_row - 1) / (rows - 1),\r\n row= get(_row_),\r\n tier= !rows ? get(_tier_) : may_set(_tier_, frame_tier, row, rows),\r\n fraction= may_set(_fraction_, undefined, base, frames),\r\n footage= get(_footage_)\r\n if (opt.orbital && get(_vertical_)) var\r\n frame= opt.inversed ? footage + 1 - frame : frame,\r\n frame= frame + footage\r\n var\r\n stitched= get(_stitched_),\r\n images= get(_images_),\r\n is_sprite= !images.length || stitched\r\n if (!is_sprite){\r\n get(_responsive_) && gauge();\r\n get(_preloaded_) && t.attr({ src: reen(reel.substitute(path + images[frame - 1], get)) });\r\n }else{\r\n var\r\n spacing= get(_spacing_),\r\n width= get(_width_),\r\n height= get(_height_)\r\n if (!stitched) var\r\n horizontal= opt.horizontal,\r\n minor= (frame % footage) - 1,\r\n minor= minor < 0 ? footage - 1 : minor,\r\n major= floor((frame - 0.1) / footage),\r\n major= major + (rows > 1 ? 0 : (get(_backwards_) ? 0 : !opt.directional ? 0 : get(_rows_))),\r\n a= major * ((horizontal ? height : width) + spacing),\r\n b= minor * ((horizontal ? width : height) + spacing),\r\n shift= images.length ? [0, 0] : horizontal ? [px(-b), px(-a)] : [px(-a), px(-b)]\r\n else{\r\n var\r\n x= set(_stitched_shift_, round(interpolate(fraction, 0, get(_stitched_travel_))) % stitched),\r\n y= rows <= 1 ? 0 : (height + spacing) * (rows - row),\r\n shift= [px(-x), px(-y)],\r\n image= images.length > 1 && images[row - 1],\r\n fullpath= reel.substitute(path + image, get)\r\n image && t.css('backgroundImage').search(fullpath) < 0 && t.css({ backgroundImage: url(fullpath) })\r\n }\r\n t.css({ backgroundPosition: shift.join(___) })\r\n }\r\n },\r\n\r\n // This extra binding takes care of watching frame position while animating the `\"reach\"` event.\r\n //\r\n 'frameChange.reach': function(e, nil, frame){\r\n if (!get(_destination_) || nil !== undefined) return;\r\n var\r\n travelled= reel.math.distance(get(_departure_), frame, get(_frames_)),\r\n onorover= abs(travelled) >= abs(get(_distance_))\r\n if (!onorover) return;\r\n set(_frame_, set(_destination_));\r\n set(_destination_, set(_distance_, set(_departure_, 0)));\r\n t.trigger('stop');\r\n },\r\n\r\n // ~~~\r\n //\r\n // When `image` or `images` is changed on the fly, this handler resets the loading cache and triggers\r\n // new preload sequence. Images are actually switched only after the new image is fully loaded.\r\n //\r\n 'imageChange imagesChange': function(e, nil, image){\r\n t.trigger('preload');\r\n },\r\n\r\n // ---------\r\n // Indicator\r\n // ---------\r\n //\r\n // When configured with the [`indicator`](#indicator-Option) option, Reel adds to the scene\r\n // a visual indicator in a form of a black rectangle traveling along the bottom edge\r\n // of the image. It bears two distinct messages:\r\n //\r\n // - its horizontal position accurately reflects actual `fraction`\r\n // - and its width reflect one frame's share on the whole (more frames mean narrower\r\n // indicator).\r\n //\r\n 'fractionChange.indicator': function(e, nil, fraction){\r\n if (opt.indicator && nil === undefined) var\r\n size= opt.indicator,\r\n orbital= opt.orbital,\r\n travel= orbital && get(_vertical_) ? get(_height_) : get(_width_),\r\n slots= orbital ? get(_footage_) : opt.images.length || get(_frames_),\r\n weight= ceil(travel / slots),\r\n travel= travel - weight,\r\n indicate= round(interpolate(fraction, 0, travel)),\r\n indicate= !opt.cw || get(_stitched_) ? indicate : travel - indicate,\r\n $indicator= indicator.$x.css(get(_vertical_)\r\n ? { left: 0, top: px(indicate), bottom: _auto_, width: size, height: weight }\r\n : { bottom: 0, left: px(indicate), top: _auto_, width: weight, height: size })\r\n },\r\n\r\n // For multi-row object movies, there's a second indicator sticked to the left edge\r\n // and communicates:\r\n //\r\n // - its vertical position accurately reflects actual `tier`\r\n // - and its height reflect one row's share on the whole (more rows mean narrower\r\n // indicator).\r\n //\r\n 'tierChange.indicator': function(e, nil, tier){\r\n if (opt.rows > 1 && opt.indicator && nil === undefined) var\r\n travel= get(_height_),\r\n size= opt.indicator,\r\n weight= ceil(travel / opt.rows),\r\n travel= travel - weight,\r\n indicate= round(tier * travel),\r\n $yindicator= indicator.$y.css({ left: 0, top: indicate, width: size, height: weight })\r\n },\r\n\r\n // Indicators are bound to `fraction` or `row` changes, meaning they alone can consume\r\n // more CPU resources than the entire Reel scene. Use them for development only.\r\n //\r\n\r\n // -----------\r\n // Annotations\r\n // -----------\r\n //\r\n // If you want to annotate features of your scene to better describe the subject,\r\n // there's annotations for you. Annotations feature allows you to place virtually any\r\n // HTML content over or into the image and have its position and visibility synchronized\r\n // with the position of Reel. These two easy looking handlers do a lot more than to fit\r\n // in here.\r\n //\r\n // Learn more about [Annotations][1] in the wiki, where a great care has been taken\r\n // to in-depth explain this new exciting functionality.\r\n //\r\n // [1]:https://github.com/pisi/Reel/wiki/Annotations\r\n //\r\n 'setup.annotations': function(e){\r\n var\r\n $overlay= t.parent()\r\n $.each(get(_annotations_), function(ida, note){\r\n var\r\n $note= typeof note.node == _string_ ? $(note.node) : note.node || {},\r\n $note= $note.jquery ? $note : $(tag(_div_), $note),\r\n $note= $note.attr({ id: ida }).addClass(annotation_klass),\r\n $image= note.image ? $(tag(_img_), note.image) : $(),\r\n $link= note.link ? $(tag('a'), note.link).click(function(){ t.trigger('up.annotations', { target: $link }); }) : $()\r\n css(hash(ida), { display: _none_, position: _absolute_ }, true);\r\n note.image || note.link && $note.append($link);\r\n note.link || note.image && $note.append($image);\r\n note.link && note.image && $note.append($link.append($image));\r\n $note.appendTo($overlay);\r\n });\r\n },\r\n 'prepare.annotations': function(e){\r\n $.each(get(_annotations_), function(ida, note){\r\n $(hash(ida)).hide();\r\n });\r\n },\r\n 'frameChange.annotations': function(e, nil, frame){\r\n if (!get(_preloaded_) || nil !== undefined) return;\r\n var\r\n width= get(_width_),\r\n stitched= get(_stitched_),\r\n ss= get(_stitched_shift_)\r\n $.each(get(_annotations_), function(ida, note){\r\n var\r\n $note= $(hash(ida)),\r\n start= note.start || 1,\r\n end= note.end,\r\n frame= frame || get(_frame_),\r\n offset= frame - 1,\r\n at= note.at ? (note.at[offset] == '+') : false,\r\n offset= note.at ? offset : offset - start + 1,\r\n x= typeof note.x!=_object_ ? note.x : note.x[offset],\r\n y= typeof note.y!=_object_ ? note.y : note.y[offset],\r\n placed= x !== undefined && y !== undefined,\r\n visible= placed && (note.at ? at : (offset >= 0 && (!end || offset <= end - start)))\r\n if (stitched) var\r\n on_edge= x < width && ss > stitched - width,\r\n after_edge= x > stitched - width && ss >= 0 && ss < width,\r\n x= !on_edge ? x : x + stitched,\r\n x= !after_edge ? x : x - stitched,\r\n x= x - ss\r\n if (get(_responsive_)) var\r\n ratio= get(_ratio_),\r\n x= x && x * ratio,\r\n y= y && y * ratio\r\n var\r\n style= { display: visible ? _block_:_none_, left: px(x), top: px(y) }\r\n $note.css(style);\r\n });\r\n },\r\n 'up.annotations': function(e, ev){\r\n if (panned > 10 || wheeled) return;\r\n var\r\n $target= $(ev.target),\r\n $link= ($target.is('a') ? $target : $target.parents('a')),\r\n href= $link.attr('href')\r\n href && (panned= 10);\r\n },\r\n\r\n // ---------------------\r\n // Click Stepping Events\r\n // ---------------------\r\n //\r\n // For devices without drag support or for developers, who want to use some sort\r\n // of left & right buttons on their site to control your instance from outside, Reel\r\n // supports ordinary click with added detection of left half or right half and resulting\r\n // triggering of `stepLeft` and `stepRight` events respectively.\r\n //\r\n // This behavior can be disabled by the [`steppable`](#steppable-Option) option.\r\n //\r\n 'up.steppable': function(e, ev){\r\n if (panned || wheeled) return;\r\n t.trigger(get(_clicked_location_).x - t.offset().left > 0.5 * get(_width_) ? 'stepRight' : 'stepLeft')\r\n },\r\n 'stepLeft stepRight': function(e){\r\n unidle();\r\n },\r\n\r\n // ### `stepLeft` Event ######\r\n // `Event`, since 1.2\r\n //\r\n stepLeft: function(e){\r\n set(_backwards_, false);\r\n set(_fraction_, get(_fraction_) - get(_bit_) * get(_cwish_));\r\n },\r\n\r\n // ### `stepRight` Event ######\r\n // `Event`, since 1.2\r\n //\r\n stepRight: function(e){\r\n set(_backwards_, true);\r\n set(_fraction_, get(_fraction_) + get(_bit_) * get(_cwish_));\r\n },\r\n\r\n // ### `stepUp` Event ######\r\n // [NEW] `Event`, since 1.3\r\n //\r\n stepUp: function(e){\r\n set(_row_, get(_row_) - 1);\r\n },\r\n\r\n // ### `stepDown` Event ######\r\n // [NEW] `Event`, since 1.3\r\n //\r\n stepDown: function(e){\r\n set(_row_, get(_row_) + 1);\r\n },\r\n\r\n // -----------------------\r\n // [NEW] Responsive Events\r\n // -----------------------\r\n //\r\n // In responsive mode in case of parent's size change, in addition to actual recalculations,\r\n // the instance starts to emit throttled `resize` events. This handler in turn emulates\r\n // images changes event leading to reload of frames.\r\n //\r\n // ---\r\n //\r\n // ### `resize` Event ######\r\n // [NEW] `Event`, since 1.3\r\n //\r\n resize: function(e, force){\r\n if (get(_loading_) && !force) return;\r\n var\r\n stitched= get(_stitched_),\r\n spacing= get(_spacing_),\r\n height= get(_height_),\r\n is_sprite= !get(_images_).length || stitched,\r\n rows= opt.rows || 1,\r\n size= get(_images_).length\r\n ? !stitched ? undefined : px(stitched)+___+px(height)\r\n : stitched && px(stitched)+___+px((height + spacing) * rows - spacing)\r\n || px((get(_width_) + spacing) * get(_footage_) - spacing)+___+px((height + spacing) * get(_rows_) * rows * (opt.directional? 2:1) - spacing)\r\n t.css({\r\n height: is_sprite ? px(height) : null,\r\n backgroundSize: size || null\r\n });\r\n force || t.trigger('imagesChange');\r\n },\r\n\r\n // ----------------\r\n // Follow-up Events\r\n // ----------------\r\n //\r\n // When some event as a result triggers another event, it preferably is not triggered\r\n // directly, because it would disallow preventing the event propagation / chaining\r\n // to happen. Instead a followup handler is bound to the first event and it triggers the\r\n // second one.\r\n //\r\n 'setup.fu': function(e){\r\n var\r\n frame= set(_frame_, opt.frame + (get(_row_) - 1) * get(_frames_))\r\n t.trigger('preload')\r\n },\r\n 'wheel.fu': function(){ wheeled= false },\r\n 'clean.fu': function(){ t.trigger('teardown') },\r\n 'loaded.fu': function(){ t.trigger('opening') }\r\n },\r\n\r\n // -------------\r\n // Tick Handlers\r\n // -------------\r\n //\r\n // As opposed to the events bound to the instance itself, there is a [ticker](#Ticker)\r\n // in place, which emits `tick.reel` event on the document level by default every 1/36\r\n // of a second and drives all the animations. Three handlers currently bind each instance\r\n // to the tick.\r\n //\r\n pool: {\r\n\r\n // This handler has a responsibility of continuously updating the preloading indicator\r\n // until all images are loaded and to unbind itself then.\r\n //\r\n 'tick.reel.preload': function(e){\r\n if (!(loaded || get(_loading_)) || get(_shy_)) return;\r\n var\r\n width= get(_width_),\r\n current= number(preloader.$.css(_width_)),\r\n images= get(_images_).length || 1,\r\n target= round(1 / images * get(_preloaded_) * width)\r\n preloader.$.css({ width: current + (target - current) / 3 + 1 })\r\n if (get(_preloaded_) === images && current > width - 1){\r\n loaded= false;\r\n preloader.$.fadeOut(300, function(){ preloader.$.css({ opacity: 1, width: 0 }) });\r\n }\r\n },\r\n\r\n // This handler binds to the document's ticks at all times, regardless the situation.\r\n // It serves several tasks:\r\n //\r\n // - keeps track of how long the instance is being operated by the user,\r\n // - or for how long it is braking the velocity inertia,\r\n // - decreases gained velocity by applying power of the [`brake`](#brake-Option) option,\r\n // - flags the instance as `slidable` again, so that `pan` event handler can be executed\r\n // again,\r\n // - updates the [`monitor`](#monitor-Option) value,\r\n // - bounces off the edges for non-looping panoramas,\r\n // - and most importantly it animates the Reel if [`speed`](#speed-Option) is configured.\r\n //\r\n 'tick.reel': function(e){\r\n if (get(_shy_)) return;\r\n var\r\n velocity= get(_velocity_),\r\n leader_tempo= leader(_tempo_),\r\n monitor= opt.monitor\r\n if (!reel.intense && offscreen()) return;\r\n if (braking) var\r\n braked= velocity - (get(_brake_) / leader_tempo * braking),\r\n velocity= set(_velocity_, braked > 0.1 ? braked : (braking= operated= 0))\r\n monitor && $monitor.text(get(monitor));\r\n velocity && braking++;\r\n operated && operated++;\r\n to_bias(0);\r\n slidable= true;\r\n if (operated && !velocity) return mute(e);\r\n if (get(_clicked_)) return mute(e, unidle());\r\n if (get(_opening_ticks_) > 0) return;\r\n if (!opt.loops && opt.rebound) var\r\n edgy= !operated && !(get(_fraction_) % 1) ? on_edge++ : (on_edge= 0),\r\n bounce= on_edge >= opt.rebound * 1000 / leader_tempo,\r\n backwards= bounce && set(_backwards_, !get(_backwards_))\r\n var\r\n direction= get(_cwish_) * negative_when(1, get(_backwards_)),\r\n ticks= get(_ticks_),\r\n step= (!get(_playing_) || oriented || !ticks ? velocity : abs(get(_speed_)) + velocity) / leader(_tempo_),\r\n fraction= set(_fraction_, get(_fraction_) - step * direction),\r\n ticks= !opt.duration ? ticks : ticks > 0 && set(_ticks_, ticks - 1)\r\n !ticks && get(_playing_) && t.trigger('stop');\r\n },\r\n\r\n // This handler performs the opening animation duty when during it the normal animation\r\n // is halted until the opening finishes.\r\n //\r\n 'tick.reel.opening': function(e){\r\n if (!get(_opening_)) return;\r\n var\r\n speed= opt.entry || opt.speed,\r\n step= speed / leader(_tempo_) * (opt.cw? -1:1),\r\n ticks= set(_opening_ticks_, get(_opening_ticks_) - 1),\r\n fraction= set(_fraction_, get(_fraction_) + step)\r\n ticks || t.trigger('openingDone');\r\n }\r\n }\r\n },\r\n\r\n loaded= false,\r\n\r\n // ------------------------\r\n // Instance Private Helpers\r\n // ------------------------\r\n //\r\n // - Events propagation stopper / muter\r\n //\r\n mute= function(e, result){ return e.stopImmediatePropagation() || result },\r\n\r\n // - Shy initialization helper\r\n //\r\n shy_setup= function(){ t.trigger('setup') },\r\n\r\n // - User idle control\r\n //\r\n operated,\r\n braking= 0,\r\n idle= function(){ return operated= 0 },\r\n unidle= function(){\r\n clearTimeout(delay);\r\n pool.unbind(_tick_+dot(_opening_), on.pool[_tick_+dot(_opening_)]);\r\n set(_opening_ticks_, 0);\r\n set(_reeled_, true);\r\n return operated= -opt.timeout * leader(_tempo_)\r\n },\r\n panned= 0,\r\n wheeled= false,\r\n oriented= false,\r\n\r\n // - Constructors of UI elements\r\n //\r\n $monitor= $(),\r\n preloader= function(){\r\n css(___+dot(preloader_klass), {\r\n position: _absolute_,\r\n left: 0, bottom: 0,\r\n height: opt.preloader,\r\n overflow: _hidden_,\r\n backgroundColor: '#000'\r\n });\r\n return preloader.$= $(tag(_div_), { 'class': preloader_klass })\r\n },\r\n indicator= function(axis){\r\n css(___+dot(indicator_klass)+dot(axis), {\r\n position: _absolute_,\r\n width: 0, height: 0,\r\n overflow: _hidden_,\r\n backgroundColor: '#000'\r\n });\r\n return indicator['$'+axis]= $(tag(_div_), { 'class': indicator_klass+___+axis })\r\n },\r\n\r\n // - CSS rules & stylesheet\r\n //\r\n css= function(selector, definition, global){\r\n var\r\n stage= global ? __ : get(_stage_),\r\n selector= selector.replace(/^/, stage).replace(____, ____+stage)\r\n return css.rules.push(selector+cssize(definition)) && definition\r\n function cssize(values){\r\n var rules= [];\r\n $.each(values, function(key, value){ rules.push(key.replace(/([A-Z])/g, '-$1').toLowerCase()+':'+px(value)+';') });\r\n return '{'+rules.join(__)+'}'\r\n }\r\n },\r\n $style,\r\n\r\n // - Off screen detection (vertical only for performance)\r\n //\r\n offscreen= function(){\r\n var\r\n height= get(_height_),\r\n width= get(_width_),\r\n rect= t[0].getBoundingClientRect()\r\n return rect.top < -height\r\n || rect.left < -width\r\n || rect.right > width + $(window).width()\r\n || rect.bottom > height + $(window).height()\r\n },\r\n\r\n // - Inertia rotation control\r\n //\r\n on_edge= 0,\r\n last= { x: 0, y: 0 },\r\n to_bias= function(value){ return bias.push(value) && bias.shift() && value },\r\n no_bias= function(){ return bias= [0,0] },\r\n bias= no_bias(),\r\n\r\n // - Graph function to be used\r\n //\r\n graph= opt.graph || reel.math[opt.loops ? 'hatch' : 'envelope'],\r\n normal= reel.normal,\r\n\r\n // - Response to the size changes in responsive mode\r\n //\r\n slow_gauge= function(){\r\n clearTimeout(gauge_delay);\r\n gauge_delay= setTimeout(gauge, reel.resize_gauge);\r\n },\r\n gauge= function(){\r\n if (t.width() == get(_width_)) return;\r\n var\r\n truescale= get(_truescale_),\r\n ratio= set(_ratio_, t.width() / truescale.width)\r\n $.each(truescale, function(key, value){ set(key, round(value * ratio)) })\r\n t.trigger('resize');\r\n },\r\n\r\n // - Delay timer pointers\r\n //\r\n delay, // openingDone's delayed play\r\n gauge_delay, // slow_gauge's throttle\r\n\r\n // - Interaction graph's zero point reset\r\n //\r\n recenter_mouse= function(revolution, x, y){\r\n var\r\n fraction= set(_clicked_on_, get(_fraction_)),\r\n tier= set(_clicked_tier_, get(_tier_)),\r\n loops= opt.loops,\r\n lo= set(_lo_, loops ? 0 : - fraction * revolution),\r\n hi= set(_hi_, loops ? revolution : revolution - fraction * revolution)\r\n return x !== undefined && set(_clicked_location_, { x: x, y: y }) || undefined\r\n },\r\n slidable= true,\r\n\r\n // ~~~\r\n //\r\n // Data interface used to set `fraction` and `tier` with the value recalculated through their\r\n // _cousin_ keys (`frame` for `fraction` and `row` for `tier`). This value is actually set\r\n // only if it does make a difference in the cousin value.\r\n //\r\n may_set= function(key, value, cousin, maximum){\r\n if (!maximum) return;\r\n var\r\n current= get(key) || 0,\r\n recalculated= value !== undefined ? value : (cousin - 1) / (maximum - 1),\r\n recalculated= key != _fraction_ ? recalculated : min( recalculated, 0.9999),\r\n worthy= +abs(current - recalculated).toFixed(8) >= +(1 / (maximum - 1)).toFixed(8),\r\n value= worthy ? set(key, recalculated) : value || current\r\n return value\r\n },\r\n\r\n // ~~~\r\n //\r\n // Global events are bound to the pool (`document`), but to make it work inside an `