今天实现一个触摸屏,可以360°来回滑动的图片效果放在vue项目里面!
网上有很多方法,这里采用其中之一,希望对你有帮助~
按步骤引入:
-
在index.html 引入 jq 和一个封装好的js。
封装好的js如下
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.SpriteSpin = {})));
}(this, (function (exports) { 'use strict';
/**
* @internal
*/
var Api = /** @class */ (function () {
function Api(data) {
this.data = data;
}
return Api;
}());
/**
* Adds methods to the SpriteSpin api
*
* @public
*/
function extendApi(methods) {
var api = Api.prototype;
for (var key in methods) {
if (methods.hasOwnProperty(key)) {
if (api[key]) {
throw new Error('API method is already defined: ' + key);
}
else {
api[key] = methods[key];
}
}
}
return api;
}
var $$1 = window.jQuery || window.$;
function getCursorPosition(event) {
var touches = event.touches;
var source = event;
// jQuery Event normalization does not preserve the 'event.touches'
// try to grab touches from the original event
if (event.touches === undefined && event.originalEvent !== undefined) {
touches = event.originalEvent.touches;
}
// get current touch or mouse position
if (touches !== undefined && touches.length > 0) {
source = touches[0];
}
return {
x: source.clientX || 0,
y: source.clientY || 0
};
}
var canvas;
var context;
function detectionContext() {
if (context) {
return context;
}
if (!canvas) {
canvas = document.createElement('canvas');
}
if (!canvas || !canvas.getContext) {
return null;
}
context = canvas.getContext('2d');
return context;
}
/**
* Idea taken from https://github.com/stomita/ios-imagefile-megapixel
* Detects whether the image has been sub sampled by the browser and does not have its original dimensions.
* This method unfortunately does not work for images that have transparent background.
*/
function detectSubsampling(img, width, height) {
if (!detectionContext()) {
return false;
}
// sub sampling happens on images above 1 megapixel
if (width * height <= 1024 * 1024) {
return false;
}
// set canvas to 1x1 pixel size and fill it with magenta color
canvas.width = canvas.height = 1;
context.fillStyle = '#FF00FF';
context.fillRect(0, 0, 1, 1);
// render the image with a negative offset to the left so that it would
// fill the canvas pixel with the top right pixel of the image.
context.drawImage(img, -width + 1, 0);
// check color value to confirm image is covering edge pixel or not.
// if color still magenta, the image is assumed to be sub sampled.
try {
var dat = context.getImageData(0, 0, 1, 1).data;
return (dat[0] === 255) && (dat[1] === 0) && (dat[2] === 255);
}
catch (err) {
// avoids cross origin exception for chrome when code runs without a server
return false;
}
}
/**
*
*/
function getOuterSize(data) {
var width = Math.floor(data.width || data.frameWidth || data.target.innerWidth());
var height = Math.floor(data.height || data.frameHeight || data.target.innerHeight());
return {
aspect: width / height,
height: height,
width: width
};
}
function getComputedSize(data) {
var size = getOuterSize(data);
if (typeof window.getComputedStyle !== 'function') {
return size;
}
var style = window.getComputedStyle(data.target[0]);
if (!style.width) {
return size;
}
size.width = Math.floor(Number(style.width.replace('px', '')));
size.height = Math.floor(size.width / size.aspect);
return size;
}
/**
*
*/
function getInnerSize(data) {
var width = Math.floor(data.frameWidth || data.width || data.target.innerWidth());
var height = Math.floor(data.frameHeight || data.height || data.target.innerHeight());
return {
aspect: width / height,
height: height,
width: width
};
}
/**
*
*/
function getInnerLayout(mode, inner, outer) {
// get mode
var isFit = mode === 'fit';
var isFill = mode === 'fill';
var isMatch = mode === 'stretch';
// resulting layout
var layout = {
width: '100%',
height: '100%',
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute',
overflow: 'hidden'
};
// no calculation here
if (!mode || isMatch) {
return layout;
}
// get size and aspect
var aspectIsGreater = inner.aspect >= outer.aspect;
// mode == original
var width = inner.width;
var height = inner.height;
// keep aspect ratio but fit/fill into container
if (isFit && aspectIsGreater || isFill && !aspectIsGreater) {
width = outer.width;
height = outer.width / inner.aspect;
}
if (isFill && aspectIsGreater || isFit && !aspectIsGreater) {
height = outer.height;
width = outer.height * inner.aspect;
}
// floor the numbers
width = Math.floor(width);
height = Math.floor(height);
// position in center
layout.width = width;
layout.height = height;
layout.top = Math.floor((outer.height - height) / 2);
layout.left = Math.floor((outer.width - width) / 2);
layout.right = layout.left;
layout.bottom = layout.top;
return layout;
}
var img;
/**
* gets the original width and height of an image element
*/
function naturalSize(image) {
// for browsers that support naturalWidth and naturalHeight properties
if (image.naturalWidth) {
return {
height: image.naturalHeight,
width: image.naturalWidth
};
}
// browsers that do not support naturalWidth and naturalHeight properties have to fall back to the width and
// height properties. However, the image might have a css style applied so width and height would return the
// css size. To avoid thet create a new Image object that is free of css rules and grab width and height
// properties
//
// assume that the src has already been downloaded, so no onload callback is needed.
img = img || new Image();
img.src = image.src;
return {
height: img.height,
width: img.width
};
}
/**
* Measures the image frames that are used in the given data object
*/
function measure(images, options) {
if (images.length === 1) {
return [measureSheet(images[0], options)];
}
else if (options.framesX && options.framesY) {
return measureMutipleSheets(images, options);
}
else {
return measureFrames(images, options);
}
}
function measureSheet(image, options) {
var result = { id: 0, sprites: [] };
measureImage(image, options, result);
var frames = options.frames;
var framesX = Number(options.framesX) || frames;
var framesY = Math.ceil(frames / framesX);
var frameWidth = Math.floor(result.width / framesX);
var frameHeight = Math.floor(result.height / framesY);
var divisor = result.isSubsampled ? 2 : 1;
for (var i = 0; i < frames; i++) {
var x = (i % framesX) * frameWidth;
var y = Math.floor(i / framesX) * frameHeight;
result.sprites.push({
id: i,
x: x, y: y,
width: frameWidth,
height: frameHeight,
sampledX: x / divisor,
sampledY: y / divisor,
sampledWidth: frameWidth / divisor,
sampledHeight: frameHeight / divisor
});
}
return result;
}
function measureFrames(images, options) {
var result = [];
for (var id = 0; id < images.length; id++) {
// TODO: optimize
// dont measure images with same size twice
var sheet = measureSheet(images[id], { frames: 1, framesX: 1, detectSubsampling: options.detectSubsampling });
sheet.id = id;
result.push(sheet);
}
return result;
}
function measureMutipleSheets(images, options) {
var result = [];
for (var id = 0; id < images.length; id++) {
// TODO: optimize
// dont measure images with same size twice
var sheet = measureSheet(images[id], {
frames: undefined,
framesX: options.framesX,
framesY: options.framesY,
detectSubsampling: options.detectSubsampling
});
sheet.id = id;
result.push(sheet);
}
return result;
}
function measureImage(image, options, result) {
var size = naturalSize(image);
result.isSubsampled = options.detectSubsampling && detectSubsampling(image, size.width, size.height);
result.width = size.width;
result.height = size.height;
result.sampledWidth = size.width / (result.isSubsampled ? 2 : 1);
result.sampledHeight = size.height / (result.isSubsampled ? 2 : 1);
return result;
}
function findSpecs(metrics, frames, frame, lane) {
var spriteId = lane * frames + frame;
var sheetId = 0;
var sprite = null;
var sheet = null;
while (true) {
sheet = metrics[sheetId];
if (!sheet) {
break;
}
if (spriteId >= sheet.sprites.length) {
spriteId -= sheet.sprites.length;
sheetId++;
continue;
}
sprite = sheet.sprites[spriteId];
break;
}
return { sprite: sprite, sheet: sheet };
}
function indexOf(element, arr) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] === element) {
return i;
}
}
}
function noop() {
//
}
function preload(opts) {
var src;
var input = opts.source;
src = typeof input === 'string' ? [input] : input;
// const src: string[] = ? [opts.source] : opts.source
var images = [];
var targetCount = (opts.preloadCount || src.length);
var onInitiated = opts.initiated || noop;
var onProgress = opts.progress || noop;
var onComplete = opts.complete || noop;
var count = 0;
var completed = false;
var firstLoaded = false;
var tick = function () {
count += 1;
onProgress({
index: indexOf(this, images),
loaded: count,
total: src.length,
percent: Math.round((count / src.length) * 100)
});
firstLoaded = firstLoaded || (this === images[0]);
if (firstLoaded && !completed && (count >= targetCount)) {
completed = true;
onComplete(images);
}
};
for (var _i = 0, src_1 = src; _i < src_1.length; _i++) {
var url = src_1[_i];
var img = new Image();
// push result
images.push(img);
// bind logic, dont care about abort/errors
img.onload = img.onabort = img.onerror = tick;
// begin load
img.src = url;
}
onInitiated(images);
}
function padNumber(num, length, pad) {
var result = String(num);
while (result.length < length) {
result = String(pad) + result;
}
return result;
}
/**
* Generates an array of source strings
*
* @remarks
* Takes a template string and generates an array of strings by interpolating {lane} and {frame} placeholders.
*
* ```
* sourceArray('http://example.com/image_{frame}.jpg, { frame: [1, 3], digits: 2 })
* // gives:
* // [ 'http://example.com/image_01.jpg', 'http://example.com/image_02.jpg', 'http://example.com/image_03.jpg' ]
*
* sourceArray('http://example.com/image_FRAME.jpg, { frame: [1, 3], digits: 2, framePlacer: 'FRAME' })
* // gives:
* // [ 'http://example.com/image_01.jpg', 'http://example.com/image_02.jpg', 'http://example.com/image_03.jpg' ]
* ```
*
* @param template - The template string
* @param opts - Interpolation options
*
* @public
*/
function sourceArray(template, opts) {
var digits = opts.digits || 2;
var lPlacer = opts.lanePlacer || '{lane}';
var fPlacer = opts.framePlacer || '{frame}';
var fStart = 0;
var fEnd = 0;
if (opts.frame) {
fStart = opts.frame[0];
fEnd = opts.frame[1];
}
var lStart = 0;
var lEnd = 0;
if (opts.lane) {
lStart = opts.lane[0];
lEnd = opts.lane[1];
}
var result = [];
for (var lane = lStart; lane <= lEnd; lane += 1) {
for (var frame = fStart; frame <= fEnd; frame += 1) {
result.push(template
.replace(lPlacer, padNumber(lane, digits, '0'))
.replace(fPlacer, padNumber(frame, digits, '0')));
}
}
return result;
}
/**
* The namespace that is used to bind functions to DOM events and store the data object
*/
var namespace = 'spritespin';
/**
* Event names that are recognized by SpriteSpin. A module can implement any of these and they will be bound
* to the target element on which the plugin is called.
*/
var eventNames = [
'mousedown',
'mousemove',
'mouseup',
'mouseenter',
'mouseover',
'mouseleave',
'mousewheel',
'wheel',
'click',
'dblclick',
'touchstart',
'touchmove',
'touchend',
'touchcancel',
'selectstart',
'gesturestart',
'gesturechange',
'gestureend'
];
/**
*
*/
var callbackNames = [
'onInit',
'onProgress',
'onLoad',
'onFrameChanged',
'onFrame',
'onDraw',
'onComplete',
'onDestroy'
];
/**
* Names of events for that the default behavior should be prevented.
*/
var eventsToPrevent = [
'dragstart'
];
/**
* Default set of SpriteSpin options. This also represents the majority of data attributes that are used during the
* lifetime of a SpriteSpin instance. The data is stored inside the target DOM element on which the plugin is called.
*/
var defaults = {
source: undefined,
width: undefined,
height: undefined,
frames: undefined,
framesX: undefined,
lanes: 1,
sizeMode: undefined,
renderer: 'canvas',
lane: 0,
frame: 0,
frameTime: 40,
animate: true,
retainAnimate: false,
reverse: false,
loop: true,
stopFrame: 0,
wrap: true,
wrapLane: false,
sense: 1,
senseLane: undefined,
orientation: 'horizontal',
detectSubsampling: true,
preloadCount: undefined,
touchScrollTimer: [200, 1500],
responsive: undefined,
plugins: undefined
};
function noop$1() {
// noop
}
function wrapConsole(type) {
return console && console[type] ? function () {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
return console.log.apply(console, args);
} : noop$1;
}
var log = wrapConsole('log');
var warn = wrapConsole('warn');
var error = wrapConsole('error');
function toArray(value) {
return Array.isArray(value) ? value : [value];
}
/**
* clamps the given value by the given min and max values
*/
function clamp(value, min, max) {
return (value > max ? max : (value < min ? min : value));
}
/**
*
*/
function wrap(value, min, max, size) {
while (value > max) {
value -= size;
}
while (value < min) {
value += size;
}
return value;
}
/**
* prevents default action on the given event
*/
function prevent(e) {
e.preventDefault();
return false;
}
/**
* Binds on the given target and event the given function.
* The SpriteSpin namespace is attached to the event name
*/
function bind(target, event, func) {
if (func) {
target.bind(event + '.' + namespace, function (e) {
func.apply(target, [e, target.spritespin('data')]);
});
}
}
/**
* Unbinds all SpriteSpin events from given target element
*/
function unbind(target) {
target.unbind('.' + namespace);
}
/**
* Checks if given object is a function
*/
function isFunction(fn) {
return typeof fn === 'function';
}
function pixelRatio(context) {
var devicePixelRatio = window.devicePixelRatio || 1;
var backingStoreRatio = context.webkitBackingStorePixelRatio ||
context.mozBackingStorePixelRatio ||
context.msBackingStorePixelRatio ||
context.oBackingStorePixelRatio ||
context.backingStorePixelRatio || 1;
return devicePixelRatio / backingStoreRatio;
}
var _Utils = Object.freeze({
$: $$1,
getCursorPosition: getCursorPosition,
detectSubsampling: detectSubsampling,
getOuterSize: getOuterSize,
getComputedSize: getComputedSize,
getInnerSize: getInnerSize,
getInnerLayout: getInnerLayout,
measure: measure,
findSpecs: findSpecs,
naturalSize: naturalSize,
preload: preload,
sourceArray: sourceArray,
noop: noop$1,
log: log,
warn: warn,
error: error,
toArray: toArray,
clamp: clamp,
wrap: wrap,
prevent: prevent,
bind: bind,
unbind: unbind,
isFunction: isFunction,
pixelRatio: pixelRatio
});
/**
* Applies css attributes to layout the SpriteSpin containers.
*
* @internal
*/
function applyLayout(data) {
// disable selection
data.target
.attr('unselectable', 'on')
.css({
width: '',
height: '',
'-ms-user-select': 'none',
'-moz-user-select': 'none',
'-khtml-user-select': 'none',
'-webkit-user-select': 'none',
'user-select': 'none'
});
var size = data.responsive ? getComputedSize(data) : getOuterSize(data);
var layout = getInnerLayout(data.sizeMode, getInnerSize(data), size);
// apply layout on target
data.target.css({
width: size.width,
height: size.height,
position: 'relative',
overflow: 'hidden'
});
// apply layout on stage
data.stage
.css(layout)
.hide();
if (!data.canvas) {
return;
}
// apply layout on canvas
data.canvas.css(layout).hide();
// apply pixel ratio on canvas
data.canvasRatio = data.canvasRatio || pixelRatio(data.context);
if (typeof layout.width === 'number' && typeof layout.height === 'number') {
data.canvas[0].width = (layout.width * data.canvasRatio) || size.width;
data.canvas[0].height = (layout.height * data.canvasRatio) || size.height;
}
else {
data.canvas[0].width = (size.width * data.canvasRatio);
data.canvas[0].height = (size.height * data.canvasRatio);
}
// width and height must be set before calling scale
data.context.scale(data.canvasRatio, data.canvasRatio);
}
/**
* Gets a state object by name.
* @internal
* @param data - The SpriteSpin instance data
* @param name - The name of the state object
*/
function getState(data, name) {
data.state = data.state || {};
data.state[name] = data.state[name] || {};
return data.state[name];
}
/**
* Gets a plugin state object by name.
*
* @remarks
* Plugins should use this method to get or create a state object where they can
* store any instance variables.
*
* @public
* @param data - The SpriteSpin instance data
* @param name - The name of the plugin
*/
function getPluginState(data, name) {
var state = getState(data, 'plugin');
state[name] = state[name] || {};
return state[name];
}
/**
* Checks whether a flag is set. See {@link flag}.
*
* @public
* @param data - The SpriteSpin instance data
* @param key - The name of the flag
*/
function is(data, key) {
return !!getState(data, 'flags')[key];
}
/**
* Sets a flag value. See {@link is}.
*
* @public
* @param data - The SpriteSpin instance data
* @param key - The name of the flag
* @param value - The value to set
*/
function flag(data, key, value) {
getState(data, 'flags')[key] = !!value;
}
/**
* Gets the playback state
*
* @public
* @param data - The SpriteSpin instance data
*/
function getPlaybackState(data) {
return getState(data, 'playback');
}
function updateLane(data, lane) {
data.lane = data.wrapLane
? wrap(lane, 0, data.lanes - 1, data.lanes)
: clamp(lane, 0, data.lanes - 1);
}
function updateAnimationFrame(data) {
data.frame += (data.reverse ? -1 : 1);
// wrap the frame value to fit in range [0, data.frames)
data.frame = wrap(data.frame, 0, data.frames - 1, data.frames);
// stop animation if loop is disabled and the stopFrame is reached
if (!data.loop && (data.frame === data.stopFrame)) {
stopAnimation(data);
}
}
function updateInputFrame(data, frame) {
data.frame = Number(frame);
data.frame = data.wrap
? wrap(data.frame, 0, data.frames - 1, data.frames)
: clamp(data.frame, 0, data.frames - 1);
}
function updateAnimation(data) {
var state = getPlaybackState(data);
if (state.handler) {
updateBefore(data);
updateAnimationFrame(data);
updateAfter(data);
}
}
function updateBefore(data) {
var state = getPlaybackState(data);
state.lastFrame = data.frame;
state.lastLane = data.lane;
}
function updateAfter(data) {
var state = getPlaybackState(data);
if (state.lastFrame !== data.frame || state.lastLane !== data.lane) {
data.target.trigger('onFrameChanged.' + namespace, data);
}
data.target.trigger('onFrame.' + namespace, data);
data.target.trigger('onDraw.' + namespace, data);
}
/**
* Updates the frame or lane number of the SpriteSpin data.
*
* @public
* @param data - The SpriteSpin instance data
* @param frame - The frame number to set
* @param lane - The lane number to set
*/
function updateFrame(data, frame, lane) {
updateBefore(data);
if (frame != null) {
updateInputFrame(data, frame);
}
if (lane != null) {
updateLane(data, lane);
}
updateAfter(data);
}
/**
* Stops the running animation.
*
* @public
* @param data - The SpriteSpin instance data
*/
function stopAnimation(data) {
data.animate = false;
var state = getPlaybackState(data);
if (state.handler != null) {
window.clearInterval(state.handler);
state.handler = null;
}
}
/**
* Starts animation playback if needed.
*
* @remarks
* Starts animation playback if `animate` property is `true` and the animation is not yet running.
*
* @public
* @param data - The SpriteSpin instance data
*/
function applyAnimation(data) {
var state = getPlaybackState(data);
if (state.handler && (!data.animate || state.frameTime !== data.frameTime)) {
stopAnimation(data);
}
if (data.animate && !state.handler) {
state.frameTime = data.frameTime;
state.handler = window.setInterval(function () { return updateAnimation(data); }, state.frameTime);
}
}
/**
* Starts the animation playback
*
* @remarks
* Starts the animation playback and also sets the `animate` property to `true`
*
* @public
* @param data - The SpriteSpin instance data
*/
function startAnimation(data) {
data.animate = true;
applyAnimation(data);
}
var plugins = {};
/**
* Registers a plugin.
*
* @remarks
* Use this to add custom Rendering or Updating modules that can be addressed with the 'module' option.
*
* @public
* @param name - The name of the plugin
* @param plugin - The plugin implementation
*/
function registerPlugin(name, plugin) {
if (plugins[name]) {
error("Plugin name \"" + name + "\" is already taken");
return;
}
plugin = plugin || {};
plugins[name] = plugin;
return plugin;
}
/**
* Registers a plugin.
*
* @public
* @deprecated Use {@link registerPlugin} instead
* @param name - The name of the plugin
* @param plugin - The plugin implementation
*/
function registerModule(name, plugin) {
warn('"registerModule" is deprecated, use "registerPlugin" instead');
registerPlugin(name, plugin);
}
/**
* Gets an active plugin by name
*
* @internal
* @param name - The name of the plugin
*/
function getPlugin(name) {
return plugins[name];
}
/**
* Replaces module names on given SpriteSpin data and replaces them with actual implementations.
* @internal
*/
function applyPlugins(data) {
fixPlugins(data);
for (var i = 0; i < data.plugins.length; i += 1) {
var name_1 = data.plugins[i];
if (typeof name_1 !== 'string') {
continue;
}
var plugin = getPlugin(name_1);
if (!plugin) {
error('No plugin found with name ' + name_1);
continue;
}
data.plugins[i] = plugin;
}
}
function fixPlugins(data) {
// tslint:disable no-string-literal
if (data['mods']) {
warn('"mods" option is deprecated, use "plugins" instead');
data.plugins = data['mods'];
delete data['mods'];
}
if (data['behavior']) {
warn('"behavior" option is deprecated, use "plugins" instead');
data.plugins.push(data['behavior']);
delete data['behavior'];
}
if (data['module']) {
warn('"module" option is deprecated, use "plugins" instead');
data.plugins.push(data['module']);
delete data['module'];
}
}
var $$2 = $$1;
var counter = 0;
/**
* Collection of all SpriteSpin instances
*/
var instances = {};
function pushInstance(data) {
counter += 1;
data.id = String(counter);
instances[data.id] = data;
}
function popInstance(data) {
delete instances[data.id];
}
function eachInstance(cb) {
for (var id in instances) {
if (instances.hasOwnProperty(id)) {
cb(instances[id]);
}
}
}
var lazyinit = function () {
// replace function with a noop
// this logic must run only once
lazyinit = function () { };
function onEvent(eventName, e) {
eachInstance(function (data) {
for (var _i = 0, _a = data.plugins; _i < _a.length; _i++) {
var module_1 = _a[_i];
if (typeof module_1[eventName] === 'function') {
module_1[eventName].apply(data.target, [e, data]);
}
}
});
}
function onResize() {
eachInstance(function (data) {
if (data.responsive) {
boot(data);
}
});
}
var _loop_1 = function (eventName) {
$$2(window.document).bind(eventName + '.' + namespace, function (e) {
onEvent('document' + eventName, e);
});
};
for (var _i = 0, eventNames_1 = eventNames; _i < eventNames_1.length; _i++) {
var eventName = eventNames_1[_i];
_loop_1(eventName);
}
var resizeTimeout = null;
$$2(window).on('resize', function () {
window.clearTimeout(resizeTimeout);
resizeTimeout = window.setTimeout(onResize, 100);
});
};
/**
* (re)binds all spritespin events on the target element
*
* @internal
*/
function applyEvents(data) {
var target = data.target;
// Clear all SpriteSpin events on the target element
unbind(target);
// disable all default browser behavior on the following events
// mainly prevents image drag operation
for (var _i = 0, eventsToPrevent_1 = eventsToPrevent; _i < eventsToPrevent_1.length; _i++) {
var eName = eventsToPrevent_1[_i];
bind(target, eName, prevent);
}
// Bind module functions to SpriteSpin events
for (var _a = 0, _b = data.plugins; _a < _b.length; _a++) {
var plugin = _b[_a];
for (var _c = 0, eventNames_2 = eventNames; _c < eventNames_2.length; _c++) {
var eName = eventNames_2[_c];
bind(target, eName, plugin[eName]);
}
for (var _d = 0, callbackNames_1 = callbackNames; _d < callbackNames_1.length; _d++) {
var eName = callbackNames_1[_d];
bind(target, eName, plugin[eName]);
}
}
// bind auto start function to load event.
bind(target, 'onLoad', function (e, d) {
applyAnimation(d);
});
// bind all user events that have been passed on initialization
for (var _e = 0, callbackNames_2 = callbackNames; _e < callbackNames_2.length; _e++) {
var eName = callbackNames_2[_e];
bind(target, eName, data[eName]);
}
}
function applyMetrics(data) {
if (!data.images) {
data.metrics = [];
}
data.metrics = measure(data.images, data);
var spec = findSpecs(data.metrics, data.frames, 0, 0);
if (spec.sprite) {
// TODO: try to remove frameWidth/frameHeight
data.frameWidth = spec.sprite.width;
data.frameHeight = spec.sprite.height;
}
}
/**
* Runs the boot process.
*
* @remarks
* (re)initializes plugins, (re)initializes the layout, (re)binds events and loads source images.
*
* @internal
*/
function boot(data) {
applyPlugins(data);
applyEvents(data);
applyLayout(data);
data.source = toArray(data.source);
data.loading = true;
data.target
.addClass('loading')
.trigger('onInit.' + namespace, data);
preload({
source: data.source,
preloadCount: data.preloadCount,
progress: function (progress) {
data.progress = progress;
data.target.trigger('onProgress.' + namespace, data);
},
complete: function (images) {
data.images = images;
data.loading = false;
data.frames = data.frames || images.length;
applyMetrics(data);
applyLayout(data);
data.stage.show();
data.target
.removeClass('loading')
.trigger('onLoad.' + namespace, data)
.trigger('onFrame.' + namespace, data)
.trigger('onDraw.' + namespace, data)
.trigger('onComplete.' + namespace, data);
}
});
}
/**
* Creates a new SpriteSpin instance
*
* @public
*/
function create(options) {
var _this = this;
var target = options.target;
// SpriteSpin is not initialized
// Create default settings object and extend with given options
var data = $$2.extend(true, {}, defaults, options);
// ensure source is set
data.source = data.source || [];
// ensure plugins are set
data.plugins = data.plugins || [
'360',
'drag'
];
// if image tags are contained inside this DOM element
// use these images as the source files
target.find('img').each(function () {
if (!Array.isArray(data.source)) {
data.source = [];
}
data.source.push($$2(_this).attr('src'));
});
// build inner html
// <div>
// <div class='spritespin-stage'></div>
// <canvas class='spritespin-canvas'></canvas>
// </div>
target
.empty()
.addClass('spritespin-instance')
.append("<div class='spritespin-stage'></div>");
// add the canvas element if canvas rendering is enabled and supported
if (data.renderer === 'canvas') {
var canvas = document.createElement('canvas');
if (!!(canvas.getContext && canvas.getContext('2d'))) {
data.canvas = $$2(canvas).addClass('spritespin-canvas');
data.context = canvas.getContext('2d');
target.append(data.canvas);
target.addClass('with-canvas');
}
else {
// fallback to image rendering mode
data.renderer = 'image';
}
}
// setup references to DOM elements
data.target = target;
data.stage = target.find('.spritespin-stage');
// store the data
target.data(namespace, data);
pushInstance(data);
return data;
}
/**
* Creates a new SpriteSpin instance, or updates an existing one
*
* @public
*/
function createOrUpdate(options) {
lazyinit();
var data = options.target.data(namespace);
if (!data) {
data = create(options);
}
else {
$$2.extend(data, options);
}
boot(data);
return data;
}
/**
* Destroys the SpriteSpin instance
*
* @remarks
* - stops running animation
* - unbinds all events
* - deletes the data on the target element
*
* @public
*/
function destroy(data) {
popInstance(data);
stopAnimation(data);
data.target
.trigger('onDestroy', data)
.html(null)
.attr('style', null)
.attr('unselectable', null)
.removeClass(['spritespin-instance', 'with-canvas']);
unbind(data.target);
data.target.removeData(namespace);
}
/**
* Gets the current input state
*
* @public
* @param data - The SpriteSpin instance data
*/
function getInputState(data) {
return getState(data, 'input');
}
/**
* Updates the input state using a mous or touch event.
*
* @public
* @param e - The input event
* @param data - The SpriteSpin instance data
*/
function updateInput(e, data) {
var cursor = getCursorPosition(e);
var state = getInputState(data);
// cache positions from previous frame
state.oldX = state.currentX;
state.oldY = state.currentY;
state.currentX = cursor.x;
state.currentY = cursor.y;
// Fix old position.
if (state.oldX === undefined || state.oldY === undefined) {
state.oldX = state.currentX;
state.oldY = state.currentY;
}
// Cache the initial click/touch position and store the frame number at which the click happened.
// Useful for different behavior implementations. This must be restored when the click/touch is released.
if (state.startX === undefined || state.startY === undefined) {
state.startX = state.currentX;
state.startY = state.currentY;
state.clickframe = data.frame;
state.clicklane = data.lane;
}
// Calculate the vector from start position to current pointer position.
state.dX = state.currentX - state.startX;
state.dY = state.currentY - state.startY;
// Calculate the vector from last frame position to current pointer position.
state.ddX = state.currentX - state.oldX;
state.ddY = state.currentY - state.oldY;
// Normalize vectors to range [-1:+1]
state.ndX = state.dX / data.target.innerWidth();
state.ndY = state.dY / data.target.innerHeight();
state.nddX = state.ddX / data.target.innerWidth();
state.nddY = state.ddY / data.target.innerHeight();
}
/**
* Resets the input state.
*
* @public
*/
function resetInput(data) {
var input = getInputState(data);
input.startX = input.startY = undefined;
input.currentX = input.currentY = undefined;
input.oldX = input.oldY = undefined;
input.dX = input.dY = 0;
input.ddX = input.ddY = 0;
input.ndX = input.ndY = 0;
input.nddX = input.nddY = 0;
}
function extension(option, value) {
var $target = $$1(this);
if (option === 'data') {
return $target.data(namespace);
}
if (option === 'api') {
var data = $target.data(namespace);
data.api = data.api || new Api(data);
return data.api;
}
if (option === 'destroy') {
return $target.each(function () {
var data = $target.data(namespace);
if (data) {
destroy(data);
}
});
}
if (arguments.length === 2 && typeof option === 'string') {
option = (_a = {}, _a[option] = value, _a);
}
if (typeof option === 'object') {
return createOrUpdate($$1.extend(true, { target: $target }, option)).target;
}
throw new Error('Invalid call to spritespin');
var _a;
}
$$1.fn[namespace] = extension;
// tslint:disable:object-literal-shorthand
// tslint:disable:only-arrow-functions
extendApi({
// Gets a value indicating whether the animation is currently running.
isPlaying: function () {
return getPlaybackState(this.data).handler != null;
},
// Gets a value indicating whether the animation looping is enabled.
isLooping: function () {
return this.data.loop;
},
// Starts/Stops the animation playback
toggleAnimation: function () {
if (this.isPlaying()) {
this.stopAnimation();
}
else {
this.startAnimation();
}
},
// Stops animation playback
stopAnimation: function () {
this.data.animate = false;
stopAnimation(this.data);
},
// Starts animation playback
startAnimation: function () {
this.data.animate = true;
applyAnimation(this.data);
},
// Sets a value indicating whether the animation should be looped or not.
// This might start the animation (if the 'animate' data attribute is set to true)
loop: function (value) {
this.data.loop = value;
applyAnimation(this.data);
return this;
},
// Gets the current frame number
currentFrame: function () {
return this.data.frame;
},
// Updates SpriteSpin to the specified frame.
updateFrame: function (frame) {
updateFrame(this.data, frame);
return this;
},
// Skips the given number of frames
skipFrames: function (step) {
var data = this.data;
updateFrame(data, data.frame + (data.reverse ? -step : +step));
return this;
},
// Updates SpriteSpin so that the next frame is shown
nextFrame: function () {
return this.skipFrames(1);
},
// Updates SpriteSpin so that the previous frame is shown
prevFrame: function () {
return this.skipFrames(-1);
},
// Starts the animations that will play until the given frame number is reached
// options:
// force [boolean] starts the animation, even if current frame is the target frame
// nearest [boolean] animates to the direction with minimum distance to the target frame
playTo: function (frame, options) {
var data = this.data;
options = options || {};
if (!options.force && data.frame === frame) {
return;
}
if (options.nearest) {
// distance to the target frame
var a = frame - data.frame;
// distance to last frame and the to target frame
var b = frame > data.frame ? a - data.frames : a + data.frames;
// minimum distance
var c = Math.abs(a) < Math.abs(b) ? a : b;
data.reverse = c < 0;
}
data.animate = true;
data.loop = false;
data.stopFrame = frame;
applyAnimation(data);
return this;
}
});
function pick(target, names) {
for (var _i = 0, names_1 = names; _i < names_1.length; _i++) {
var name_1 = names_1[_i];
if (target[name_1] || name_1 in target) {
return name_1;
}
}
return names[0];
}
var browser = {
requestFullscreen: pick(document.documentElement, [
'requestFullscreen',
'webkitRequestFullScreen',
'mozRequestFullScreen',
'msRequestFullscreen'
]),
exitFullscreen: pick(document, [
'exitFullscreen',
'webkitExitFullscreen',
'webkitCancelFullScreen',
'mozCancelFullScreen',
'msExitFullscreen'
]),
fullscreenElement: pick(document, [
'fullscreenElement',
'webkitFullscreenElement',
'webkitCurrentFullScreenElement',
'mozFullScreenElement',
'msFullscreenElement'
]),
fullscreenEnabled: pick(document, [
'fullscreenEnabled',
'webkitFullscreenEnabled',
'mozFullScreenEnabled',
'msFullscreenEnabled'
]),
fullscreenchange: pick(document, [
'onfullscreenchange',
'onwebkitfullscreenchange',
'onmozfullscreenchange',
'onMSFullscreenChange'
]).replace(/^on/, ''),
fullscreenerror: pick(document, [
'onfullscreenerror',
'onwebkitfullscreenerror',
'onmozfullscreenerror',
'onMSFullscreenError'
]).replace(/^on/, '')
};
var changeEvent = browser.fullscreenchange + '.' + namespace + '-fullscreen';
function unbindChangeEvent() {
$$1(document).unbind(changeEvent);
}
function bindChangeEvent(callback) {
unbindChangeEvent();
$$1(document).bind(changeEvent, callback);
}
var orientationEvent = 'orientationchange.' + namespace + '-fullscreen';
function unbindOrientationEvent() {
$$1(window).unbind(orientationEvent);
}
function bindOrientationEvent(callback) {
unbindOrientationEvent();
$$1(window).bind(orientationEvent, callback);
}
function requestFullscreenNative(e) {
e = e || document.documentElement;
e[browser.requestFullscreen]();
}
function exitFullscreen() {
return document[browser.exitFullscreen]();
}
function fullscreenEnabled() {
return document[browser.fullscreenEnabled];
}
function fullscreenElement() {
return document[browser.fullscreenElement];
}
function isFullscreen() {
return !!fullscreenElement();
}
function toggleFullscreen(data, opts) {
if (isFullscreen()) {
this.apiRequestFullscreen(opts);
}
else {
this.exitFullscreen();
}
}
function requestFullscreen(data, opts) {
opts = opts || {};
var oWidth = data.width;
var oHeight = data.height;
var oSource = data.source;
var oSize = data.sizeMode;
var oResponsive = data.responsive;
var enter = function () {
data.width = window.screen.width;
data.height = window.screen.height;
data.source = (opts.source || oSource);
data.sizeMode = opts.sizeMode || 'fit';
data.responsive = false;
boot(data);
};
var exit = function () {
data.width = oWidth;
data.height = oHeight;
data.source = oSource;
data.sizeMode = oSize;
data.responsive = oResponsive;
boot(data);
};
bindChangeEvent(function () {
if (isFullscreen()) {
enter();
bindOrientationEvent(enter);
}
else {
unbindChangeEvent();
unbindOrientationEvent();
exit();
}
});
requestFullscreenNative(data.target[0]);
}
extendApi({
fullscreenEnabled: fullscreenEnabled,
fullscreenElement: fullscreenElement,
exitFullscreen: exitFullscreen,
toggleFullscreen: function (opts) {
toggleFullscreen(this.data, opts);
},
requestFullscreen: function (opts) {
requestFullscreen(this.data, opts);
}
});
(function () {
var NAME = 'click';
function click(e, data) {
if (data.loading || !data.stage.is(':visible')) {
return;
}
updateInput(e, data);
var input = getInputState(data);
var half, pos;
var target = data.target, offset = target.offset();
if (data.orientation === 'horizontal') {
half = target.innerWidth() / 2;
pos = input.currentX - offset.left;
}
else {
half = target.innerHeight() / 2;
pos = input.currentY - offset.top;
}
updateFrame(data, data.frame + (pos > half ? 1 : -1));
}
registerPlugin(NAME, {
name: NAME,
mouseup: click,
touchend: click
});
})();
(function () {
var NAME = 'drag';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function getAxis(data) {
if (typeof data.orientation === 'number') {
return data.orientation * Math.PI / 180;
}
if (data.orientation === 'horizontal') {
return 0;
}
return Math.PI / 2;
}
function onInit(e, data) {
var state = getState$$1(data);
var d = [200, 1500];
var t = data.touchScrollTimer || d;
state.minTime = t[0] || d[0];
state.maxTime = t[1] || d[1];
}
function dragStart(e, data) {
var state = getState$$1(data);
if (data.loading || is(data, 'dragging') || data['zoomPinFrame'] && !data.stage.is(':visible')) {
return;
}
// Touch scroll can only be disabled by cancelling the 'touchstart' event.
// If we would try to cancel the 'touchmove' event during a scroll
// chrome browser raises an error
//
// When a user interacts with sprite spin, we dont know whether the intention
// is to scroll the page or to roll the spin.
//
// On first interaction with SpriteSpin the scroll is not disabled
// On double tap within 200ms the scroll is not disabled
// Scroll is only disabled if there was an interaction with SpriteSpin in the past 1500ms
var now = new Date().getTime();
if (state.endAt && (now - state.endAt > state.maxTime)) {
// reset timer if the user has no interaction with spritespin within 1500ms
state.startAt = null;
state.endAt = null;
}
if (state.startAt && (now - state.startAt > state.minTime)) {
// disable scroll only if there was already an interaction with spritespin
// however, allow scrolling on double tab within 200ms
e.preventDefault();
}
state.startAt = now;
state.wasPlaying = !!getPlaybackState(data).handler;
state.frame = data.frame || 0;
state.lane = data.lane || 0;
flag(data, 'dragging', true);
updateInput(e, data);
}
function dragEnd(e, data) {
if (is(data, 'dragging')) {
getState$$1(data).endAt = new Date().getTime();
flag(data, 'dragging', false);
resetInput(data);
if (data.retainAnimate && getState$$1(data).wasPlaying) {
startAnimation(data);
}
}
}
function drag(e, data) {
var state = getState$$1(data);
var input = getInputState(data);
if (!is(data, 'dragging')) {
return;
}
updateInput(e, data);
var rad = getAxis(data);
var sn = Math.sin(rad);
var cs = Math.cos(rad);
var x = ((input.nddX * cs - input.nddY * sn) * data.sense) || 0;
var y = ((input.nddX * sn + input.nddY * cs) * (data.senseLane || data.sense)) || 0;
// accumulate
state.frame += data.frames * x;
state.lane += data.lanes * y;
// update spritespin
var oldFrame = data.frame;
var oldLane = data.lane;
updateFrame(data, Math.floor(state.frame), Math.floor(state.lane));
stopAnimation(data);
}
function mousemove(e, data) {
dragStart(e, data);
drag(e, data);
}
registerPlugin('drag', {
name: 'drag',
onInit: onInit,
mousedown: dragStart,
mousemove: drag,
mouseup: dragEnd,
documentmousemove: drag,
documentmouseup: dragEnd,
touchstart: dragStart,
touchmove: drag,
touchend: dragEnd,
touchcancel: dragEnd
});
registerPlugin('move', {
name: 'move',
onInit: onInit,
mousemove: mousemove,
mouseleave: dragEnd,
touchstart: dragStart,
touchmove: drag,
touchend: dragEnd,
touchcancel: dragEnd
});
})();
(function () {
var NAME = 'hold';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function rememberOptions(data) {
var state = getState$$1(data);
state.frameTime = data.frameTime;
state.animate = data.animate;
state.reverse = data.reverse;
}
function restoreOptions(data) {
var state = getState$$1(data);
data.frameTime = state.frameTime;
data.animate = state.animate;
data.reverse = state.reverse;
}
function start(e, data) {
if (is(data, 'loading') || is(data, 'dragging') || !data.stage.is(':visible')) {
return;
}
rememberOptions(data);
updateInput(e, data);
flag(data, 'dragging', true);
data.animate = true;
applyAnimation(data);
}
function stop(e, data) {
flag(data, 'dragging', false);
resetInput(data);
stopAnimation(data);
restoreOptions(data);
applyAnimation(data);
}
function update(e, data) {
if (!is(data, 'dragging')) {
return;
}
updateInput(e, data);
var input = getInputState(data);
var half, delta;
var target = data.target, offset = target.offset();
if (data.orientation === 'horizontal') {
half = target.innerWidth() / 2;
delta = (input.currentX - offset.left - half) / half;
}
else {
half = (data.height / 2);
delta = (input.currentY - offset.top - half) / half;
}
data.reverse = delta < 0;
delta = delta < 0 ? -delta : delta;
data.frameTime = 80 * (1 - delta) + 20;
if (((data.orientation === 'horizontal') && (input.dX < input.dY)) ||
((data.orientation === 'vertical') && (input.dX < input.dY))) {
e.preventDefault();
}
}
function onFrame(e, data) {
data.animate = true;
applyAnimation(data);
}
registerPlugin(NAME, {
name: NAME,
mousedown: start,
mousemove: update,
mouseup: stop,
mouseleave: stop,
touchstart: start,
touchmove: update,
touchend: stop,
touchcancel: stop,
onFrame: onFrame
});
})();
(function () {
var NAME = 'swipe';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function getOption(data, name, fallback) {
return data[name] || fallback;
}
function init(e, data) {
var state = getState$$1(data);
state.fling = getOption(data, 'swipeFling', 10);
state.snap = getOption(data, 'swipeSnap', 0.50);
}
function start(e, data) {
if (!data.loading && !is(data, 'dragging')) {
updateInput(e, data);
flag(data, 'dragging', true);
}
}
function update(e, data) {
if (!is(data, 'dragging')) {
return;
}
updateInput(e, data);
var frame = data.frame;
var lane = data.lane;
updateFrame(data, frame, lane);
}
function end(e, data) {
if (!is(data, 'dragging')) {
return;
}
flag(data, 'dragging', false);
var state = getState$$1(data);
var input = getInputState(data);
var frame = data.frame;
var lane = data.lane;
var snap = state.snap;
var fling = state.fling;
var dS, dF;
if (data.orientation === 'horizontal') {
dS = input.ndX;
dF = input.ddX;
}
else {
dS = input.ndY;
dF = input.ddY;
}
if (dS >= snap || dF >= fling) {
frame = data.frame - 1;
}
else if (dS <= -snap || dF <= -fling) {
frame = data.frame + 1;
}
resetInput(data);
updateFrame(data, frame, lane);
stopAnimation(data);
}
registerPlugin(NAME, {
name: NAME,
onLoad: init,
mousedown: start,
mousemove: update,
mouseup: end,
mouseleave: end,
touchstart: start,
touchmove: update,
touchend: end,
touchcancel: end
});
})();
(function () {
var NAME = 'wheel';
function wheel(e, data) {
if (!data.loading && data.stage.is(':visible')) {
e.preventDefault();
var we = e.originalEvent;
var signX = we.deltaX === 0 ? 0 : we.deltaX > 0 ? 1 : -1;
var signY = we.deltaY === 0 ? 0 : we.deltaY > 0 ? 1 : -1;
updateFrame(data, data.frame + signY, data.lane + signX);
}
}
registerPlugin(NAME, {
name: NAME,
wheel: wheel
});
})();
(function () {
var template = "\n<div class='spritespin-progress'>\n <div class='spritespin-progress-label'></div>\n <div class='spritespin-progress-bar'></div>\n</div>\n";
function getState$$1(data) {
return getPluginState(data, NAME);
}
var NAME = 'progress';
function onInit(e, data) {
var state = getState$$1(data);
if (!state.stage) {
state.stage = $$1(template);
state.stage.appendTo(data.target);
}
state.stage.find('.spritespin-progress-label')
.text("0%")
.css({ 'text-align': 'center' });
state.stage.find('.spritespin-progress-bar').css({
width: "0%"
});
state.stage.hide().fadeIn();
}
function onProgress(e, data) {
var state = getState$$1(data);
state.stage.find('.spritespin-progress-label')
.text(data.progress.percent + "%")
.css({ 'text-align': 'center' });
state.stage.find('.spritespin-progress-bar').css({
width: data.progress.percent + "%"
});
}
function onLoad(e, data) {
$$1(getState$$1(data).stage).fadeOut();
}
function onDestroy(e, data) {
$$1(getState$$1(data).stage).remove();
}
registerPlugin(NAME, {
name: NAME,
onInit: onInit,
onProgress: onProgress,
onLoad: onLoad,
onDestroy: onDestroy
});
})();
(function () {
var NAME = '360';
function onLoad(e, data) {
data.stage.find('.spritespin-frames').detach();
if (data.renderer === 'image') {
$(data.images).addClass('spritespin-frames').appendTo(data.stage);
}
}
function onDraw(e, data) {
var specs = findSpecs(data.metrics, data.frames, data.frame, data.lane);
var sheet = specs.sheet;
var sprite = specs.sprite;
if (!sheet || !sprite) {
return;
}
var src = data.source[sheet.id];
var image = data.images[sheet.id];
if (data.renderer === 'canvas') {
data.canvas.show();
var w = data.canvas[0].width / data.canvasRatio;
var h = data.canvas[0].height / data.canvasRatio;
data.context.clearRect(0, 0, w, h);
data.context.drawImage(image, sprite.sampledX, sprite.sampledY, sprite.sampledWidth, sprite.sampledHeight, 0, 0, w, h);
return;
}
var scaleX = data.stage.innerWidth() / sprite.sampledWidth;
var scaleY = data.stage.innerHeight() / sprite.sampledHeight;
var top = Math.floor(-sprite.sampledY * scaleY);
var left = Math.floor(-sprite.sampledX * scaleX);
var width = Math.floor(sheet.sampledWidth * scaleX);
var height = Math.floor(sheet.sampledHeight * scaleY);
if (data.renderer === 'background') {
data.stage.css({
'background-image': "url('" + src + "')",
'background-position': left + "px " + top + "px",
'background-repeat': 'no-repeat',
// set custom background size to enable responsive rendering
'-webkit-background-size': width + "px " + height + "px",
'-moz-background-size': width + "px " + height + "px",
'-o-background-size': width + "px " + height + "px",
'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */
});
return;
}
$(data.images).hide();
$(image).show().css({
position: 'absolute',
top: top,
left: left,
'max-width': 'initial',
width: width,
height: height
});
}
registerPlugin(NAME, {
name: NAME,
onLoad: onLoad,
onDraw: onDraw
});
})();
(function () {
var NAME = 'blur';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function getOption(data, name, fallback) {
return data[name] || fallback;
}
function init(e, data) {
var state = getState$$1(data);
state.canvas = state.canvas || $$1("<canvas class='blur-layer'></canvas>");
state.context = state.context || state.canvas[0].getContext('2d');
state.steps = state.steps || [];
state.fadeTime = Math.max(getOption(data, 'blurFadeTime', 200), 1);
state.frameTime = Math.max(getOption(data, 'blurFrameTime', data.frameTime), 16);
state.trackTime = null;
state.cssBlur = !!getOption(data, 'blurCss', false);
var inner = getInnerSize(data);
var outer = data.responsive ? getComputedSize(data) : getOuterSize(data);
var css = getInnerLayout(data.sizeMode, inner, outer);
state.canvas[0].width = data.width * data.canvasRatio;
state.canvas[0].height = data.height * data.canvasRatio;
state.canvas.css(css).show();
state.context.scale(data.canvasRatio, data.canvasRatio);
data.target.append(state.canvas);
}
function onFrame(e, data) {
var state = getState$$1(data);
trackFrame(data);
if (state.timeout == null) {
loop(data);
}
}
function trackFrame(data) {
var state = getState$$1(data);
var ani = getPlaybackState(data);
// distance between frames
var d = Math.abs(data.frame - ani.lastFrame);
// shortest distance
d = d >= data.frames / 2 ? data.frames - d : d;
state.steps.unshift({
frame: data.frame,
lane: data.lane,
live: 1,
step: state.frameTime / state.fadeTime,
d: d,
alpha: 0
});
}
var toRemove = [];
function removeOldFrames(frames) {
toRemove.length = 0;
for (var i = 0; i < frames.length; i += 1) {
if (frames[i].alpha <= 0) {
toRemove.push(i);
}
}
for (var _i = 0, toRemove_1 = toRemove; _i < toRemove_1.length; _i++) {
var item = toRemove_1[_i];
frames.splice(item, 1);
}
}
function loop(data) {
var state = getState$$1(data);
state.timeout = window.setTimeout(function () { tick(data); }, state.frameTime);
}
function killLoop(data) {
var state = getState$$1(data);
window.clearTimeout(state.timeout);
state.timeout = null;
}
function applyCssBlur(canvas, d) {
var amount = Math.min(Math.max((d / 2) - 4, 0), 2.5);
var blur = "blur(" + amount + "px)";
canvas.css({
'-webkit-filter': blur,
filter: blur
});
}
function clearFrame(data, state) {
state.canvas.show();
var w = state.canvas[0].width / data.canvasRatio;
var h = state.canvas[0].height / data.canvasRatio;
// state.context.clearRect(0, 0, w, h)
}
function drawFrame(data, state, step) {
if (step.alpha <= 0) {
return;
}
var specs = findSpecs(data.metrics, data.frames, step.frame, step.lane);
var sheet = specs.sheet;
var sprite = specs.sprite;
if (!sheet || !sprite) {
return;
}
var src = data.source[sheet.id];
var image = data.images[sheet.id];
if (image.complete === false) {
return;
}
state.canvas.show();
var w = state.canvas[0].width / data.canvasRatio;
var h = state.canvas[0].height / data.canvasRatio;
state.context.globalAlpha = step.alpha;
state.context.drawImage(image, sprite.sampledX, sprite.sampledY, sprite.sampledWidth, sprite.sampledHeight, 0, 0, w, h);
}
function tick(data) {
var state = getState$$1(data);
killLoop(data);
if (!state.context) {
return;
}
var d = 0;
clearFrame(data, state);
state.context.clearRect(0, 0, data.width, data.height);
for (var _i = 0, _a = state.steps; _i < _a.length; _i++) {
var step = _a[_i];
step.live = Math.max(step.live - step.step, 0);
step.alpha = Math.max(step.live - 0.25, 0);
drawFrame(data, state, step);
d += step.alpha + step.d;
}
if (state.cssBlur) {
applyCssBlur(state.canvas, d);
}
removeOldFrames(state.steps);
if (state.steps.length) {
loop(data);
}
}
registerPlugin(NAME, {
name: NAME,
onLoad: init,
onFrameChanged: onFrame
});
})();
(function () {
var max = Math.max;
var min = Math.min;
var NAME = 'ease';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function getOption(data, name, fallback) {
return data[name] || fallback;
}
function init(e, data) {
var state = getState$$1(data);
state.maxSamples = max(getOption(data, 'easeMaxSamples', 5), 0);
state.damping = max(min(getOption(data, 'easeDamping', 0.9), 0.999), 0);
state.abortTime = max(getOption(data, 'easeAbortTime', 250), 16);
state.updateTime = max(getOption(data, 'easeUpdateTime', data.frameTime), 16);
state.samples = [];
state.steps = [];
}
function update(e, data) {
if (is(data, 'dragging')) {
killLoop(data);
sampleInput(data);
}
}
function end(e, data) {
var state = getState$$1(data);
var samples = state.samples;
var last;
var lanes = 0;
var frames = 0;
var time = 0;
for (var _i = 0, samples_1 = samples; _i < samples_1.length; _i++) {
var sample = samples_1[_i];
if (!last) {
last = sample;
continue;
}
var dt = sample.time - last.time;
if (dt > state.abortTime) {
lanes = frames = time = 0;
return killLoop(data);
}
frames += sample.frame - last.frame;
lanes += sample.lane - last.lane;
time += dt;
last = sample;
}
samples.length = 0;
if (!time) {
return;
}
state.lane = data.lane;
state.lanes = 0;
state.laneStep = lanes / time * state.updateTime;
state.frame = data.frame;
state.frames = 0;
state.frameStep = frames / time * state.updateTime;
loop(data);
}
function sampleInput(data) {
var state = getState$$1(data);
// add a new sample
state.samples.push({
time: new Date().getTime(),
frame: data.frame,
lane: data.lane
});
// drop old samples
while (state.samples.length > state.maxSamples) {
state.samples.shift();
}
}
function killLoop(data) {
var state = getState$$1(data);
if (state.handler != null) {
window.clearTimeout(state.handler);
state.handler = null;
}
}
function loop(data) {
var state = getState$$1(data);
state.handler = window.setTimeout(function () { tick(data); }, state.updateTime);
}
function tick(data) {
var state = getState$$1(data);
state.lanes += state.laneStep;
state.frames += state.frameStep;
state.laneStep *= state.damping;
state.frameStep *= state.damping;
var frame = Math.floor(state.frame + state.frames);
var lane = Math.floor(state.lane + state.lanes);
updateFrame(data, frame, lane);
if (is(data, 'dragging')) {
killLoop(data);
}
else if (Math.abs(state.frameStep) > 0.005 || Math.abs(state.laneStep) > 0.005) {
loop(data);
}
else {
killLoop(data);
}
}
registerPlugin(NAME, {
name: NAME,
onLoad: init,
mousemove: update,
mouseup: end,
mouseleave: end,
touchmove: update,
touchend: end,
touchcancel: end
});
})();
(function () {
var NAME = 'gallery';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function getOption(data, name, fallback) {
return data[name] || fallback;
}
function load(e, data) {
var state = getState$$1(data);
state.images = [];
state.offsets = [];
state.frame = data.frame;
state.speed = getOption(data, 'gallerySpeed', 500);
state.opacity = getOption(data, 'galleryOpacity', 0.25);
state.stage = getOption(data, 'galleryStage', $$1('<div></div>'));
state.stage.empty().addClass('gallery-stage').prependTo(data.stage);
var size = 0;
for (var _i = 0, _a = data.images; _i < _a.length; _i++) {
var image = _a[_i];
var naturalSize$$1 = naturalSize(image);
var scale = data.height / naturalSize$$1.height;
var img = $$1(image);
state.stage.append(img);
state.images.push(img);
state.offsets.push(-size + (data.width - image.width * scale) / 2);
size += data.width;
img.css({
'max-width': 'initial',
opacity: state.opacity,
width: data.width,
height: data.height
});
}
var innerSize = getInnerSize(data);
var outerSize = data.responsive ? getComputedSize(data) : getOuterSize(data);
var layout = getInnerLayout(data.sizeMode, innerSize, outerSize);
state.stage.css(layout).css({ width: size, left: state.offsets[state.frame] });
state.images[state.frame].animate({ opacity: 1 }, { duration: state.speed });
}
function draw(e, data) {
var state = getState$$1(data);
var input = getInputState(data);
var isDragging = is(data, 'dragging');
if (state.frame !== data.frame && !isDragging) {
state.stage.stop(true, false).animate({ left: state.offsets[data.frame] }, { duration: state.speed });
state.images[state.frame].animate({ opacity: state.opacity }, { duration: state.speed });
state.frame = data.frame;
state.images[state.frame].animate({ opacity: 1 }, { duration: state.speed });
state.stage.animate({ left: state.offsets[state.frame] });
}
else if (isDragging || state.dX !== input.dX) {
state.dX = input.dX;
state.ddX = input.ddX;
state.stage.stop(true, true).css({ left: state.offsets[state.frame] + state.dX });
}
}
registerPlugin(NAME, {
name: NAME,
onLoad: load,
onDraw: draw
});
})();
(function () {
var NAME = 'panorama';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function onLoad(e, data) {
var state = getState$$1(data);
var sprite = data.metrics[0];
if (!sprite) {
return;
}
if (data.orientation === 'horizontal') {
state.scale = data.target.innerHeight() / sprite.sampledHeight;
data.frames = sprite.sampledWidth;
}
else {
state.scale = data.target.innerWidth() / sprite.sampledWidth;
data.frames = sprite.sampledHeight;
}
var width = Math.floor(sprite.sampledWidth * state.scale);
var height = Math.floor(sprite.sampledHeight * state.scale);
data.stage.css({
'background-image': "url(" + data.source[sprite.id] + ")",
'background-repeat': 'repeat-both',
// set custom background size to enable responsive rendering
'-webkit-background-size': width + "px " + height + "px",
'-moz-background-size': width + "px " + height + "px",
'-o-background-size': width + "px " + height + "px",
'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */
});
}
function onDraw(e, data) {
var state = getState$$1(data);
var px = data.orientation === 'horizontal' ? 1 : 0;
var py = px ? 0 : 1;
var offset = data.frame % data.frames;
var left = Math.round(px * offset * state.scale);
var top = Math.round(py * offset * state.scale);
data.stage.css({ 'background-position': left + "px " + top + "px" });
}
registerPlugin(NAME, {
name: NAME,
onLoad: onLoad,
onDraw: onDraw
});
})();
(function () {
var NAME = 'zoom';
function getState$$1(data) {
return getPluginState(data, NAME);
}
function getOption(data, name, fallback) {
return name in data ? data[name] : fallback;
}
function onInit(e, data) {
var state = getState$$1(data);
state.source = getOption(data, 'zoomSource', data.source);
state.useWheel = getOption(data, 'zoomUseWheel', false);
state.useClick = getOption(data, 'zoomUseClick', true);
state.pinFrame = getOption(data, 'zoomPinFrame', true);
state.doubleClickTime = getOption(data, 'zoomDoubleClickTime', 500);
state.stage = state.stage || $$1("<div class='zoom-stage'></div>");
state.stage.css({
width: '100%',
height: '100%',
top: 0,
left: 0,
bottom: 0,
right: 0,
position: 'absolute'
})
.appendTo(data.target)
.hide();
}
function onDestroy(e, data) {
var state = getState$$1(data);
if (state.stage) {
state.stage.remove();
delete state.stage;
}
}
function updateInput$$1(e, data) {
var state = getState$$1(data);
if (!state.stage.is(':visible')) {
return;
}
e.preventDefault();
if (state.pinFrame) {
// hack into drag/move module and disable dragging
// prevents frame change during zoom mode
flag(data, 'dragging', false);
}
// grab touch/cursor position
var cursor = getCursorPosition(e);
// normalize cursor position into [0:1] range
var x = cursor.x / data.width;
var y = cursor.y / data.height;
if (state.oldX == null) {
state.oldX = x;
state.oldY = y;
}
if (state.currentX == null) {
state.currentX = x;
state.currentY = y;
}
// calculate move delta since last frame and remember current position
var dx = x - state.oldX;
var dy = y - state.oldY;
state.oldX = x;
state.oldY = y;
// invert drag direction for touch events to enable 'natural' scrolling
if (e.type.match(/touch/)) {
dx = -dx;
dy = -dy;
}
// accumulate display coordinates
state.currentX = clamp(state.currentX + dx, 0, 1);
state.currentY = clamp(state.currentY + dy, 0, 1);
updateFrame(data, data.frame, data.lane);
}
function onClick(e, data) {
var state = getState$$1(data);
if (!state.useClick) {
return;
}
e.preventDefault();
// simulate double click
var clickTime = new Date().getTime();
if (!state.clickTime) {
// on first click
state.clickTime = clickTime;
return;
}
// on second click
var timeDelta = clickTime - state.clickTime;
if (timeDelta > state.doubleClickTime) {
// took too long, back to first click
state.clickTime = clickTime;
return;
}
// on valid double click
state.clickTime = undefined;
if (toggleZoom(data)) {
updateInput$$1(e, data);
}
}
function onMove(e, data) {
var state = getState$$1(data);
if (state.stage.is(':visible')) {
updateInput$$1(e, data);
}
}
function onDraw(e, data) {
var state = getState$$1(data);
// calculate the frame index
var index = data.lane * data.frames + data.frame;
// get the zoom image. Use original frames as fallback. This won't work for spritesheets
var source = state.source[index];
var spec = findSpecs(data.metrics, data.frames, data.frame, data.lane);
// get display position
var x = state.currentX;
var y = state.currentY;
// fallback to centered position
if (x == null) {
x = state.currentX = 0.5;
y = state.currentY = 0.5;
}
if (source) {
// scale up from [0:1] to [0:100] range
x = Math.floor(x * 100);
y = Math.floor(y * 100);
// update background image and position
state.stage.css({
'background-repeat': 'no-repeat',
'background-image': "url('" + source + "')",
'background-position': x + "% " + y + "%"
});
}
else if (spec.sheet && spec.sprite) {
var sprite = spec.sprite;
var sheet = spec.sheet;
var src = data.source[sheet.id];
var left = -Math.floor(sprite.sampledX + x * (sprite.sampledWidth - data.width));
var top_1 = -Math.floor(sprite.sampledY + y * (sprite.sampledHeight - data.height));
var width = sheet.sampledWidth;
var height = sheet.sampledHeight;
state.stage.css({
'background-image': "url('" + src + "')",
'background-position': left + "px " + top_1 + "px",
'background-repeat': 'no-repeat',
// set custom background size to enable responsive rendering
'-webkit-background-size': width + "px " + height + "px",
'-moz-background-size': width + "px " + height + "px",
'-o-background-size': width + "px " + height + "px",
'background-size': width + "px " + height + "px" /* Chrome, Firefox 4+, IE 9+, Opera, Safari 5+ */
});
}
}
function toggleZoom(data) {
var state = getState$$1(data);
if (!state.stage) {
throw new Error('zoom module is not initialized or is not available.');
}
if (state.stage.is(':visible')) {
showZoom(data);
}
else {
hideZoom(data);
return true;
}
return false;
}
function showZoom(data) {
var state = getState$$1(data);
state.stage.fadeOut();
data.stage.fadeIn();
}
function hideZoom(data) {
var state = getState$$1(data);
state.stage.fadeIn();
data.stage.fadeOut();
}
function wheel(e, data) {
var state = getState$$1(data);
if (!data.loading && state.useWheel) {
var we = e.originalEvent;
var signY = we.deltaY === 0 ? 0 : we.deltaY > 0 ? 1 : -1;
if (typeof state.useWheel === 'number') {
signY *= state.useWheel;
}
if (state.stage.is(':visible') && signY > 0) {
e.preventDefault();
showZoom(data);
}
if (!state.stage.is(':visible') && signY < 0) {
e.preventDefault();
hideZoom(data);
}
}
}
registerPlugin(NAME, {
name: NAME,
mousedown: onClick,
touchstart: onClick,
mousemove: onMove,
touchmove: onMove,
wheel: wheel,
onInit: onInit,
onDestroy: onDestroy,
onDraw: onDraw
});
extendApi({
toggleZoom: function () { toggleZoom(this.data); } // tslint:disable-line
});
})();
var Utils = _Utils;
exports.Utils = Utils;
exports.sourceArray = sourceArray;
exports.Api = Api;
exports.extendApi = extendApi;
exports.instances = instances;
exports.applyEvents = applyEvents;
exports.boot = boot;
exports.create = create;
exports.createOrUpdate = createOrUpdate;
exports.destroy = destroy;
exports.namespace = namespace;
exports.eventNames = eventNames;
exports.callbackNames = callbackNames;
exports.eventsToPrevent = eventsToPrevent;
exports.defaults = defaults;
exports.getInputState = getInputState;
exports.updateInput = updateInput;
exports.resetInput = resetInput;
exports.applyLayout = applyLayout;
exports.getPlaybackState = getPlaybackState;
exports.updateFrame = updateFrame;
exports.stopAnimation = stopAnimation;
exports.applyAnimation = applyAnimation;
exports.startAnimation = startAnimation;
exports.registerPlugin = registerPlugin;
exports.registerModule = registerModule;
exports.getPlugin = getPlugin;
exports.applyPlugins = applyPlugins;
exports.getState = getState;
exports.getPluginState = getPluginState;
exports.is = is;
exports.flag = flag;
Object.defineProperty(exports, '__esModule', { value: true });
})));
//# sourceMappingURL=spritespin.js.map
-
在页面上引入 html标签
<div class="spritespin" > </div>
- 初始化时候调用一下即可
$(function() {
$('a.js-fullscreen').click(function(e) {
e.preventDefault();
$('.spritespin').spritespin('api').requestFullscreen();
});
$('.spritespin').spritespin({
source: SpriteSpin.sourceArray('../../../static/imgs/{frame}.jpg', { frame: [0,39], digits: 1 }),
width: 450,
height: 450,
sense: 1
});
});
这样就可以360°滑动,但是如果嵌套在轮播图是有问题 需要更改第 2、3步骤:
2. 第二步更改成
<div :class="'spritespin' + index" ></div>
3. 第三步改成
initPic(classNum,picAllList){
$('a.js-fullscreen').click(function(e) {
e.preventDefault();
$(classNum).spritespin('api').requestFullscreen();
});
$(classNum).spritespin({
source:picAllList,
width: 533,
height: 441,
sense: 1
});
},
这个方法在调用的时候是传的一个数组如下
for(let i = 0; i< len; i++)
{
this.initPic('.spritespin'+i,this.prdList[i].picList)
}
这样就可以在轮播图中调用多个360°滑动图片!
版权声明:本文为return_js原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。