vendor: 76,875 bytes, lines 1-2478
1(function (global, factory) { 2 typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : 3 typeof define === 'function' && define.amd ? define(['exports'], factory) : 4 (factory((global.SpriteSpin = {}))); 5}(this, (function (exports) { 'use strict'; 6 7/** 8 * @internal 9 */ 10var Api = /** @class */ (function () { 11 function Api(data) { 12 this.data = data; 13 } 14 return Api; 15}()); 16/** 17 * Adds methods to the SpriteSpin api 18 * 19 * @public 20 */ 21function extendApi(methods) { 22 var api = Api.prototype; 23 for (var key in methods) { 24 if (methods.hasOwnProperty(key)) { 25 if (api[key]) { 26 throw new Error('API method is already defined: ' + key); 27 } 28 else { 29 api[key] = methods[key]; 30 } 31 } 32 } 33 return api; 34} 35 36var $$1 = window.jQuery || window.$; 37 38function getCursorPosition(event) { 39 var touches = event.touches; 40 var source = event; 41 // jQuery Event normalization does not preserve the 'event.touches' 42 // try to grab touches from the original event 43 if (event.touches === undefined && event.originalEvent !== undefined) { 44 touches = event.originalEvent.touches; 45 } 46 // get current touch or mouse position 47 if (touches !== undefined && touches.length > 0) { 48 source = touches[0]; 49 } 50 return { 51 x: source.clientX || 0, 52 y: source.clientY || 0 53 }; 54} 55 56var canvas; 57var context; 58function detectionContext() { 59 if (context) { 60 return context; 61 } 62 if (!canvas) { 63 canvas = document.createElement('canvas'); 64 } 65 if (!canvas || !canvas.getContext) { 66 return null; 67 } 68 context = canvas.getContext('2d'); 69 return context; 70} 71/** 72 * Idea taken from https://github.com/stomita/ios-imagefile-megapixel 73 * Detects whether the image has been sub sampled by the browser and does not have its original dimensions. 74 * This method unfortunately does not work for images that have transparent background. 75 */ 76function detectSubsampling(img, width, height) { 77 if (!detectionContext()) { 78 return false; 79 } 80 // sub sampling happens on images above 1 megapixel 81 if (width * height <= 1024 * 1024) { 82 return false; 83 } 84 // set canvas to 1x1 pixel size and fill it with magenta color 85 canvas.width = canvas.height = 1; 86 context.fillStyle = '#FF00FF'; 87 context.fillRect(0, 0, 1, 1); 88 // render the image with a negative offset to the left so that it would 89 // fill the canvas pixel with the top right pixel of the image. 90 context.drawImage(img, -width + 1, 0); 91 // check color value to confirm image is covering edge pixel or not. 92 // if color still magenta, the image is assumed to be sub sampled. 93 try { 94 var dat = context.getImageData(0, 0, 1, 1).data; 95 return (dat[0] === 255) && (dat[1] === 0) && (dat[2] === 255); 96 } 97 catch (err) { 98 // avoids cross origin exception for chrome when code runs without a server 99 return false; 100 } 101} 102 103/** 104 * 105 */ 106function getOuterSize(data) { 107 var width = Math.floor(data.width || data.frameWidth || data.target.innerWidth()); 108 var height = Math.floor(data.height || data.frameHeight || data.target.innerHeight()); 109 return { 110 aspect: width / height, 111 height: height, 112 width: width 113 }; 114} 115function getComputedSize(data) { 116 var size = getOuterSize(data); 117 if (typeof window.getComputedStyle !== 'function') { 118 return size; 119 } 120 var style = window.getComputedStyle(data.target[0]); 121 if (!style.width) { 122 return size; 123 } 124 size.width = Math.floor(Number(style.width.replace('px', ''))); 125 size.height = Math.floor(size.width / size.aspect); 126 return size; 127} 128/** 129 * 130 */ 131function getInnerSize(data) { 132 var width = Math.floor(data.frameWidth || data.width || data.target.innerWidth()); 133 var height = Math.floor(data.frameHeight || data.height || data.target.innerHeight()); 134 return { 135 aspect: width / height, 136 height: height, 137 width: width 138 }; 139} 140/** 141 * 142 */ 143function getInnerLayout(mode, inner, outer) { 144 // get mode 145 var isFit = mode === 'fit'; 146 var isFill = mode === 'fill'; 147 var isMatch = mode === 'stretch'; 148 // resulting layout 149 var layout = { 150 width: '100%', 151 height: '100%', 152 top: 0, 153 left: 0, 154 bottom: 0, 155 right: 0, 156 position: 'absolute', 157 overflow: 'hidden' 158 }; 159 // no calculation here 160 if (!mode || isMatch) { 161 return layout; 162 } 163 // get size and aspect 164 var aspectIsGreater = inner.aspect >= outer.aspect; 165 // mode == original 166 var width = inner.width; 167 var height = inner.height; 168 // keep aspect ratio but fit/fill into container 169 if (isFit && aspectIsGreater || isFill && !aspectIsGreater) { 170 width = outer.width; 171 height = outer.width / inner.aspect; 172 } 173 if (isFill && aspectIsGreater || isFit && !aspectIsGreater) { 174 height = outer.height; 175 width = outer.height * inner.aspect; 176 } 177 // floor the numbers 178 width = Math.floor(width); 179 height = Math.floor(height); 180 // position in center 181 layout.width = width; 182 layout.height = height; 183 layout.top = Math.floor((outer.height - height) / 2); 184 layout.left = Math.floor((outer.width - width) / 2); 185 layout.right = layout.left; 186 layout.bottom = layout.top; 187 return layout; 188} 189 190var img; 191/** 192 * gets the original width and height of an image element 193 */ 194function naturalSize(image) { 195 // for browsers that support naturalWidth and naturalHeight properties 196 if (image.naturalWidth) { 197 return { 198 height: image.naturalHeight, 199 width: image.naturalWidth 200 }; 201 } 202 // browsers that do not support naturalWidth and naturalHeight properties have to fall back to the width and 203 // height properties. However, the image might have a css style applied so width and height would return the 204 // css size. To avoid that create a new Image object that is free of css rules and grab width and height 205 // properties 206 // 207 // assume that the src has already been downloaded, so no onload callback is needed. 208 img = img || new Image(); 209 img.crossOrigin = image.crossOrigin; 210 img.src = image.src; 211 return { 212 height: img.height, 213 width: img.width 214 }; 215} 216 217/** 218 * Measures the image frames that are used in the given data object 219 */ 220function measure(images, options) { 221 if (images.length === 1) { 222 return [measureSheet(images[0], options)]; 223 } 224 else if (options.framesX && options.framesY) { 225 return measureMutipleSheets(images, options); 226 } 227 else { 228 return measureFrames(images, options); 229 } 230} 231function measureSheet(image, options) { 232 var result = { id: 0, sprites: [] }; 233 measureImage(image, options, result); 234 var frames = options.frames; 235 var framesX = Number(options.framesX) || frames; 236 var framesY = Math.ceil(frames / framesX); 237 var frameWidth = Math.floor(result.width / framesX); 238 var frameHeight = Math.floor(result.height / framesY); 239 var divisor = result.isSubsampled ? 2 : 1; 240 for (var i = 0; i < frames; i++) { 241 var x = (i % framesX) * frameWidth; 242 var y = Math.floor(i / framesX) * frameHeight; 243 result.sprites.push({ 244 id: i, 245 x: x, y: y, 246 width: frameWidth, 247 height: frameHeight, 248 sampledX: x / divisor, 249 sampledY: y / divisor, 250 sampledWidth: frameWidth / divisor, 251 sampledHeight: frameHeight / divisor 252 }); 253 } 254 return result; 255} 256function measureFrames(images, options) { 257 var result = []; 258 for (var id = 0; id < images.length; id++) { 259 // TODO: optimize 260 // don't measure images with same size twice 261 var sheet = measureSheet(images[id], { frames: 1, framesX: 1, detectSubsampling: options.detectSubsampling }); 262 sheet.id = id; 263 result.push(sheet); 264 } 265 return result; 266} 267function measureMutipleSheets(images, options) { 268 var result = []; 269 for (var id = 0; id < images.length; id++) { 270 // TODO: optimize 271 // don't measure images with same size twice 272 var sheet = measureSheet(images[id], { 273 frames: undefined, 274 framesX: options.framesX, 275 framesY: options.framesY, 276 detectSubsampling: options.detectSubsampling 277 }); 278 sheet.id = id; 279 result.push(sheet); 280 } 281 return result; 282} 283function measureImage(image, options, result) { 284 var size = naturalSize(image); 285 result.isSubsampled = options.detectSubsampling && detectSubsampling(image, size.width, size.height); 286 result.width = size.width; 287 result.height = size.height; 288 result.sampledWidth = size.width / (result.isSubsampled ? 2 : 1); 289 result.sampledHeight = size.height / (result.isSubsampled ? 2 : 1); 290 return result; 291} 292function findSpecs(metrics, frames, frame, lane) { 293 var spriteId = lane * frames + frame; 294 var sheetId = 0; 295 var sprite = null; 296 var sheet = null; 297 while (true) { 298 sheet = metrics[sheetId]; 299 if (!sheet) { 300 break; 301 } 302 if (spriteId >= sheet.sprites.length) { 303 spriteId -= sheet.sprites.length; 304 sheetId++; 305 continue; 306 } 307 sprite = sheet.sprites[spriteId]; 308 break; 309 } 310 return { sprite: sprite, sheet: sheet }; 311} 312 313function indexOf(element, arr) { 314 for (var i = 0; i < arr.length; i++) { 315 if (arr[i] === element) { 316 return i; 317 } 318 } 319} 320function noop() { 321 // 322} 323function preload(opts) { 324 var src; 325 var input = opts.source; 326 src = typeof input === 'string' ? [input] : input; 327 // const src: string[] = ? [opts.source] : opts.source 328 var images = []; 329 var targetCount = (opts.preloadCount || src.length); 330 var onInitiated = opts.initiated || noop; 331 var onProgress = opts.progress || noop; 332 var onComplete = opts.complete || noop; 333 var count = 0; 334 var completed = false; 335 var firstLoaded = false; 336 var tick = function () { 337 count += 1; 338 onProgress({ 339 index: indexOf(this, images), 340 loaded: count, 341 total: src.length, 342 percent: Math.round((count / src.length) * 100) 343 }); 344 firstLoaded = firstLoaded || (this === images[0]); 345 if (firstLoaded && !completed && (count >= targetCount)) { 346 completed = true; 347 onComplete(images); 348 } 349 }; 350 for (var _i = 0, src_1 = src; _i < src_1.length; _i++) { 351 var url = src_1[_i]; 352 var img = new Image(); 353 // push result 354 images.push(img); 355 // https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image 356 img.crossOrigin = opts.crossOrigin; 357 // bind logic, don't care about abort/errors 358 img.onload = img.onabort = img.onerror = tick; 359 // begin load 360 img.src = url; 361 } 362 onInitiated(images); 363} 364 365function padNumber(num, length, pad) { 366 var result = String(num); 367 while (result.length < length) { 368 result = String(pad) + result; 369 } 370 return result; 371} 372/** 373 * Generates an array of source strings 374 * 375 * @remarks 376 * Takes a template string and generates an array of strings by interpolating {lane} and {frame} placeholders. 377 * 378 * ``` 379 * sourceArray('http://example.com/image_{frame}.jpg, { frame: [1, 3], digits: 2 }) 380 * // gives: 381 * // [ 'http://example.com/image_01.jpg', 'http://example.com/image_02.jpg', 'http://example.com/image_03.jpg' ] 382 * 383 * sourceArray('http://example.com/image_FRAME.jpg, { frame: [1, 3], digits: 2, framePlacer: 'FRAME' }) 384 * // gives: 385 * // [ 'http://example.com/image_01.jpg', 'http://example.com/image_02.jpg', 'http://example.com/image_03.jpg' ] 386 * ``` 387 * 388 * @param template - The template string 389 * @param opts - Interpolation options 390 * 391 * @public 392 */ 393function sourceArray(template, opts) { 394 var digits = opts.digits || 2; 395 var lPlacer = opts.lanePlacer || '{lane}'; 396 var fPlacer = opts.framePlacer || '{frame}'; 397 var fStart = 0; 398 var fEnd = 0; 399 if (opts.frame) { 400 fStart = opts.frame[0]; 401 fEnd = opts.frame[1]; 402 } 403 var lStart = 0; 404 var lEnd = 0; 405 if (opts.lane) { 406 lStart = opts.lane[0]; 407 lEnd = opts.lane[1]; 408 } 409 var result = []; 410 for (var lane = lStart; lane <= lEnd; lane += 1) { 411 for (var frame = fStart; frame <= fEnd; frame += 1) { 412 result.push(template 413 .replace(lPlacer, padNumber(lane, digits, '0')) 414 .replace(fPlacer, padNumber(frame, digits, '0'))); 415 } 416 } 417 return result; 418} 419 420/** 421 * The namespace that is used to bind functions to DOM events and store the data object 422 */ 423var namespace = 'spritespin'; 424/** 425 * Event names that are recognized by SpriteSpin. A module can implement any of these and they will be bound 426 * to the target element on which the plugin is called. 427 */ 428var eventNames = [ 429 'mousedown', 430 'mousemove', 431 'mouseup', 432 'mouseenter', 433 'mouseover', 434 'mouseleave', 435 'mousewheel', 436 'wheel', 437 'click', 438 'dblclick', 439 'touchstart', 440 'touchmove', 441 'touchend', 442 'touchcancel', 443 'selectstart', 444 'gesturestart', 445 'gesturechange', 446 'gestureend' 447]; 448/** 449 * 450 */ 451var callbackNames = [ 452 'onInit', 453 'onProgress', 454 'onLoad', 455 'onFrameChanged', 456 'onFrame', 457 'onDraw', 458 'onComplete', 459 'onDestroy' 460]; 461/** 462 * Names of events for that the default behavior should be prevented. 463 */ 464var eventsToPrevent = [ 465 'dragstart' 466]; 467/** 468 * Default set of SpriteSpin options. This also represents the majority of data attributes that are used during the 469 * lifetime of a SpriteSpin instance. The data is stored inside the target DOM element on which the plugin is called. 470 */ 471var defaults = { 472 source: undefined, 473 width: undefined, 474 height: undefined, 475 frames: undefined, 476 framesX: undefined, 477 lanes: 1, 478 sizeMode: undefined, 479 renderer: 'canvas', 480 lane: 0, 481 frame: 0, 482 frameTime: 40, 483 animate: true, 484 retainAnimate: false, 485 reverse: false, 486 loop: true, 487 stopFrame: 0, 488 wrap: true, 489 wrapLane: false, 490 sense: 1, 491 senseLane: undefined, 492 orientation: 'horizontal', 493 detectSubsampling: true, 494 preloadCount: undefined, 495 touchScrollTimer: [200, 1500], 496 responsive: undefined, 497 plugins: undefined 498}; 499 500function noop$1() { 501 // noop 502} 503function wrapConsole(type) { 504 return console && console[type] ? function () { 505 var args = []; 506 for (var _i = 0; _i < arguments.length; _i++) { 507 args[_i] = arguments[_i]; 508 } 509 return console.log.apply(console, args); 510 } : noop$1; 511} 512var log = wrapConsole('log'); 513var warn = wrapConsole('warn'); 514var error = wrapConsole('error'); 515function toArray(value) { 516 return Array.isArray(value) ? value : [value]; 517} 518/** 519 * clamps the given value by the given min and max values 520 */ 521function clamp(value, min, max) { 522 return (value > max ? max : (value < min ? min : value)); 523} 524/** 525 * 526 */ 527function wrap(value, min, max, size) { 528 while (value > max) { 529 value -= size; 530 } 531 while (value < min) { 532 value += size; 533 } 534 return value; 535} 536/** 537 * prevents default action on the given event 538 */ 539function prevent(e) { 540 e.preventDefault(); 541 return false; 542} 543/** 544 * Binds on the given target and event the given function. 545 * The SpriteSpin namespace is attached to the event name 546 */ 547function bind(target, event, func) { 548 if (func) { 549 target.bind(event + '.' + namespace, function (e) { 550 func.apply(target, [e, target.spritespin('data')]); 551 }); 552 } 553} 554/** 555 * Unbinds all SpriteSpin events from given target element 556 */ 557function unbind(target) { 558 target.unbind('.' + namespace); 559} 560/** 561 * Checks if given object is a function 562 */ 563function isFunction(fn) { 564 return typeof fn === 'function'; 565} 566function pixelRatio(context) { 567 var devicePixelRatio = window.devicePixelRatio || 1; 568 var backingStoreRatio = context.webkitBackingStorePixelRatio || 569 context.mozBackingStorePixelRatio || 570 context.msBackingStorePixelRatio || 571 context.oBackingStorePixelRatio || 572 context.backingStorePixelRatio || 1; 573 return devicePixelRatio / backingStoreRatio; 574} 575 576/** 577 * Applies css attributes to layout the SpriteSpin containers. 578 * 579 * @internal 580 */ 581function applyLayout(data) { 582 // disable selection 583 data.target 584 .attr('unselectable', 'on') 585 .css({ 586 width: '', 587 height: '', 588 '-ms-user-select': 'none', 589 '-moz-user-select': 'none', 590 '-khtml-user-select': 'none', 591 '-webkit-user-select': 'none', 592 'user-select': 'none' 593 }); 594 var size = data.responsive ? getComputedSize(data) : getOuterSize(data); 595 var layout = getInnerLayout(data.sizeMode, getInnerSize(data), size); 596 // apply layout on target 597 data.target.css({ 598 width: size.width, 599 height: size.height, 600 position: 'relative', 601 overflow: 'hidden' 602 }); 603 // apply layout on stage 604 data.stage 605 .css(layout) 606 .hide(); 607 if (!data.canvas) { 608 return; 609 } 610 // apply layout on canvas 611 data.canvas.css(layout).hide(); 612 // apply pixel ratio on canvas 613 data.canvasRatio = data.canvasRatio || pixelRatio(data.context); 614 if (typeof layout.width === 'number' && typeof layout.height === 'number') { 615 data.canvas[0].width = (layout.width * data.canvasRatio) || size.width; 616 data.canvas[0].height = (layout.height * data.canvasRatio) || size.height; 617 } 618 else { 619 data.canvas[0].width = (size.width * data.canvasRatio); 620 data.canvas[0].height = (size.height * data.canvasRatio); 621 } 622 // width and height must be set before calling scale 623 data.context.scale(data.canvasRatio, data.canvasRatio); 624} 625 626/** 627 * Gets a state object by name. 628 * @internal 629 * @param data - The SpriteSpin instance data 630 * @param name - The name of the state object 631 */ 632function getState(data, name) { 633 data.state = data.state || {}; 634 data.state[name] = data.state[name] || {}; 635 return data.state[name]; 636} 637/** 638 * Gets a plugin state object by name. 639 * 640 * @remarks 641 * Plugins should use this method to get or create a state object where they can 642 * store any instance variables. 643 * 644 * @public 645 * @param data - The SpriteSpin instance data 646 * @param name - The name of the plugin 647 */ 648function getPluginState(data, name) { 649 var state = getState(data, 'plugin'); 650 state[name] = state[name] || {}; 651 return state[name]; 652} 653/** 654 * Checks whether a flag is set. See {@link flag}. 655 * 656 * @public 657 * @param data - The SpriteSpin instance data 658 * @param key - The name of the flag 659 */ 660function is(data, key) { 661 return !!getState(data, 'flags')[key]; 662} 663/** 664 * Sets a flag value. See {@link is}. 665 * 666 * @public 667 * @param data - The SpriteSpin instance data 668 * @param key - The name of the flag 669 * @param value - The value to set 670 */ 671function flag(data, key, value) { 672 getState(data, 'flags')[key] = !!value; 673} 674 675/** 676 * Gets the playback state 677 * 678 * @public 679 * @param data - The SpriteSpin instance data 680 */ 681function getPlaybackState(data) { 682 return getState(data, 'playback'); 683} 684function updateLane(data, lane) { 685 data.lane = data.wrapLane 686 ? wrap(lane, 0, data.lanes - 1, data.lanes) 687 : clamp(lane, 0, data.lanes - 1); 688} 689function updateAnimationFrame(data) { 690 data.frame += (data.reverse ? -1 : 1); 691 // wrap the frame value to fit in range [0, data.frames) 692 data.frame = wrap(data.frame, 0, data.frames - 1, data.frames); 693 // stop animation if loop is disabled and the stopFrame is reached 694 if (!data.loop && (data.frame === data.stopFrame)) { 695 stopAnimation(data); 696 } 697} 698function updateInputFrame(data, frame) { 699 data.frame = Number(frame); 700 data.frame = data.wrap 701 ? wrap(data.frame, 0, data.frames - 1, data.frames) 702 : clamp(data.frame, 0, data.frames - 1); 703} 704function updateAnimation(data) { 705 var state = getPlaybackState(data); 706 if (state.handler) { 707 updateBefore(data); 708 updateAnimationFrame(data); 709 updateAfter(data); 710 } 711} 712function updateBefore(data) { 713 var state = getPlaybackState(data); 714 state.lastFrame = data.frame; 715 state.lastLane = data.lane; 716} 717function updateAfter(data) { 718 var state = getPlaybackState(data); 719 if (state.lastFrame !== data.frame || state.lastLane !== data.lane) { 720 data.target.trigger('onFrameChanged.' + namespace, data); 721 } 722 data.target.trigger('onFrame.' + namespace, data); 723 data.target.trigger('onDraw.' + namespace, data); 724} 725/** 726 * Updates the frame or lane number of the SpriteSpin data. 727 * 728 * @public 729 * @param data - The SpriteSpin instance data 730 * @param frame - The frame number to set 731 * @param lane - The lane number to set 732 */ 733function updateFrame(data, frame, lane) { 734 updateBefore(data); 735 if (frame != null) { 736 updateInputFrame(data, frame); 737 } 738 if (lane != null) { 739 updateLane(data, lane); 740 } 741 updateAfter(data); 742} 743/** 744 * Stops the running animation. 745 * 746 * @public 747 * @param data - The SpriteSpin instance data 748 */ 749function stopAnimation(data) { 750 data.animate = false; 751 var state = getPlaybackState(data); 752 if (state.handler != null) { 753 window.clearInterval(state.handler); 754 state.handler = null; 755 } 756} 757/** 758 * Starts animation playback if needed. 759 * 760 * @remarks 761 * Starts animation playback if `animate` property is `true` and the animation is not yet running. 762 * 763 * @public 764 * @param data - The SpriteSpin instance data 765 */ 766function applyAnimation(data) { 767 var state = getPlaybackState(data); 768 if (state.handler && (!data.animate || state.frameTime !== data.frameTime)) { 769 stopAnimation(data); 770 } 771 if (data.animate && !state.handler) { 772 state.frameTime = data.frameTime; 773 state.handler = window.setInterval(function () { return updateAnimation(data); }, state.frameTime); 774 } 775} 776/** 777 * Starts the animation playback 778 * 779 * @remarks 780 * Starts the animation playback and also sets the `animate` property to `true` 781 * 782 * @public 783 * @param data - The SpriteSpin instance data 784 */ 785function startAnimation(data) { 786 data.animate = true; 787 applyAnimation(data); 788} 789 790var plugins = {}; 791/** 792 * Registers a plugin. 793 * 794 * @remarks 795 * Use this to add custom Rendering or Updating modules that can be addressed with the 'module' option. 796 * 797 * @public 798 * @param name - The name of the plugin 799 * @param plugin - The plugin implementation 800 */ 801function registerPlugin(name, plugin) { 802 if (plugins[name]) { 803 error("Plugin name \"" + name + "\" is already taken"); 804 return; 805 } 806 plugin = plugin || {}; 807 plugins[name] = plugin; 808 return plugin; 809} 810/** 811 * Registers a plugin. 812 * 813 * @public 814 * @deprecated Use {@link registerPlugin} instead 815 * @param name - The name of the plugin 816 * @param plugin - The plugin implementation 817 */ 818function registerModule(name, plugin) { 819 warn('"registerModule" is deprecated, use "registerPlugin" instead'); 820 registerPlugin(name, plugin); 821} 822/** 823 * Gets an active plugin by name 824 * 825 * @internal 826 * @param name - The name of the plugin 827 */ 828function getPlugin(name) { 829 return plugins[name]; 830} 831/** 832 * Replaces module names on given SpriteSpin data and replaces them with actual implementations. 833 * @internal 834 */ 835function applyPlugins(data) { 836 fixPlugins(data); 837 for (var i = 0; i < data.plugins.length; i += 1) { 838 var name_1 = data.plugins[i]; 839 if (typeof name_1 !== 'string') { 840 continue; 841 } 842 var plugin = getPlugin(name_1); 843 if (!plugin) { 844 error('No plugin found with name ' + name_1); 845 continue; 846 } 847 data.plugins[i] = plugin; 848 } 849} 850function fixPlugins(data) { 851 // tslint:disable no-string-literal 852 if (data['mods']) { 853 warn('"mods" option is deprecated, use "plugins" instead'); 854 data.plugins = data['mods']; 855 delete data['mods']; 856 } 857 if (data['behavior']) { 858 warn('"behavior" option is deprecated, use "plugins" instead'); 859 data.plugins.push(data['behavior']); 860 delete data['behavior']; 861 } 862 if (data['module']) { 863 warn('"module" option is deprecated, use "plugins" instead'); 864 data.plugins.push(data['module']); 865 delete data['module']; 866 } 867} 868 869var $$2 = $$1; 870var counter = 0; 871/** 872 * Collection of all SpriteSpin instances 873 */ 874var instances = {}; 875function pushInstance(data) { 876 counter += 1; 877 data.id = String(counter); 878 instances[data.id] = data; 879} 880function popInstance(data) { 881 delete instances[data.id]; 882} 883function eachInstance(cb) { 884 for (var id in instances) { 885 if (instances.hasOwnProperty(id)) { 886 cb(instances[id]); 887 } 888 } 889} 890var lazyinit = function () { 891 // replace function with a noop 892 // this logic must run only once 893 lazyinit = function () { }; 894 function onEvent(eventName, e) { 895 eachInstance(function (data) { 896 for (var _i = 0, _a = data.plugins; _i < _a.length; _i++) { 897 var module_1 = _a[_i]; 898 if (typeof module_1[eventName] === 'function') { 899 module_1[eventName].apply(data.target, [e, data]); 900 } 901 } 902 }); 903 } 904 function onResize() { 905 eachInstance(function (data) { 906 if (data.responsive) { 907 boot(data); 908 } 909 }); 910 } 911 var _loop_1 = function (eventName) { 912 $$2(window.document).bind(eventName + '.' + namespace, function (e) { 913 onEvent('document' + eventName, e); 914 }); 915 }; 916 for (var _i = 0, eventNames_1 = eventNames; _i < eventNames_1.length; _i++) { 917 var eventName = eventNames_1[_i]; 918 _loop_1(eventName); 919 } 920 var resizeTimeout = null; 921 $$2(window).on('resize', function () { 922 window.clearTimeout(resizeTimeout); 923 resizeTimeout = window.setTimeout(onResize, 100); 924 }); 925}; 926/** 927 * (re)binds all spritespin events on the target element 928 * 929 * @internal 930 */ 931function applyEvents(data) { 932 var target = data.target; 933 // Clear all SpriteSpin events on the target element 934 unbind(target); 935 // disable all default browser behavior on the following events 936 // mainly prevents image drag operation 937 for (var _i = 0, eventsToPrevent_1 = eventsToPrevent; _i < eventsToPrevent_1.length; _i++) { 938 var eName = eventsToPrevent_1[_i]; 939 bind(target, eName, prevent); 940 } 941 // Bind module functions to SpriteSpin events 942 for (var _a = 0, _b = data.plugins; _a < _b.length; _a++) { 943 var plugin = _b[_a]; 944 for (var _c = 0, eventNames_2 = eventNames; _c < eventNames_2.length; _c++) { 945 var eName = eventNames_2[_c]; 946 bind(target, eName, plugin[eName]); 947 } 948 for (var _d = 0, callbackNames_1 = callbackNames; _d < callbackNames_1.length; _d++) { 949 var eName = callbackNames_1[_d]; 950 bind(target, eName, plugin[eName]); 951 } 952 } 953 // bind auto start function to load event. 954 bind(target, 'onLoad', function (e, d) { 955 applyAnimation(d); 956 }); 957 // bind all user events that have been passed on initialization 958 for (var _e = 0, callbackNames_2 = callbackNames; _e < callbackNames_2.length; _e++) { 959 var eName = callbackNames_2[_e]; 960 bind(target, eName, data[eName]); 961 } 962} 963function applyMetrics(data) { 964 if (!data.images) { 965 data.metrics = []; 966 } 967 data.metrics = measure(data.images, data); 968 var spec = findSpecs(data.metrics, data.frames, 0, 0); 969 if (spec.sprite) { 970 // TODO: try to remove frameWidth/frameHeight 971 data.frameWidth = spec.sprite.width; 972 data.frameHeight = spec.sprite.height; 973 } 974} 975/** 976 * Runs the boot process. 977 * 978 * @remarks 979 * (re)initializes plugins, (re)initializes the layout, (re)binds events and loads source images. 980 * 981 * @internal 982 */ 983function boot(data) { 984 applyPlugins(data); 985 applyEvents(data); 986 applyLayout(data); 987 data.source = toArray(data.source); 988 data.loading = true; 989 data.target 990 .addClass('loading') 991 .trigger('onInit.' + namespace, data); 992 preload({ 993 source: data.source, 994 crossOrigin: data.crossOrigin, 995 preloadCount: data.preloadCount, 996 progress: function (progress) { 997 data.progress = progress; 998 data.target.trigger('onProgress.' + namespace, data); 999 }, 1000 complete: function (images) { 1001 data.images = images; 1002 data.loading = false; 1003 data.frames = data.frames || images.length; 1004 applyMetrics(data); 1005 applyLayout(data); 1006 data.stage.show(); 1007 data.target 1008 .removeClass('loading') 1009 .trigger('onLoad.' + namespace, data) 1010 .trigger('onFrame.' + namespace, data) 1011 .trigger('onDraw.' + namespace, data) 1012 .trigger('onComplete.' + namespace, data); 1013 } 1014 }); 1015} 1016/** 1017 * Creates a new SpriteSpin instance 1018 * 1019 * @public 1020 */ 1021function create(options) { 1022 var _this = this; 1023 var target = options.target; 1024 // SpriteSpin is not initialized 1025 // Create default settings object and extend with given options 1026 var data = $$2.extend(true, {}, defaults, options); 1027 // ensure source is set 1028 data.source = data.source || []; 1029 // ensure plugins are set 1030 data.plugins = data.plugins || [ 1031 '360', 1032 'drag' 1033 ]; 1034 // if image tags are contained inside this DOM element 1035 // use these images as the source files 1036 target.find('img').each(function () { 1037 if (!Array.isArray(data.source)) { 1038 data.source = []; 1039 } 1040 data.source.push($$2(_this).attr('src')); 1041 }); 1042 // build inner html 1043 // <div> 1044 // <div class='spritespin-stage'></div> 1045 // <canvas class='spritespin-canvas'></canvas> 1046 // </div> 1047 target 1048 .empty() 1049 .addClass('spritespin-instance') 1050 .append("<div class='spritespin-stage'></div>"); 1051 // add the canvas element if canvas rendering is enabled and supported 1052 if (data.renderer === 'canvas') { 1053 var canvas = document.createElement('canvas'); 1054 if (!!(canvas.getContext && canvas.getContext('2d'))) { 1055 data.canvas = $$2(canvas).addClass('spritespin-canvas'); 1056 data.context = canvas.getContext('2d'); 1057 target.append(data.canvas); 1058 target.addClass('with-canvas'); 1059 } 1060 else { 1061 // fallback to image rendering mode 1062 data.renderer = 'image'; 1063 } 1064 } 1065 // setup references to DOM elements 1066 data.target = target; 1067 data.stage = target.find('.spritespin-stage'); 1068 // store the data 1069 target.data(namespace, data); 1070 pushInstance(data); 1071 return data; 1072} 1073/** 1074 * Creates a new SpriteSpin instance, or updates an existing one 1075 * 1076 * @public 1077 */ 1078function createOrUpdate(options) { 1079 lazyinit(); 1080 var data = options.target.data(namespace); 1081 if (!data) { 1082 data = create(options); 1083 } 1084 else { 1085 $$2.extend(data, options); 1086 } 1087 boot(data); 1088 return data; 1089} 1090/** 1091 * Destroys the SpriteSpin instance 1092 * 1093 * @remarks 1094 * - stops running animation 1095 * - unbinds all events 1096 * - deletes the data on the target element 1097 * 1098 * @public 1099 */ 1100function destroy(data) { 1101 popInstance(data); 1102 stopAnimation(data); 1103 data.target 1104 .trigger('onDestroy', data) 1105 .html(null) 1106 .attr('style', null) 1107 .attr('unselectable', null) 1108 .removeClass(['spritespin-instance', 'with-canvas']); 1109 unbind(data.target); 1110 data.target.removeData(namespace); 1111} 1112 1113/** 1114 * Gets the current input state 1115 * 1116 * @public 1117 * @param data - The SpriteSpin instance data 1118 */ 1119function getInputState(data) { 1120 return getState(data, 'input'); 1121} 1122/** 1123 * Updates the input state using a mouse or touch event. 1124 * 1125 * @public 1126 * @param e - The input event 1127 * @param data - The SpriteSpin instance data 1128 */ 1129function updateInput(e, data) { 1130 var cursor = getCursorPosition(e); 1131 var state = getInputState(data); 1132 // cache positions from previous frame 1133 state.oldX = state.currentX; 1134 state.oldY = state.currentY; 1135 state.currentX = cursor.x; 1136 state.currentY = cursor.y; 1137 // Fix old position. 1138 if (state.oldX === undefined || state.oldY === undefined) { 1139 state.oldX = state.currentX; 1140 state.oldY = state.currentY; 1141 } 1142 // Cache the initial click/touch position and store the frame number at which the click happened. 1143 // Useful for different behavior implementations. This must be restored when the click/touch is released. 1144 if (state.startX === undefined || state.startY === undefined) { 1145 state.startX = state.currentX; 1146 state.startY = state.currentY; 1147 state.clickframe = data.frame; 1148 state.clicklane = data.lane; 1149 } 1150 // Calculate the vector from start position to current pointer position. 1151 state.dX = state.currentX - state.startX; 1152 state.dY = state.currentY - state.startY; 1153 // Calculate the vector from last frame position to current pointer position. 1154 state.ddX = state.currentX - state.oldX; 1155 state.ddY = state.currentY - state.oldY; 1156 // Normalize vectors to range [-1:+1] 1157 state.ndX = state.dX / data.target.innerWidth(); 1158 state.ndY = state.dY / data.target.innerHeight(); 1159 state.nddX = state.ddX / data.target.innerWidth(); 1160 state.nddY = state.ddY / data.target.innerHeight(); 1161} 1162/** 1163 * Resets the input state. 1164 * 1165 * @public 1166 */ 1167function resetInput(data) { 1168 var input = getInputState(data); 1169 input.startX = input.startY = undefined; 1170 input.currentX = input.currentY = undefined; 1171 input.oldX = input.oldY = undefined; 1172 input.dX = input.dY = 0; 1173 input.ddX = input.ddY = 0; 1174 input.ndX = input.ndY = 0; 1175 input.nddX = input.nddY = 0; 1176} 1177 1178function extension(option, value) { 1179 var $target = $$1(this); 1180 if (option === 'data') { 1181 return $target.data(namespace); 1182 } 1183 if (option === 'api') { 1184 var data = $target.data(namespace); 1185 data.api = data.api || new Api(data); 1186 return data.api; 1187 } 1188 if (option === 'destroy') { 1189 return $target.each(function () { 1190 var data = $target.data(namespace); 1191 if (data) { 1192 destroy(data); 1193 } 1194 }); 1195 } 1196 if (arguments.length === 2 && typeof option === 'string') { 1197 option = (_a = {}, _a[option] = value, _a); 1198 } 1199 if (typeof option === 'object') { 1200 return createOrUpdate($$1.extend(true, { target: $target }, option)).target; 1201 } 1202 throw new Error('Invalid call to spritespin'); 1203 var _a; 1204} 1205$$1.fn[namespace] = extension; 1206 1207// tslint:disable:object-literal-shorthand 1208// tslint:disable:only-arrow-functions 1209extendApi({ 1210 // Gets a value indicating whether the animation is currently running. 1211 isPlaying: function () { 1212 return getPlaybackState(this.data).handler != null; 1213 }, 1214 // Gets a value indicating whether the animation looping is enabled. 1215 isLooping: function () { 1216 return this.data.loop; 1217 }, 1218 // Starts/Stops the animation playback 1219 toggleAnimation: function () { 1220 if (this.isPlaying()) { 1221 this.stopAnimation(); 1222 } 1223 else { 1224 this.startAnimation(); 1225 } 1226 }, 1227 // Stops animation playback 1228 stopAnimation: function () { 1229 this.data.animate = false; 1230 stopAnimation(this.data); 1231 }, 1232 // Starts animation playback 1233 startAnimation: function () { 1234 this.data.animate = true; 1235 applyAnimation(this.data); 1236 }, 1237 // Sets a value indicating whether the animation should be looped or not. 1238 // This might start the animation (if the 'animate' data attribute is set to true) 1239 loop: function (value) { 1240 this.data.loop = value; 1241 applyAnimation(this.data); 1242 return this; 1243 }, 1244 // Gets the current frame number 1245 currentFrame: function () { 1246 return this.data.frame; 1247 }, 1248 // Updates SpriteSpin to the specified frame. 1249 updateFrame: function (frame) { 1250 updateFrame(this.data, frame); 1251 return this; 1252 }, 1253 // Skips the given number of frames 1254 skipFrames: function (step) { 1255 var data = this.data; 1256 updateFrame(data, data.frame + (data.reverse ? -step : +step)); 1257 return this; 1258 }, 1259 // Updates SpriteSpin so that the next frame is shown 1260 nextFrame: function () { 1261 return this.skipFrames(1); 1262 }, 1263 // Updates SpriteSpin so that the previous frame is shown 1264 prevFrame: function () { 1265 return this.skipFrames(-1); 1266 }, 1267 // Starts the animations that will play until the given frame number is reached 1268 // options: 1269 // force [boolean] starts the animation, even if current frame is the target frame 1270 // nearest [boolean] animates to the direction with minimum distance to the target frame 1271 playTo: function (frame, options) { 1272 var data = this.data; 1273 options = options || {}; 1274 if (!options.force && data.frame === frame) { 1275 return; 1276 } 1277 if (options.nearest) { 1278 // distance to the target frame 1279 var a = frame - data.frame; 1280 // distance to last frame and the to target frame 1281 var b = frame > data.frame ? a - data.frames : a + data.frames; 1282 // minimum distance 1283 var c = Math.abs(a) < Math.abs(b) ? a : b; 1284 data.reverse = c < 0; 1285 } 1286 data.animate = true; 1287 data.loop = false; 1288 data.stopFrame = frame; 1289 applyAnimation(data); 1290 return this; 1291 } 1292}); 1293 1294function pick(target, names) { 1295 for (var _i = 0, names_1 = names; _i < names_1.length; _i++) { 1296 var name_1 = names_1[_i]; 1297 if (target[name_1] || name_1 in target) { 1298 return name_1; 1299 } 1300 } 1301 return names[0]; 1302} 1303var browser = { 1304 requestFullscreen: pick(document.documentElement, [ 1305 'requestFullscreen', 1306 'webkitRequestFullScreen', 1307 'mozRequestFullScreen', 1308 'msRequestFullscreen' 1309 ]), 1310 exitFullscreen: pick(document, [ 1311 'exitFullscreen', 1312 'webkitExitFullscreen', 1313 'webkitCancelFullScreen', 1314 'mozCancelFullScreen', 1315 'msExitFullscreen' 1316 ]), 1317 fullscreenElement: pick(document, [ 1318 'fullscreenElement', 1319 'webkitFullscreenElement', 1320 'webkitCurrentFullScreenElement', 1321 'mozFullScreenElement', 1322 'msFullscreenElement' 1323 ]), 1324 fullscreenEnabled: pick(document, [ 1325 'fullscreenEnabled', 1326 'webkitFullscreenEnabled', 1327 'mozFullScreenEnabled', 1328 'msFullscreenEnabled' 1329 ]), 1330 fullscreenchange: pick(document, [ 1331 'onfullscreenchange', 1332 'onwebkitfullscreenchange', 1333 'onmozfullscreenchange', 1334 'onMSFullscreenChange' 1335 ]).replace(/^on/, ''), 1336 fullscreenerror: pick(document, [ 1337 'onfullscreenerror', 1338 'onwebkitfullscreenerror', 1339 'onmozfullscreenerror', 1340 'onMSFullscreenError' 1341 ]).replace(/^on/, '') 1342}; 1343var changeEvent = browser.fullscreenchange + '.' + namespace + '-fullscreen'; 1344function unbindChangeEvent() { 1345 $$1(document).unbind(changeEvent); 1346} 1347function bindChangeEvent(callback) { 1348 unbindChangeEvent(); 1349 $$1(document).bind(changeEvent, callback); 1350} 1351var orientationEvent = 'orientationchange.' + namespace + '-fullscreen'; 1352function unbindOrientationEvent() { 1353 $$1(window).unbind(orientationEvent); 1354} 1355function bindOrientationEvent(callback) { 1356 unbindOrientationEvent(); 1357 $$1(window).bind(orientationEvent, callback); 1358} 1359function requestFullscreenNative(e) { 1360 e = e || document.documentElement; 1361 e[browser.requestFullscreen](); 1362} 1363function exitFullscreen() { 1364 return document[browser.exitFullscreen](); 1365} 1366function fullscreenEnabled() { 1367 return document[browser.fullscreenEnabled]; 1368} 1369function fullscreenElement() { 1370 return document[browser.fullscreenElement]; 1371} 1372function isFullscreen() { 1373 return !!fullscreenElement(); 1374} 1375function toggleFullscreen(data, opts) { 1376 if (isFullscreen()) { 1377 this.apiRequestFullscreen(opts); 1378 } 1379 else { 1380 this.exitFullscreen(); 1381 } 1382} 1383function requestFullscreen(data, opts) { 1384 opts = opts || {}; 1385 var oWidth = data.width; 1386 var oHeight = data.height; 1387 var oSource = data.source; 1388 var oSize = data.sizeMode; 1389 var oResponsive = data.responsive; 1390 var enter = function () { 1391 data.width = window.screen.width; 1392 data.height = window.screen.height; 1393 data.source = (opts.source || oSource); 1394 data.sizeMode = opts.sizeMode || 'fit'; 1395 data.responsive = false; 1396 boot(data); 1397 }; 1398 var exit = function () { 1399 data.width = oWidth; 1400 data.height = oHeight; 1401 data.source = oSource; 1402 data.sizeMode = oSize; 1403 data.responsive = oResponsive; 1404 boot(data); 1405 }; 1406 bindChangeEvent(function () { 1407 if (isFullscreen()) { 1408 enter(); 1409 bindOrientationEvent(enter); 1410 } 1411 else { 1412 unbindChangeEvent(); 1413 unbindOrientationEvent(); 1414 exit(); 1415 } 1416 }); 1417 requestFullscreenNative(data.target[0]); 1418} 1419extendApi({ 1420 fullscreenEnabled: fullscreenEnabled, 1421 fullscreenElement: fullscreenElement, 1422 exitFullscreen: exitFullscreen, 1423 toggleFullscreen: function (opts) { 1424 toggleFullscreen(this.data, opts); 1425 }, 1426 requestFullscreen: function (opts) { 1427 requestFullscreen(this.data, opts); 1428 } 1429}); 1430 1431(function () { 1432 var NAME = 'click'; 1433 function click(e, data) { 1434 if (data.loading || !data.stage.is(':visible')) { 1435 return; 1436 } 1437 updateInput(e, data); 1438 var input = getInputState(data); 1439 var half, pos; 1440 var target = data.target, offset = target.offset(); 1441 if (data.orientation === 'horizontal') { 1442 half = target.innerWidth() / 2; 1443 pos = input.currentX - offset.left; 1444 } 1445 else { 1446 half = target.innerHeight() / 2; 1447 pos = input.currentY - offset.top; 1448 } 1449 updateFrame(data, data.frame + (pos > half ? 1 : -1)); 1450 } 1451 registerPlugin(NAME, { 1452 name: NAME, 1453 mouseup: click, 1454 touchend: click 1455 }); 1456})(); 1457 1458(function () { 1459 var NAME = 'drag'; 1460 function getState$$1(data) { 1461 return getPluginState(data, NAME); 1462 } 1463 function getAxis(data) { 1464 if (typeof data.orientation === 'number') { 1465 return data.orientation * Math.PI / 180; 1466 } 1467 if (data.orientation === 'horizontal') { 1468 return 0; 1469 } 1470 return Math.PI / 2; 1471 } 1472 function onInit(e, data) { 1473 var state = getState$$1(data); 1474 var d = [200, 1500]; 1475 var t = data.touchScrollTimer || d; 1476 state.minTime = t[0] || d[0]; 1477 state.maxTime = t[1] || d[1]; 1478 } 1479 function dragStart(e, data) { 1480 var state = getState$$1(data); 1481 if (data.loading || is(data, 'dragging') || data['zoomPinFrame'] && !data.stage.is(':visible')) { 1482 return; 1483 } 1484 // Touch scroll can only be disabled by cancelling the 'touchstart' event. 1485 // If we would try to cancel the 'touchmove' event during a scroll 1486 // chrome browser raises an error 1487 // 1488 // When a user interacts with sprite spin, we don't know whether the intention 1489 // is to scroll the page or to roll the spin. 1490 // 1491 // On first interaction with SpriteSpin the scroll is not disabled 1492 // On double tap within 200ms the scroll is not disabled 1493 // Scroll is only disabled if there was an interaction with SpriteSpin in the past 1500ms 1494 var now = new Date().getTime(); 1495 if (state.endAt && (now - state.endAt > state.maxTime)) { 1496 // reset timer if the user has no interaction with spritespin within 1500ms 1497 state.startAt = null; 1498 state.endAt = null; 1499 } 1500 if (state.startAt && (now - state.startAt > state.minTime)) { 1501 // disable scroll only if there was already an interaction with spritespin 1502 // however, allow scrolling on double tab within 200ms 1503 e.preventDefault(); 1504 } 1505 state.startAt = now; 1506 state.wasPlaying = !!getPlaybackState(data).handler; 1507 state.frame = data.frame || 0; 1508 state.lane = data.lane || 0; 1509 flag(data, 'dragging', true); 1510 updateInput(e, data); 1511 } 1512 function dragEnd(e, data) { 1513 if (is(data, 'dragging')) { 1514 getState$$1(data).endAt = new Date().getTime(); 1515 flag(data, 'dragging', false); 1516 resetInput(data); 1517 if (data.retainAnimate && getState$$1(data).wasPlaying) { 1518 startAnimation(data); 1519 } 1520 } 1521 } 1522 function drag(e, data) { 1523 var state = getState$$1(data); 1524 var input = getInputState(data); 1525 if (!is(data, 'dragging')) { 1526 return; 1527 } 1528 updateInput(e, data); 1529 var rad = getAxis(data); 1530 var sn = Math.sin(rad); 1531 var cs = Math.cos(rad); 1532 var x = ((input.nddX * cs - input.nddY * sn) * data.sense) || 0; 1533 var y = ((input.nddX * sn + input.nddY * cs) * (data.senseLane || data.sense)) || 0; 1534 // accumulate 1535 state.frame += data.frames * x; 1536 state.lane += data.lanes * y; 1537 // update spritespin 1538 var oldFrame = data.frame; 1539 var oldLane = data.lane; 1540 updateFrame(data, Math.floor(state.frame), Math.floor(state.lane)); 1541 stopAnimation(data); 1542 } 1543 function mousemove(e, data) { 1544 dragStart(e, data); 1545 drag(e, data); 1546 } 1547 registerPlugin('drag', { 1548 name: 'drag', 1549 onInit: onInit, 1550 mousedown: dragStart, 1551 mousemove: drag, 1552 mouseup: dragEnd, 1553 documentmousemove: drag, 1554 documentmouseup: dragEnd, 1555 touchstart: dragStart, 1556 touchmove: drag, 1557 touchend: dragEnd, 1558 touchcancel: dragEnd 1559 }); 1560 registerPlugin('move', { 1561 name: 'move', 1562 onInit: onInit, 1563 mousemove: mousemove, 1564 mouseleave: dragEnd, 1565 touchstart: dragStart, 1566 touchmove: drag, 1567 touchend: dragEnd, 1568 touchcancel: dragEnd 1569 }); 1570})(); 1571 1572(function () { 1573 var NAME = 'hold'; 1574 function getState$$1(data) { 1575 return getPluginState(data, NAME); 1576 } 1577 function rememberOptions(data) { 1578 var state = getState$$1(data); 1579 state.frameTime = data.frameTime; 1580 state.animate = data.animate; 1581 state.reverse = data.reverse; 1582 } 1583 function restoreOptions(data) { 1584 var state = getState$$1(data); 1585 data.frameTime = state.frameTime; 1586 data.animate = state.animate; 1587 data.reverse = state.reverse; 1588 } 1589 function start(e, data) { 1590 if (is(data, 'loading') || is(data, 'dragging') || !data.stage.is(':visible')) { 1591 return; 1592 } 1593 rememberOptions(data); 1594 updateInput(e, data); 1595 flag(data, 'dragging', true); 1596 data.animate = true; 1597 applyAnimation(data); 1598 } 1599 function stop(e, data) { 1600 flag(data, 'dragging', false); 1601 resetInput(data); 1602 stopAnimation(data); 1603 restoreOptions(data); 1604 applyAnimation(data); 1605 } 1606 function update(e, data) { 1607 if (!is(data, 'dragging')) { 1608 return; 1609 } 1610 updateInput(e, data); 1611 var input = getInputState(data); 1612 var half, delta; 1613 var target = data.target, offset = target.offset(); 1614 if (data.orientation === 'horizontal') { 1615 half = target.innerWidth() / 2; 1616 delta = (input.currentX - offset.left - half) / half; 1617 } 1618 else { 1619 half = (data.height / 2); 1620 delta = (input.currentY - offset.top - half) / half; 1621 } 1622 data.reverse = delta < 0; 1623 delta = delta < 0 ? -delta : delta; 1624 data.frameTime = 80 * (1 - delta) + 20; 1625 if (((data.orientation === 'horizontal') && (input.dX < input.dY)) || 1626 ((data.orientation === 'vertical') && (input.dX < input.dY))) { 1627 e.preventDefault(); 1628 } 1629 } 1630 function onFrame(e, data) { 1631 data.animate = true; 1632 applyAnimation(data); 1633 } 1634 registerPlugin(NAME, { 1635 name: NAME, 1636 mousedown: start, 1637 mousemove: update, 1638 mouseup: stop, 1639 mouseleave: stop, 1640 touchstart: start, 1641 touchmove: update, 1642 touchend: stop, 1643 touchcancel: stop, 1644 onFrame: onFrame 1645 }); 1646})(); 1647 1648(function () { 1649 var NAME = 'swipe'; 1650 function getState$$1(data) { 1651 return getPluginState(data, NAME); 1652 } 1653 function getOption(data, name, fallback) { 1654 return data[name] || fallback; 1655 } 1656 function init(e, data) { 1657 var state = getState$$1(data); 1658 state.fling = getOption(data, 'swipeFling', 10); 1659 state.snap = getOption(data, 'swipeSnap', 0.50); 1660 } 1661 function start(e, data) { 1662 if (!data.loading && !is(data, 'dragging')) { 1663 updateInput(e, data); 1664 flag(data, 'dragging', true); 1665 } 1666 } 1667 function update(e, data) { 1668 if (!is(data, 'dragging')) { 1669 return; 1670 } 1671 updateInput(e, data); 1672 var frame = data.frame; 1673 var lane = data.lane; 1674 updateFrame(data, frame, lane); 1675 } 1676 function end(e, data) { 1677 if (!is(data, 'dragging')) { 1678 return; 1679 } 1680 flag(data, 'dragging', false); 1681 var state = getState$$1(data); 1682 var input = getInputState(data); 1683 var frame = data.frame; 1684 var lane = data.lane; 1685 var snap = state.snap; 1686 var fling = state.fling; 1687 var dS, dF; 1688 if (data.orientation === 'horizontal') { 1689 dS = input.ndX; 1690 dF = input.ddX; 1691 } 1692 else { 1693 dS = input.ndY; 1694 dF = input.ddY; 1695 } 1696 if (dS >= snap || dF >= fling) { 1697 frame = data.frame - 1; 1698 } 1699 else if (dS <= -snap || dF <= -fling) { 1700 frame = data.frame + 1; 1701 } 1702 resetInput(data); 1703 updateFrame(data, frame, lane); 1704 stopAnimation(data); 1705 } 1706 registerPlugin(NAME, { 1707 name: NAME, 1708 onLoad: init, 1709 mousedown: start, 1710 mousemove: update, 1711 mouseup: end, 1712 mouseleave: end, 1713 touchstart: start, 1714 touchmove: update, 1715 touchend: end, 1716 touchcancel: end 1717 }); 1718})(); 1719 1720(function () { 1721 var NAME = 'wheel'; 1722 function wheel(e, data) { 1723 if (!data.loading && data.stage.is(':visible')) { 1724 e.preventDefault(); 1725 var we = e.originalEvent; 1726 var signX = we.deltaX === 0 ? 0 : we.deltaX > 0 ? 1 : -1; 1727 var signY = we.deltaY === 0 ? 0 : we.deltaY > 0 ? 1 : -1; 1728 updateFrame(data, data.frame + signY, data.lane + signX); 1729 } 1730 } 1731 registerPlugin(NAME, { 1732 name: NAME, 1733 wheel: wheel 1734 }); 1735})(); 1736 1737(function () { 1738 var template = "\n<div class='spritespin-progress'>\n <div class='spritespin-progress-label'></div>\n <div class='spritespin-progress-bar'></div>\n</div>\n"; 1739 function getState$$1(data) { 1740 return getPluginState(data, NAME); 1741 } 1742 var NAME = 'progress'; 1743 function onInit(e, data) { 1744 var state = getState$$1(data); 1745 if (!state.stage) { 1746 state.stage = $$1(template); 1747 state.stage.appendTo(data.target); 1748 } 1749 state.stage.find('.spritespin-progress-label') 1750 .text("0%") 1751 .css({ 'text-align': 'center' }); 1752 state.stage.find('.spritespin-progress-bar').css({ 1753 width: "0%" 1754 }); 1755 state.stage.hide().fadeIn(); 1756 } 1757 function onProgress(e, data) { 1758 var state = getState$$1(data); 1759 state.stage.find('.spritespin-progress-label') 1760 .text(data.progress.percent + "%") 1761 .css({ 'text-align': 'center' }); 1762 state.stage.find('.spritespin-progress-bar').css({ 1763 width: data.progress.percent + "%" 1764 }); 1765 } 1766 function onLoad(e, data) { 1767 $$1(getState$$1(data).stage).fadeOut(); 1768 } 1769 function onDestroy(e, data) { 1770 $$1(getState$$1(data).stage).remove(); 1771 } 1772 registerPlugin(NAME, { 1773 name: NAME, 1774 onInit: onInit, 1775 onProgress: onProgress, 1776 onLoad: onLoad, 1777 onDestroy: onDestroy 1778 }); 1779})(); 1780 1781(function () { 1782 var NAME = '360'; 1783 function onLoad(e, data) { 1784 data.stage.find('.spritespin-frames').detach(); 1785 if (data.renderer === 'image') { 1786 $(data.images).addClass('spritespin-frames').appendTo(data.stage); 1787 } 1788 } 1789 function onDraw(e, data) { 1790 var specs = findSpecs(data.metrics, data.frames, data.frame, data.lane); 1791 var sheet = specs.sheet; 1792 var sprite = specs.sprite; 1793 if (!sheet || !sprite) { 1794 return; 1795 } 1796 var src = data.source[sheet.id]; 1797 var image = data.images[sheet.id]; 1798 if (data.renderer === 'canvas') { 1799 data.canvas.show(); 1800 var w = data.canvas[0].width / data.canvasRatio; 1801 var h = data.canvas[0].height / data.canvasRatio; 1802 data.context.clearRect(0, 0, w, h); 1803 data.context.drawImage(image, sprite.sampledX, sprite.sampledY, sprite.sampledWidth, sprite.sampledHeight, 0, 0, w, h); 1804 return; 1805 } 1806 var scaleX = data.stage.innerWidth() / sprite.sampledWidth; 1807 var scaleY = data.stage.innerHeight() / sprite.sampledHeight; 1808 var top = Math.floor(-sprite.sampledY * scaleY); 1809 var left = Math.floor(-sprite.sampledX * scaleX); 1810 var width = Math.floor(sheet.sampledWidth * scaleX); 1811 var height = Math.floor(sheet.sampledHeight * scaleY); 1812 if (data.renderer === 'background') { 1813 data.stage.css({ 1814 'background-image': "url('" + src + "')", 1815 'background-position': left + "px " + top + "px", 1816 'background-repeat': 'no-repeat', 1817 // set custom background size to enable responsive rendering 1818 '-webkit-background-size': width + "px " + height + "px", 1819 '-moz-background-size': width + "px " + height + "px", 1820 '-o-background-size': width + "px " + height + "px", 1821 'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */ 1822 }); 1823 return; 1824 } 1825 $(data.images).hide(); 1826 $(image).show().css({ 1827 position: 'absolute', 1828 top: top, 1829 left: left, 1830 'max-width': 'initial', 1831 width: width, 1832 height: height 1833 }); 1834 } 1835 registerPlugin(NAME, { 1836 name: NAME, 1837 onLoad: onLoad, 1838 onDraw: onDraw 1839 }); 1840})(); 1841 1842(function () { 1843 var NAME = 'blur'; 1844 function getState$$1(data) { 1845 return getPluginState(data, NAME); 1846 } 1847 function getOption(data, name, fallback) { 1848 return data[name] || fallback; 1849 } 1850 function init(e, data) { 1851 var state = getState$$1(data); 1852 state.canvas = state.canvas || $$1("<canvas class='blur-layer'></canvas>"); 1853 state.context = state.context || state.canvas[0].getContext('2d'); 1854 state.steps = state.steps || []; 1855 state.fadeTime = Math.max(getOption(data, 'blurFadeTime', 200), 1); 1856 state.frameTime = Math.max(getOption(data, 'blurFrameTime', data.frameTime), 16); 1857 state.trackTime = null; 1858 state.cssBlur = !!getOption(data, 'blurCss', false); 1859 var inner = getInnerSize(data); 1860 var outer = data.responsive ? getComputedSize(data) : getOuterSize(data); 1861 var css = getInnerLayout(data.sizeMode, inner, outer); 1862 state.canvas[0].width = data.width * data.canvasRatio; 1863 state.canvas[0].height = data.height * data.canvasRatio; 1864 state.canvas.css(css).show(); 1865 state.context.scale(data.canvasRatio, data.canvasRatio); 1866 data.target.append(state.canvas); 1867 } 1868 function onFrame(e, data) { 1869 var state = getState$$1(data); 1870 trackFrame(data); 1871 if (state.timeout == null) { 1872 loop(data); 1873 } 1874 } 1875 function trackFrame(data) { 1876 var state = getState$$1(data); 1877 var ani = getPlaybackState(data); 1878 // distance between frames 1879 var d = Math.abs(data.frame - ani.lastFrame); 1880 // shortest distance 1881 d = d >= data.frames / 2 ? data.frames - d : d; 1882 state.steps.unshift({ 1883 frame: data.frame, 1884 lane: data.lane, 1885 live: 1, 1886 step: state.frameTime / state.fadeTime, 1887 d: d, 1888 alpha: 0 1889 }); 1890 } 1891 var toRemove = []; 1892 function removeOldFrames(frames) { 1893 toRemove.length = 0; 1894 for (var i = 0; i < frames.length; i += 1) { 1895 if (frames[i].alpha <= 0) { 1896 toRemove.push(i); 1897 } 1898 } 1899 for (var _i = 0, toRemove_1 = toRemove; _i < toRemove_1.length; _i++) { 1900 var item = toRemove_1[_i]; 1901 frames.splice(item, 1); 1902 } 1903 } 1904 function loop(data) { 1905 var state = getState$$1(data); 1906 state.timeout = window.setTimeout(function () { tick(data); }, state.frameTime); 1907 } 1908 function killLoop(data) { 1909 var state = getState$$1(data); 1910 window.clearTimeout(state.timeout); 1911 state.timeout = null; 1912 } 1913 function applyCssBlur(canvas, d) { 1914 var amount = Math.min(Math.max((d / 2) - 4, 0), 2.5); 1915 var blur = "blur(" + amount + "px)"; 1916 canvas.css({ 1917 '-webkit-filter': blur, 1918 filter: blur 1919 }); 1920 } 1921 function clearFrame(data, state) { 1922 state.canvas.show(); 1923 var w = state.canvas[0].width / data.canvasRatio; 1924 var h = state.canvas[0].height / data.canvasRatio; 1925 // state.context.clearRect(0, 0, w, h) 1926 } 1927 function drawFrame(data, state, step) { 1928 if (step.alpha <= 0) { 1929 return; 1930 } 1931 var specs = findSpecs(data.metrics, data.frames, step.frame, step.lane); 1932 var sheet = specs.sheet; 1933 var sprite = specs.sprite; 1934 if (!sheet || !sprite) { 1935 return; 1936 } 1937 var src = data.source[sheet.id]; 1938 var image = data.images[sheet.id]; 1939 if (image.complete === false) { 1940 return; 1941 } 1942 state.canvas.show(); 1943 var w = state.canvas[0].width / data.canvasRatio; 1944 var h = state.canvas[0].height / data.canvasRatio; 1945 state.context.globalAlpha = step.alpha; 1946 state.context.drawImage(image, sprite.sampledX, sprite.sampledY, sprite.sampledWidth, sprite.sampledHeight, 0, 0, w, h); 1947 } 1948 function tick(data) { 1949 var state = getState$$1(data); 1950 killLoop(data); 1951 if (!state.context) { 1952 return; 1953 } 1954 var d = 0; 1955 clearFrame(data, state); 1956 state.context.clearRect(0, 0, data.width, data.height); 1957 for (var _i = 0, _a = state.steps; _i < _a.length; _i++) { 1958 var step = _a[_i]; 1959 step.live = Math.max(step.live - step.step, 0); 1960 step.alpha = Math.max(step.live - 0.25, 0); 1961 drawFrame(data, state, step); 1962 d += step.alpha + step.d; 1963 } 1964 if (state.cssBlur) { 1965 applyCssBlur(state.canvas, d); 1966 } 1967 removeOldFrames(state.steps); 1968 if (state.steps.length) { 1969 loop(data); 1970 } 1971 } 1972 registerPlugin(NAME, { 1973 name: NAME, 1974 onLoad: init, 1975 onFrameChanged: onFrame 1976 }); 1977})(); 1978 1979(function () { 1980 var max = Math.max; 1981 var min = Math.min; 1982 var NAME = 'ease'; 1983 function getState$$1(data) { 1984 return getPluginState(data, NAME); 1985 } 1986 function getOption(data, name, fallback) { 1987 return data[name] || fallback; 1988 } 1989 function init(e, data) { 1990 var state = getState$$1(data); 1991 state.maxSamples = max(getOption(data, 'easeMaxSamples', 5), 0); 1992 state.damping = max(min(getOption(data, 'easeDamping', 0.9), 0.999), 0); 1993 state.abortTime = max(getOption(data, 'easeAbortTime', 250), 16); 1994 state.updateTime = max(getOption(data, 'easeUpdateTime', data.frameTime), 16); 1995 state.samples = []; 1996 state.steps = []; 1997 } 1998 function update(e, data) { 1999 if (is(data, 'dragging')) { 2000 killLoop(data); 2001 sampleInput(data); 2002 } 2003 } 2004 function end(e, data) { 2005 var state = getState$$1(data); 2006 var samples = state.samples; 2007 var last; 2008 var lanes = 0; 2009 var frames = 0; 2010 var time = 0; 2011 for (var _i = 0, samples_1 = samples; _i < samples_1.length; _i++) { 2012 var sample = samples_1[_i]; 2013 if (!last) { 2014 last = sample; 2015 continue; 2016 } 2017 var dt = sample.time - last.time; 2018 if (dt > state.abortTime) { 2019 lanes = frames = time = 0; 2020 return killLoop(data); 2021 } 2022 frames += sample.frame - last.frame; 2023 lanes += sample.lane - last.lane; 2024 time += dt; 2025 last = sample; 2026 } 2027 samples.length = 0; 2028 if (!time) { 2029 return; 2030 } 2031 state.lane = data.lane; 2032 state.lanes = 0; 2033 state.laneStep = lanes / time * state.updateTime; 2034 state.frame = data.frame; 2035 state.frames = 0; 2036 state.frameStep = frames / time * state.updateTime; 2037 loop(data); 2038 } 2039 function sampleInput(data) { 2040 var state = getState$$1(data); 2041 // add a new sample 2042 state.samples.push({ 2043 time: new Date().getTime(), 2044 frame: data.frame, 2045 lane: data.lane 2046 }); 2047 // drop old samples 2048 while (state.samples.length > state.maxSamples) { 2049 state.samples.shift(); 2050 } 2051 } 2052 function killLoop(data) { 2053 var state = getState$$1(data); 2054 if (state.handler != null) { 2055 window.clearTimeout(state.handler); 2056 state.handler = null; 2057 } 2058 } 2059 function loop(data) { 2060 var state = getState$$1(data); 2061 state.handler = window.setTimeout(function () { tick(data); }, state.updateTime); 2062 } 2063 function tick(data) { 2064 var state = getState$$1(data); 2065 state.lanes += state.laneStep; 2066 state.frames += state.frameStep; 2067 state.laneStep *= state.damping; 2068 state.frameStep *= state.damping; 2069 var frame = Math.floor(state.frame + state.frames); 2070 var lane = Math.floor(state.lane + state.lanes); 2071 updateFrame(data, frame, lane); 2072 if (is(data, 'dragging')) { 2073 killLoop(data); 2074 } 2075 else if (Math.abs(state.frameStep) > 0.005 || Math.abs(state.laneStep) > 0.005) { 2076 loop(data); 2077 } 2078 else { 2079 killLoop(data); 2080 } 2081 } 2082 registerPlugin(NAME, { 2083 name: NAME, 2084 onLoad: init, 2085 mousemove: update, 2086 mouseup: end, 2087 mouseleave: end, 2088 touchmove: update, 2089 touchend: end, 2090 touchcancel: end 2091 }); 2092})(); 2093 2094(function () { 2095 var NAME = 'gallery'; 2096 function getState$$1(data) { 2097 return getPluginState(data, NAME); 2098 } 2099 function getOption(data, name, fallback) { 2100 return data[name] || fallback; 2101 } 2102 function load(e, data) { 2103 var state = getState$$1(data); 2104 state.images = []; 2105 state.offsets = []; 2106 state.frame = data.frame; 2107 state.speed = getOption(data, 'gallerySpeed', 500); 2108 state.opacity = getOption(data, 'galleryOpacity', 0.25); 2109 state.stage = getOption(data, 'galleryStage', $$1('<div></div>')); 2110 state.stage.empty().addClass('gallery-stage').prependTo(data.stage); 2111 var size = 0; 2112 for (var _i = 0, _a = data.images; _i < _a.length; _i++) { 2113 var image = _a[_i]; 2114 var naturalSize$$1 = naturalSize(image); 2115 var scale = data.height / naturalSize$$1.height; 2116 var img = $$1(image); 2117 state.stage.append(img); 2118 state.images.push(img); 2119 state.offsets.push(-size + (data.width - image.width * scale) / 2); 2120 size += data.width; 2121 img.css({ 2122 'max-width': 'initial', 2123 opacity: state.opacity, 2124 width: data.width, 2125 height: data.height 2126 }); 2127 } 2128 var innerSize = getInnerSize(data); 2129 var outerSize = data.responsive ? getComputedSize(data) : getOuterSize(data); 2130 var layout = getInnerLayout(data.sizeMode, innerSize, outerSize); 2131 state.stage.css(layout).css({ width: size, left: state.offsets[state.frame] }); 2132 state.images[state.frame].animate({ opacity: 1 }, { duration: state.speed }); 2133 } 2134 function draw(e, data) { 2135 var state = getState$$1(data); 2136 var input = getInputState(data); 2137 var isDragging = is(data, 'dragging'); 2138 if (state.frame !== data.frame && !isDragging) { 2139 state.stage.stop(true, false).animate({ left: state.offsets[data.frame] }, { duration: state.speed }); 2140 state.images[state.frame].animate({ opacity: state.opacity }, { duration: state.speed }); 2141 state.frame = data.frame; 2142 state.images[state.frame].animate({ opacity: 1 }, { duration: state.speed }); 2143 state.stage.animate({ left: state.offsets[state.frame] }); 2144 } 2145 else if (isDragging || state.dX !== input.dX) { 2146 state.dX = input.dX; 2147 state.ddX = input.ddX; 2148 state.stage.stop(true, true).css({ left: state.offsets[state.frame] + state.dX }); 2149 } 2150 } 2151 registerPlugin(NAME, { 2152 name: NAME, 2153 onLoad: load, 2154 onDraw: draw 2155 }); 2156})(); 2157 2158(function () { 2159 var NAME = 'panorama'; 2160 function getState$$1(data) { 2161 return getPluginState(data, NAME); 2162 } 2163 function onLoad(e, data) { 2164 var state = getState$$1(data); 2165 var sprite = data.metrics[0]; 2166 if (!sprite) { 2167 return; 2168 } 2169 if (data.orientation === 'horizontal') { 2170 state.scale = data.target.innerHeight() / sprite.sampledHeight; 2171 data.frames = sprite.sampledWidth; 2172 } 2173 else { 2174 state.scale = data.target.innerWidth() / sprite.sampledWidth; 2175 data.frames = sprite.sampledHeight; 2176 } 2177 var width = Math.floor(sprite.sampledWidth * state.scale); 2178 var height = Math.floor(sprite.sampledHeight * state.scale); 2179 data.stage.css({ 2180 'background-image': "url(" + data.source[sprite.id] + ")", 2181 'background-repeat': 'repeat-both', 2182 // set custom background size to enable responsive rendering 2183 '-webkit-background-size': width + "px " + height + "px", 2184 '-moz-background-size': width + "px " + height + "px", 2185 '-o-background-size': width + "px " + height + "px", 2186 'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */ 2187 }); 2188 } 2189 function onDraw(e, data) { 2190 var state = getState$$1(data); 2191 var px = data.orientation === 'horizontal' ? 1 : 0; 2192 var py = px ? 0 : 1; 2193 var offset = data.frame % data.frames; 2194 var left = Math.round(px * offset * state.scale); 2195 var top = Math.round(py * offset * state.scale); 2196 data.stage.css({ 'background-position': left + "px " + top + "px" }); 2197 } 2198 registerPlugin(NAME, { 2199 name: NAME, 2200 onLoad: onLoad, 2201 onDraw: onDraw 2202 }); 2203})(); 2204 2205(function () { 2206 var NAME = 'zoom'; 2207 function getState$$1(data) { 2208 return getPluginState(data, NAME); 2209 } 2210 function getOption(data, name, fallback) { 2211 return name in data ? data[name] : fallback; 2212 } 2213 function onInit(e, data) { 2214 var state = getState$$1(data); 2215 state.source = getOption(data, 'zoomSource', data.source); 2216 state.useWheel = getOption(data, 'zoomUseWheel', false); 2217 state.useClick = getOption(data, 'zoomUseClick', true); 2218 state.pinFrame = getOption(data, 'zoomPinFrame', true); 2219 state.doubleClickTime = getOption(data, 'zoomDoubleClickTime', 500); 2220 state.stage = state.stage || $$1("<div class='zoom-stage'></div>"); 2221 state.stage.css({ 2222 width: '100%', 2223 height: '100%', 2224 top: 0, 2225 left: 0, 2226 bottom: 0, 2227 right: 0, 2228 position: 'absolute' 2229 }) 2230 .appendTo(data.target) 2231 .hide(); 2232 } 2233 function onDestroy(e, data) { 2234 var state = getState$$1(data); 2235 if (state.stage) { 2236 state.stage.remove(); 2237 delete state.stage; 2238 } 2239 } 2240 function updateInput$$1(e, data) { 2241 var state = getState$$1(data); 2242 if (!state.stage.is(':visible')) { 2243 return; 2244 } 2245 e.preventDefault(); 2246 if (state.pinFrame) { 2247 // hack into drag/move module and disable dragging 2248 // prevents frame change during zoom mode 2249 flag(data, 'dragging', false); 2250 } 2251 // grab touch/cursor position 2252 var cursor = getCursorPosition(e); 2253 // normalize cursor position into [0:1] range 2254 var x = cursor.x / data.width; 2255 var y = cursor.y / data.height; 2256 if (state.oldX == null) { 2257 state.oldX = x; 2258 state.oldY = y; 2259 } 2260 if (state.currentX == null) { 2261 state.currentX = x; 2262 state.currentY = y; 2263 } 2264 // calculate move delta since last frame and remember current position 2265 var dx = x - state.oldX; 2266 var dy = y - state.oldY; 2267 state.oldX = x; 2268 state.oldY = y; 2269 // invert drag direction for touch events to enable 'natural' scrolling 2270 if (e.type.match(/touch/)) { 2271 dx = -dx; 2272 dy = -dy; 2273 } 2274 // accumulate display coordinates 2275 state.currentX = clamp(state.currentX + dx, 0, 1); 2276 state.currentY = clamp(state.currentY + dy, 0, 1); 2277 updateFrame(data, data.frame, data.lane); 2278 } 2279 function onClick(e, data) { 2280 var state = getState$$1(data); 2281 if (!state.useClick) { 2282 return; 2283 } 2284 e.preventDefault(); 2285 // simulate double click 2286 var clickTime = new Date().getTime(); 2287 if (!state.clickTime) { 2288 // on first click 2289 state.clickTime = clickTime; 2290 return; 2291 } 2292 // on second click 2293 var timeDelta = clickTime - state.clickTime; 2294 if (timeDelta > state.doubleClickTime) { 2295 // took too long, back to first click 2296 state.clickTime = clickTime; 2297 return; 2298 } 2299 // on valid double click 2300 state.clickTime = undefined; 2301 if (toggleZoom(data)) { 2302 updateInput$$1(e, data); 2303 } 2304 } 2305 function onMove(e, data) { 2306 var state = getState$$1(data); 2307 if (state.stage.is(':visible')) { 2308 updateInput$$1(e, data); 2309 } 2310 } 2311 function onDraw(e, data) { 2312 var state = getState$$1(data); 2313 // calculate the frame index 2314 var index = data.lane * data.frames + data.frame; 2315 // get the zoom image. Use original frames as fallback. This won't work for sprite sheets 2316 var source = state.source[index]; 2317 var spec = findSpecs(data.metrics, data.frames, data.frame, data.lane); 2318 // get display position 2319 var x = state.currentX; 2320 var y = state.currentY; 2321 // fallback to centered position 2322 if (x == null) { 2323 x = state.currentX = 0.5; 2324 y = state.currentY = 0.5; 2325 } 2326 if (source) { 2327 // scale up from [0:1] to [0:100] range 2328 x = Math.floor(x * 100); 2329 y = Math.floor(y * 100); 2330 // update background image and position 2331 state.stage.css({ 2332 'background-repeat': 'no-repeat', 2333 'background-image': "url('" + source + "')", 2334 'background-position': x + "% " + y + "%" 2335 }); 2336 } 2337 else if (spec.sheet && spec.sprite) { 2338 var sprite = spec.sprite; 2339 var sheet = spec.sheet; 2340 var src = data.source[sheet.id]; 2341 var left = -Math.floor(sprite.sampledX + x * (sprite.sampledWidth - data.width)); 2342 var top_1 = -Math.floor(sprite.sampledY + y * (sprite.sampledHeight - data.height)); 2343 var width = sheet.sampledWidth; 2344 var height = sheet.sampledHeight; 2345 state.stage.css({ 2346 'background-image': "url('" + src + "')", 2347 'background-position': left + "px " + top_1 + "px", 2348 'background-repeat': 'no-repeat', 2349 // set custom background size to enable responsive rendering 2350 '-webkit-background-size': width + "px " + height + "px", 2351 '-moz-background-size': width + "px " + height + "px", 2352 '-o-background-size': width + "px " + height + "px", 2353 'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */ 2354 }); 2355 } 2356 } 2357 function toggleZoom(data) { 2358 var state = getState$$1(data); 2359 if (!state.stage) { 2360 throw new Error('zoom module is not initialized or is not available.'); 2361 } 2362 if (state.stage.is(':visible')) { 2363 showZoom(data); 2364 } 2365 else { 2366 hideZoom(data); 2367 return true; 2368 } 2369 return false; 2370 } 2371 function showZoom(data) { 2372 var state = getState$$1(data); 2373 state.stage.fadeOut(); 2374 data.stage.fadeIn(); 2375 } 2376 function hideZoom(data) { 2377 var state = getState$$1(data); 2378 state.stage.fadeIn(); 2379 data.stage.fadeOut(); 2380 } 2381 function wheel(e, data) { 2382 var state = getState$$1(data); 2383 if (!data.loading && state.useWheel) { 2384 var we = e.originalEvent; 2385 var signY = we.deltaY === 0 ? 0 : we.deltaY > 0 ? 1 : -1; 2386 if (typeof state.useWheel === 'number') { 2387 signY *= state.useWheel; 2388 } 2389 if (state.stage.is(':visible') && signY > 0) { 2390 e.preventDefault(); 2391 showZoom(data); 2392 } 2393 if (!state.stage.is(':visible') && signY < 0) { 2394 e.preventDefault(); 2395 hideZoom(data); 2396 } 2397 } 2398 } 2399 registerPlugin(NAME, { 2400 name: NAME, 2401 mousedown: onClick, 2402 touchstart: onClick, 2403 mousemove: onMove, 2404 touchmove: onMove, 2405 wheel: wheel, 2406 onInit: onInit, 2407 onDestroy: onDestroy, 2408 onDraw: onDraw 2409 }); 2410 extendApi({ 2411 toggleZoom: function () { toggleZoom(this.data); } // tslint:disable-line 2412 }); 2413})(); 2414 2415var Utils = { 2416 $: $$1, 2417 bind: bind, 2418 clamp: clamp, 2419 detectSubsampling: detectSubsampling, 2420 error: error, 2421 findSpecs: findSpecs, 2422 getComputedSize: getComputedSize, 2423 getCursorPosition: getCursorPosition, 2424 getInnerLayout: getInnerLayout, 2425 getInnerSize: getInnerSize, 2426 getOuterSize: getOuterSize, 2427 isFunction: isFunction, 2428 log: log, 2429 measure: measure, 2430 naturalSize: naturalSize, 2431 noop: noop$1, 2432 pixelRatio: pixelRatio, 2433 preload: preload, 2434 prevent: prevent, 2435 sourceArray: sourceArray, 2436 toArray: toArray, 2437 unbind: unbind, 2438 warn: warn, 2439 wrap: wrap 2440}; 2441 2442exports.Utils = Utils; 2443exports.sourceArray = sourceArray; 2444exports.Api = Api; 2445exports.extendApi = extendApi; 2446exports.instances = instances; 2447exports.applyEvents = applyEvents; 2448exports.boot = boot; 2449exports.create = create; 2450exports.createOrUpdate = createOrUpdate; 2451exports.destroy = destroy; 2452exports.namespace = namespace; 2453exports.eventNames = eventNames; 2454exports.callbackNames = callbackNames; 2455exports.eventsToPrevent = eventsToPrevent; 2456exports.defaults = defaults; 2457exports.getInputState = getInputState; 2458exports.updateInput = updateInput; 2459exports.resetInput = resetInput; 2460exports.applyLayout = applyLayout; 2461exports.getPlaybackState = getPlaybackState; 2462exports.updateFrame = updateFrame; 2463exports.stopAnimation = stopAnimation; 2464exports.applyAnimation = applyAnimation; 2465exports.startAnimation = startAnimation; 2466exports.registerPlugin = registerPlugin; 2467exports.registerModule = registerModule; 2468exports.getPlugin = getPlugin; 2469exports.applyPlugins = applyPlugins; 2470exports.getState = getState; 2471exports.getPluginState = getPluginState; 2472exports.is = is; 2473exports.flag = flag; 2474 2475Object.defineProperty(exports, '__esModule', { value: true }); 2476 2477}))); 2478//# sourceMappingURL=spritespin.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.