/**
* @function scrollBarMovieClip
* @summary
* Make a movie clip touch/drag scrollable and connect to a scroll bar.
* @description
* Required parameters:
* * options.draggable Movie Clip to be made scrollable
* * options.scrollBarContainer Movie Clip for the scroll bar
* * options.scrollBarKnob Movie Clip for the scroll knob which is a child of scrollBarContainer
*
* Optional parameters:
* * options.mask optional Movie Clip to use as a mask for draggable
* this is the display area of the scrollable movie clip, so it should always be passed in
* * options.clickableArray optional array of Movie Clips
* * options.doVerticalScroll defaults to true
* * options.dragUpdate function called after each drag update
* * options.dragEnd function called at end of each drag
*
* Requires snippets:
* * Initialize Gestures
* * Constrained Drag
* * Scrollable Movie Clip
* * Get Movie Clip Bounds (if there is a ClickableArray)
* * Point In Bounds (if there is a ClickableArray)
*
* @param {Object} options
* @param {createjs.MovieClip} options.draggable Movie Clip to be made scrollable
* @param {createjs.MovieClip} options.scrollBarContainer Movie Clip parent of the scroll knob
* @param {createjs.MovieClip} options.scrollBarKnob Movie Clip of the scroll bar knob (aka thumb)
* @param {createjs.MovieClip=} options.mask optional Movie Clip to use as a mask for draggble
* @param {Array=} options.clickableArray optional array of Movie Clips
* @param {boolean=} options.doVerticalScroll defaults to true
* @param {number=} options.autoScrollIntervalMs (default 100) Number of milliseconds that autoScroll is repeated
* @param {number=} options.waitTimeToRestartAutoScrollMs (default 2000) Number of milliseconds to automatically restart
* autoscroll after the user interacts (manually moves) the draggable
* @param {number=} options.startAutoScrollDelayMs (default 0) After calling startAutoScroll, the first movement is not
* until after startAutoScrollDelayMs. The same delay time applies to automatic restarting of autoscroll,
* and restarting of autoScroll after the scrollBarContainer is clicked inside.
* @param {number=} options.autoScrollDx (default 1) Number of pixels to move a horizontal scrollable per autoScroll.
* Positive values move the scrollable to the right.
* @param {number=} options.autoScrollDy (default 1) Number of pixels to move a vertical scrollable per autoScroll
* Positive values move the scrollable downward. Most ads with scrollable text will use negative Dy.
* @param {boolean=} options.loop defaults to false
* @param {number=} options.startFraction (default auto calculated) Position draggable will be reset after auto scroll loop
* @param {number=} options.endFraction (default auto calculated) Position at which draggable loops in auto scroll
* @param {function=} options.dragUpdate function called after each drag update
* @param {function=} options.dragEnd function called at end of each drag
* @returns {{scrollBarReturn: *, scrollableReturn: *, moveToFraction: moveToFraction, moveByDelta: moveByDelta}}
*/
function scrollBarMovieClip (options) {
var scrollableMovieClip = snippets.scrollableMovieClip
if (!scrollableMovieClip) {
console.error('Scrollbar Movie Clip snippet requires Scrollable Movie Clip snippet')
return
}
if (typeof options !== 'object') {
console.error('Scrollbar Movie Clip must be passed an object as the function parameter')
return
}
if (!(options.scrollBarContainer instanceof window.createjs.MovieClip)) {
console.error('Scrollbar Movie Clip must be passed options.scrollBarContainer')
return
}
if (!(options.scrollBarKnob instanceof window.createjs.MovieClip)) {
console.error('Scrollbar Movie Clip must be passed options.scrollBarKnob')
return
}
var dragUpdate = typeof options.dragUpdate === 'function' ? options.dragUpdate : null
var dragEnd = typeof options.dragEnd === 'function' ? options.dragEnd : null
var scrollBarKnob = options.scrollBarKnob
var scrollBarContainer = options.scrollBarContainer
var loop = options.loop === true
/*
* Clone options in case the user passes the same object, to prevent assignment of
* forceDragRelease = false to the scrollable
*/
var scrollBarOptions = typeof options.scrollBarOptions === 'object'
? Object.assign({}, options.scrollBarOptions) : {}
var scrollableOptions = typeof options.scrollableOptions === 'object'
? Object.assign({}, options.scrollableOptions) : {}
/*
* The scrollBarKnob is added to the scrollBarContainer in a Tween, so wait for before testing
*/
setTimeout(function () {
if (scrollBarContainer.getChildIndex(scrollBarKnob) < 0) {
console.error('scrollBarKnob must be a child of scrollBarContainer')
}
}, 100)
var clickableArray = options.clickableArray instanceof Array ? options.clickableArray : []
/*
* Remove duplicate clickableArray in case it was added there by accident
*/
if (clickableArray.length) {
delete scrollBarOptions.clickableArray
delete scrollableOptions.clickableArray
}
/*
* Only the scrollable (not the scrollBar) can have loop set
*/
delete scrollBarOptions.loop
scrollableOptions.loop = loop
var doVerticalScroll = !(options.doVerticalScroll === false)
/*
* Placeholder function until scrollableReturn is available
*/
var scrollableMoveToFraction = function () {}
/*
* Note: when scrollBar is at fraction 1, scrollable is at fraction 0
*/
var scrollBarDragUpdate = function (callbackOptions) {
scrollableMoveToFraction({ fraction: 1 - callbackOptions.fraction })
dragUpdate && dragUpdate()
}
/*
* Allow clicking on the scrollKnob to propagate the event to the scrollBarContainer to
* update the scrolling position.
*
* Do not allow the scrollBar to be released until a mouseup.
*/
var scrollBarReturn = scrollableMovieClip(Object.assign(scrollBarOptions, {
draggable: options.scrollBarKnob,
doVerticalScroll: doVerticalScroll,
doLogging: options.doLogging,
forceDragRelease: false,
allowDraggableClick: true,
startFraction: options.startFraction,
endFraction: options.endFraction,
dragUpdate: scrollBarDragUpdate
}))
var scrollableDragUpdate = function (callbackOptions) {
scrollBarReturn.moveToFraction({ fraction: 1 - callbackOptions.fraction })
}
var moveToFractionCallback = function (options) {
scrollBarReturn.moveToFraction({ fraction: 1 - options.fraction })
}
var moveByDeltaCallback = function () {
var fraction = scrollableReturn.getFraction()
scrollBarReturn.moveToFraction({ fraction: 1 - fraction })
}
var scrollableReturn = scrollableMovieClip(Object.assign(scrollableOptions, {
draggable: options.draggable,
mask: options.mask,
doVerticalScroll: doVerticalScroll,
clickableArray: clickableArray,
allowDraggableClick: options.allowDraggableClick,
dragUpdate: scrollableDragUpdate,
dragEnd: dragEnd,
moveToFractionCallback: moveToFractionCallback,
moveByDeltaCallback: moveByDeltaCallback,
autoScrollIntervalMs: options.autoScrollIntervalMs,
startAutoScrollDelayMs: options.startAutoScrollDelayMs,
waitTimeToRestartAutoScrollMs: options.waitTimeToRestartAutoScrollMs,
autoScrollDx: options.autoScrollDx,
autoScrollDy: options.autoScrollDy,
doLogging: options.doLogging
}))
scrollableMoveToFraction = scrollableReturn.moveToFraction
var initialFraction = scrollableReturn.getFraction()
scrollBarReturn.moveToFraction({ fraction: 1 - initialFraction })
/*
* Function returned to user to allow arbitrary position change.
*/
var moveToFraction = function (options) {
var deltaObj = scrollBarReturn.moveToFraction({ fraction: 1 - options.fraction })
// var deltaObj = scrollableReturn.moveToFraction(options)
return deltaObj
}
/*
* Function returned to user to allow arbitrary delta position change.
* Useful as an event handler on scrollBar arrows.
*/
var moveByDelta = function (options) {
var deltaObj = scrollableReturn.moveByDelta(options)
// var fraction = scrollableReturn.getFraction()
// scrollBarReturn.moveToFraction({ fraction: 1 - fraction })
return deltaObj
}
/*
* Update the scrollable position based on the click location in the scrollBarContainer,
* but do not propagate the event to lower layers.
*/
scrollBarContainer.on('click', function (evt) {
scrollableReturn.cancelInertia()
scrollBarReturn.cancelInertia()
scrollableReturn.stopAutoScroll()
var point = scrollBarReturn.getMousePoint({ event: evt, parent: scrollBarContainer })
var fraction = 1 - scrollBarReturn.getFractionAtPoint(point).fraction
scrollableReturn.moveToFraction({ fraction: fraction })
scrollableReturn.restartAutoScroll({ overrideCancel: true })
evt.preventDefault()
evt.stopPropagation()
})
return {
scrollBarReturn: scrollBarReturn,
scrollableReturn: scrollableReturn,
moveToFraction: moveToFraction,
moveByDelta: moveByDelta,
scrollableDragUpdate: scrollableDragUpdate,
startAutoScroll: scrollableReturn.startAutoScroll,
stopAutoScroll: scrollableReturn.stopAutoScroll,
restartAutoScroll: scrollableReturn.restartAutoScroll
}
}
if (window.module) {
window.module.scrollBarMovieClip = scrollBarMovieClip
}
window.$b = window.$b || {}
window.$b.snippets = window.$b.snippets || {}
var snippets = window.$b.snippets
snippets.scrollBarMovieClip = scrollBarMovieClip