/**
* @function animationSequence
* @summary
* Use this function to create a sprite animation sequence from a sprite sheet.
* @description
* <strong>Note: This function should only be called after the user has engaged with the ad as it will be loading additional assets.</strong>
*
* Options Object:
* * eventLabel:
* * Type: string
* * Requirements: Required
* * Description: string prepended to event names
*
* * container:
* * Type: Movie Clip
* * Requirements: Required
* * Description: The movie clip that will contain your sprite animation sequence.
* * Notes: The sprite animation sequence will be scaled to fit the size of this container movie clip.
*
* * spritesheet:
* * Type: String
* * Requirements: Required
* * Description: The path to the spritesheet image.
*
* * json:
* * Type: String
* * Requirements: Optional
* * Description: The path to the JSON that accompanies your spritesheet image.
* * Note: Having JSON is required, however the property is optional. If no opts.json path is specified, the animationSequence function will automatically assume that you have created a JSON file in the src/json directory and have given it the same filename as your sprite sheet image.
*
* * framerate
* * Type: Integer
* * Requirements: Optional
* * Default: 24
* * Description: The framerate for the animation. Set this value to change how fast the animation sequence plays. Should be a non-zero integer (whole-number).
*
* * loop:
* * Type: Boolean
* * Requirements: Optional
* * Default: True
* * Description: If true, the animation sequence will play in a loop, restarting and playing thru each time it completes.
*
* * autoplay:
* * Type: Boolean
* * Default: True
* * Requirements: Optional
* * Description: If true, the animtion sequence will begin playing automatically, as soon as it is ready.
*
* Returns an object with a play and pause function:
* ```
* {
* play: function, (play or resume the animation)
* pause: function (pause the animation)
* }
* ```
* The following event names are emitted:
* ```
* eventLabel + '-ANIMATION_SEQUENCE_COMPLETE'
* eventLabel + '-ANIMATION_SEQUENCE_PROGRESS'
* eventLabel + '-ANIMATION_SEQUENCE_ERROR'
* eventLabel + '-ANIMATION_SEQUENCE_SPRITESHEET_ERROR'
* eventLabel + '-ANIMATION_SEQUENCE_JSON_ERROR'
* ```
* Sample Usage:
* ```
* var here = this
* var animation = window.$b.snippets.animationSequence({
* eventLabel: 'KiaSedan',
* spritesheet: 'images/s.png',
* json: 'json/spritesheet.json',
* container: here.slateDesign.imageContainer,
* framerate: 48,
* autoplay: false,
* loop: true
* })
* var completeFunction = function (evt) {
* here.slateDesign.playBtn.addEventListener('click', function () {
* animation.play()
* })
* here.slateDesign.pauseBtn.addEventListener('click', function () {
* animation.pause()
* })
* }
* window.$b.on('KiaSedan-ANIMATION_SEQUENCE_COMPLETE, completeFunction)
* ```
*
* @param {Object} opts Object containing all of the params to pass into the function
* @param {string} opts.eventLabel a string prepended to the event names
* @param {MovieClip} opts.container The movie clip that will contain your sprite animation sequence
* @param {Object} opts.spritesheet
* @param {string} opts.spritesheet.src the string path to the spritesheet image file (ex: 'images/mySpriteSheet.png')
* @param {Object} opts.spritesheet.json JSON object containing size and coordinates for each image frame in sprite sheet
* @param {number=} opts.framerate The framerate for the animation. Set this value to change how fast the animation sequence plays. Should be a non-zero integer (whole-number).
* @param {boolean=} opts.loop Sets the animation sequence to play in a loop (default true)
* @param {boolean=} opts.autoplay Sets the animation to automatically play as soon as it is ready (default true)
* @param {string=} opts.root optional (external) baseUrl (if not specified in opts.spritesheet.src)
* @returns {Object<play, pause>}
*
*/
function animationSequence (opts) {
var _this = {}
// placeholders under images are loaded and sprite is created
_this.play = function () {}
_this.pause = function () {}
var createjs = window.createjs
if (!opts.eventLabel || typeof opts.eventLabel !== 'string') {
console.error('You must provide a (string) label for the event prefix.')
return _this
}
var eventLabel = opts.eventLabel
var completeEvent = eventLabel + '-ANIMATION_SEQUENCE_COMPLETE'
var errorEvent = eventLabel + '-ANIMATION_SEQUENCE_ERROR'
var progressEvent = eventLabel + '-ANIMATION_SEQUENCE_PROGRESS'
var message
if (!(typeof opts === 'object')) {
message = 'You must provide an options (opts) object with parameters to pass into the function'
console.log(errorEvent, message)
window.$b.emit(errorEvent, message)
return _this
}
if (!(opts.container instanceof createjs.MovieClip)) {
message = 'You must provide a container movie clip reference which will contain your spritesheet animation once it has been created.'
console.log(errorEvent, message)
window.$b.emit(errorEvent, message)
return _this
}
if (!opts.spritesheet || typeof opts.spritesheet !== 'string') {
message = 'You must provide a [string] path to an image file (opts.spritesheet)'
console.log(errorEvent, message)
window.$b.emit(errorEvent, message)
return _this
}
if (opts.json && typeof opts.json !== 'string') {
console.log('The json property must be a [string] path to a JSON file')
return _this
}
// set loaded to false by default
_this.loaded = false
_this.spritesheet = opts.spritesheet
var jsonFilename = opts.json || null
// If no opts.json (json path) was specified, assume path to json folder + same filename as spritesheet image
if (!opts.json) {
var str = _this.spritesheet.split('/')
str = str[str.length - 1].split('.')
jsonFilename = 'json/' + str[0] + '.json'
}
// Turns to true if loading of JSON or spritesheet fails
_this.failed = false
_this.container = opts.container
if (opts.loop !== false) {
opts.loop = true
}
if (opts.autoplay !== false) {
opts.autoplay = true
}
_this.loop = opts.loop
_this.autoplay = opts.autoplay
if (typeof opts.framerate === 'number') {
if (opts.framerate < 1 || opts.framerate !== Math.floor(opts.framerate)) {
if (opts.framerate < 1) {
_this.framerate = 1
} else {
_this.framerate = Math.floor(opts.framerate)
}
console.warn('Framerate must be an integer greater than 0. It has been adjusted to the nearest non-zero whole number for you')
} else {
_this.framerate = opts.framerate
}
} else {
_this.framerate = createjs.Ticker.framerate
}
// If there's a placeholder shape make it invisible right away.
if (_this.container.shape) {
_this.container.shape.visible = false
_this.container.shape.alpha = 0
}
// Checks if blink is available. If it is, attach baseUrl
var baseUrl = ''
if (typeof window.$b === 'object') {
baseUrl = window.$b.baseUrl
}
var root = opts.root === '' ? '' : opts.root || baseUrl || ''
// Create simple image manifest to be loaded.
_this.manifest = [{ src: root + _this.spritesheet }]
// setupSprite Function: Sets up sprite after spritesheet is loaded and sprite is created
// ============================================================================================================================
_this.setupSprite = function () {
// Resize sprite to match container size.
_this.sprite.scaleX = _this.container.nominalBounds.width / _this.sprite.spriteSheet._frames[0].rect.width
_this.sprite.scaleY = _this.container.nominalBounds.height / _this.sprite.spriteSheet._frames[0].rect.height
// Add sprite to container
_this.container.addChild(_this.sprite)
// Set Framerate of Animation Sequence
_this.sprite.framerate = _this.framerate
_this.sprite.loop = _this.loop
// Start Autoplay (if Set)
if (_this.autoplay === true) {
_this.sprite.gotoAndPlay(0)
}
// handle animationend
// True: Do nothing (looping is the default behavior).
// False: Stop the animation when it ends.
_this.sprite.addEventListener('animationend', function () {
if (_this.sprite.loop === false) {
_this.sprite.gotoAndStop(_this.sprite.length - 1)
}
})
_this.play = function () {
var nextFrame = _this.sprite.currentFrame === _this.sprite.length - 1 ? 0 : _this.sprite.currentFrame + 1
_this.sprite.gotoAndPlay(nextFrame)
}
_this.pause = function () {
_this.sprite.stop()
}
}
// ============================================================================================================================
// setupSpritesheet Function: Once image has been loaded, create a sprite and start parsing json to generate individual frames.
// ============================================================================================================================
_this.setupSpritesheet = function () {
var frames = []
_this.json.frames.forEach(function (item, index) {
var slot = item.frame
var frame = [slot.x, slot.y, slot.w, slot.h]
frames.push(frame)
})
var data = {
images: [_this._loadedImage],
frames: frames
}
var _spritesheet = new createjs.SpriteSheet(data)
_this.sprite = new createjs.Sprite(_spritesheet, 0)
_this.sprite.gotoAndStop(0)
_this.sprite.length = frames.length
_this.setupSprite()
}
// ============================================================================================================================
// handleFileLoad Function
// ============================================================================================================================
_this.handleFileLoad = function (evt) {
var item = evt.item
var type = item.type
if (type === createjs.LoadQueue.IMAGE) {
_this._loadedImage = evt.result
}
}
// ============================================================================================================================
// handleComplete Function
// ============================================================================================================================
_this.handleComplete = function (evt) {
if (_this.failed === false) {
_this.setupSpritesheet()
_this.loaded = true
window.$b.emit(completeEvent, evt, _this)
}
}
// ============================================================================================================================
// handleProgress Function
// ============================================================================================================================
_this.handleProgress = function (evt) {
window.$b.emit(progressEvent, evt)
}
// ============================================================================================================================
// handleError Function
// ============================================================================================================================
_this.handleError = function (err) {
_this.failed = true
// This is called only if the error has to do with the spritesheet loading. JSON errors are handled in the Ajax.fail() function
if (err.title) {
var errorEvent = eventLabel + '-ANIMATION_SEQUENCE_SPRITESHEET_ERROR'
console.log(errorEvent, err.title)
try {
window.$b.emit(errorEvent, err.title)
} catch (err) {
console.log(err)
}
}
}
// ============================================================================================================================
// Begin Loading Sprite Sheet
// ============================================================================================================================
_this.load = function () {
if (_this.loaded === false) {
$.ajax({
url: root + jsonFilename,
crossDomain: true,
dataType: 'json',
timeout: 30000
})
.fail(function (err) {
var errorEvent = eventLabel + '-ANIMATION_SEQUENCE_JSON_ERROR'
console.log(errorEvent, err.statusText)
try {
window.$b.emit(errorEvent, err.statusText)
_this.handleError(err)
} catch (err) {
console.log(err)
}
})
.done(function (data) {
_this.json = data
_this.queue = new createjs.LoadQueue(true, root)
_this.queue.loadManifest(_this.manifest)
_this.queue.on('error', _this.handleError, this)
_this.queue.on('fileload', _this.handleFileLoad, this)
_this.queue.on('complete', _this.handleComplete, this)
_this.queue.on('progress', _this.handleProgress, this)
})
}
}
// ============================================================================================================================
return _this
} // END - function createGifPlayer(opts)
window.$b = window.$b || {}
window.$b.snippets = window.$b.snippets || {}
var snippets = window.$b.snippets
snippets.animationSequence = animationSequence