/**
* @function scrollableMovieClip
* @summary
* Add a drag handler to a movie clip, so it appears scrollable by mouse and touch events.
* @description
* The mousewheel also scrolls the movie clip on all desktop browsers except Microsoft Edge.
*
* The scrollable movie clip's endpoints for movement are the most inward of either:
* 1. the edge of the initial position of the scrollable movie clip, or
* 2. the edge of the mask
*
* You must include the Initialize Gestures and Constrained Drag snippets in your FLA.
*
* Required Parameters:
* * draggable the Movie Clip instance to be made scrollable
*
* Optional Parameters:
* * clickableArray
* * is an optional array of MovieClips that will be repositioned as the draggable is scrolled.
* * You need to add the event handlers outside of this snippet, to handle actions (clicks, mouseover,
* mouseleave, etc) on the clickables.
* * The clickables must in a layer or layers LOWER than the draggable.
* * If the goal is to make certain regions of an image clickable, then the clickables can simply be movie clips
* that contain a rectangle. The rectangle can have an alpha of 0.
*
* * mask
* * If mask is specified, this Movie Clip will be used to create a mask.
* * The mask Movie Clip will be made transparent, so you can use any color you want in the Animate CC editor.
* * The mask is also used to create a shape under the draggable which will capture clicks and not transmit the
* click events to lower layers.
*
* * margin
* * If options.margin is provided, additional padding will be added (or subtracted if negative)
* from the scrolling boundaries.
* * The units of the margin are those of the parent MovieClip.
* * If the margins cause the current position of the draggable to be outside the boundaries,
* it will be immediately positioned to the closest edge.
*
* * dragUpdate
* function will be called at each dragUpdate and passed an object with a key "fraction"
*
* Requires snippets:
* * Initialize Gestures
* * Constrained Drag
* * Get Movie Clip Bounds (if there is a ClickableArray)
* * Point In Bounds (if there is a ClickableArray)
*
* Returns
* ```
* {
* removeEventHandlers<function>,
* restoreEventHandlers<function>,
* moveToFraction<function({fraction: number}>,
* moveByDelta<function({deltaX: number, deltaY: number}>,
* startAutoScroll<function>,
* stopAutoScroll<function>
* }
* ```
* The function moveToFraction allows the position of the draggable to be easily changed outside this snippet.
*
* @param {createjs.MovieClip} options.draggable
* @param {createjs.MovieClip=} options.mask optional
* @param {boolean=} options.doVerticalScroll optional, defaults to false
* @param {Array<createjs.MovieClip>=} options.clickableArray optional
* @param {number=} clickMsAfterDrag options.clickMsAfterDrag
* optional value for number of milliseconds that activates a click after a drag (default = 200)
* @param {Object<number, number, number, number>=} options.margin
* optional values for added inward margin (can be negative) in units of the
* parent of the draggable
* @param {number} options.margin.left left margin
* @param {number} options.margin.right right margin
* @param {number} options.margin.top top margin
* @param {number} options.margin.bottom bottom margin
* @param {number=} options.mouseWheelSpeed defaults to 1.0 (100% of actual speed)
* @param {number=} options.releaseTolerance passed to constrained drag snippet, default = 0
* @param {function=} options.dragUpdate Optional function called at each drag update
* See constrained drag snippet for details.
* @param {function=} options.dragEnd Optional function called at the end of the drag
* See constrained drag snippet for details.
* @param {number=} options.clickMsAfterDrag (default 200) Number of milliseconds to wait before a click event will be
* forwarded an item in the ClickableArray. If this value is zero, every drag will send a click.
* @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.
* @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 {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 {boolean=} options.loop (default false) if true, draggable will loop back to the other end when it reaches either edge
*
* @returns {Object} same object as returned from constrained drag + moveToFraction
*/
function scrollableMovieClip (options) {
var addConstrainedDrag = snippets.addConstrainedDrag
if (typeof addConstrainedDrag !== 'function') {
console.error('Scrollable Movie Clip snippet requires Constrained Drag snippet')
return
}
var scrollableOptions = options
var doVerticalScroll = !!options.doVerticalScroll
console.log('doVerticalScroll = ', doVerticalScroll)
var draggable = options.draggable
var mask = options.mask
var doLogging = !!options.doLogging
if (!(draggable instanceof createjs.MovieClip)) {
console.error('scrollableMovieClip must be passed options.draggable')
return
}
var forceDragRelease = !(options.forceDragRelease === false)
// var allowDraggableClick = !(options.allowDraggableClick === false)
var margin = options.margin || {}
margin = Object.assign({ left: 0, right: 0, bottom: 0, top: 0 }, margin)
var optionalCallback = typeof options.dragUpdate === 'function'
? options.dragUpdate : null
var clickableArray = options.clickableArray || []
var clickMsAfterDrag = parseInt(options.clickMsAfterDrag)
clickMsAfterDrag = isNaN(clickMsAfterDrag) ? 200 : clickMsAfterDrag
clickableArray = clickableArray.filter(function (item) {
return (item instanceof createjs.MovieClip)
})
/*
* These 3 snippets are also required if a clickableArray is used
*/
var getMovieClipBounds = snippets.getMovieClipBounds
var pointInBounds = snippets.pointInBounds
if (clickableArray.length) {
if (typeof pointInBounds !== 'function') {
console.error('Scrollable Movie Clip snippet requires snippet Point In Bounds')
return
}
if (typeof getMovieClipBounds !== 'function') {
console.error('Scrollable Movie Clip snippet requires snippet Get MovieClip Bounds')
return
}
}
var allowDraggableClick = !!clickableArray.length
var contentArray = [draggable].concat(clickableArray)
var useMask = mask instanceof createjs.MovieClip
var isNumber = function (x) {
return typeof x === 'number'
}
var mouseWheelSpeed = isNumber(options.mouseWheelSpeed) ? options.mouseWheelSpeed : 1.0
mouseWheelSpeed = Math.min(mouseWheelSpeed, 1)
mouseWheelSpeed = Math.max(mouseWheelSpeed, 0)
var releaseTolerance = isNumber(options.releaseTolerance) ? options.releaseTolerance : 0.0
releaseTolerance = Math.min(releaseTolerance, 1)
releaseTolerance = Math.max(releaseTolerance, 0)
var loop = options.loop === true
clickableArray.forEach(function (clickable) {
clickable.draggableOffset = {
x: clickable.x - draggable.x,
y: clickable.y - draggable.y
}
})
var updateClickableArray = function () {
clickableArray.forEach(function (clickable) {
clickable.x = draggable.x + clickable.draggableOffset.x
clickable.y = draggable.y + clickable.draggableOffset.y
})
}
/*
* This wrapper function ensures the clickable MovieClip array is moved in sync
* with the draggable.
*/
var dragUpdateTime = new Date()
var dragUpdate = function (options) {
/*
* The dragUpdateTime is used to determine if a drag event should activate a click handler,
* for the option clickMsAfterDrag.
*/
if (!isAutoScrolling) {
dragUpdateTime = new Date()
}
optionalCallback && optionalCallback(options)
updateClickableArray()
}
var container = draggable.parent
var x0, x1, y0, y1
var containerX0, containerX1, containerY0, containerY1
var draggableUpperLeft = draggable.localToLocal(
draggable.nominalBounds.x,
draggable.nominalBounds.y,
container
)
var draggableLowerRight = draggable.localToLocal(
(draggable.nominalBounds.x + draggable.nominalBounds.width),
(draggable.nominalBounds.y + draggable.nominalBounds.height),
container
)
if (doLogging) {
console.log('draggable upper left: ', draggableUpperLeft)
console.log('draggable lower right: ', draggableLowerRight)
}
/*
* Autocalculate the Constrained Drag Line Endpoints.
*
* For horizontal scrolling:
* containerX0 = location of left edge of draggable
* containerX1 = location of right edge of draggable
* For vertical scrolling:
* containerY0 = location of top edge of draggable
* containerY1 = location of bottom edge of draggable
*/
if (useMask) {
/*
* Create a new shape to intercept clicks and add under the draggable
*/
var clickableShape = createMaskShape({ maskMC: mask, container: container, color: '#000000' })
var clickableHitArea = createMaskShape({ maskMC: mask, container: container, color: '#000000' })
clickableHitArea.x = 0
clickableHitArea.y = 0
clickableHitArea.alpha = 1
clickableShape.hitArea = clickableHitArea
clickableShape._off = false
/*
* The array container.children is not populated until each object's tween has completed
*/
setTimeout(function () {
var draggableIndex = container.getChildIndex(draggable)
container.addChildAt(clickableShape, draggableIndex)
}, 100)
clickableShape.on('click', function (evt) {
evt.preventDefault()
})
/*
* Use the mask movie clip's nominal bounds to create a mask shape and add to each item
* in the contentArray.
*/
convertToMask({
maskMC: mask,
maskableArray: contentArray
})
var maskUpperLeft = mask.localToLocal(
mask.nominalBounds.x,
mask.nominalBounds.y,
container
)
var maskLowerRight = mask.localToLocal(
(mask.nominalBounds.x + mask.nominalBounds.width),
(mask.nominalBounds.y + mask.nominalBounds.height),
container
)
if (doLogging) {
console.log('mask upper left: ', maskUpperLeft)
console.log('mask lower right: ', maskLowerRight)
}
containerX0 = Math.min(maskLowerRight.x, draggableLowerRight.x)
containerX1 = Math.max(maskUpperLeft.x, draggableUpperLeft.x)
containerY0 = Math.max(maskUpperLeft.y, draggableUpperLeft.y)
containerY1 = Math.min(maskLowerRight.y, draggableLowerRight.y)
} else {
containerX0 = draggableLowerRight.x
containerX1 = draggableUpperLeft.x
containerY0 = draggableUpperLeft.y
containerY1 = draggableLowerRight.y
var containerUpperLeft = {
x: container.nominalBounds.x,
y: container.nominalBounds.y
}
var containerLowerRight = {
x: container.nominalBounds.x + container.nominalBounds.width,
y: container.nominalBounds.y + container.nominalBounds.height
}
if (doLogging) {
console.log('container upper left: ', containerUpperLeft)
console.log('container lower right: ', containerLowerRight)
}
containerX0 = Math.max(containerLowerRight.x, draggableLowerRight.x)
containerX1 = Math.min(containerUpperLeft.x, draggableUpperLeft.x)
containerY0 = Math.min(containerUpperLeft.y, draggableUpperLeft.y)
containerY1 = Math.max(containerLowerRight.y, draggableLowerRight.y)
}
/*
* Use the scaled nominalBounds coordinates to account for an arbitrary registration point.
*
* Subtract the scaled width or height to keep the far edge of the draggable
* within the boundaries.
*
* If draggable is the same size as the container, add epsilon so addContrainedDrag uses right direction
*/
if (doVerticalScroll) {
y0 = containerY0 - draggable.nominalBounds.y * draggable.scaleY +
margin.top
y1 = containerY1 - (draggable.nominalBounds.height + draggable.nominalBounds.y) * draggable.scaleY -
margin.bottom
y1 = y0 === y1 ? y1 + 1.e-6 : y1
x0 = draggable.x
x1 = x0
} else {
x0 = containerX0 - (draggable.nominalBounds.width + draggable.nominalBounds.x) * draggable.scaleX -
margin.right
x1 = containerX1 - draggable.nominalBounds.x * draggable.scaleX +
margin.left
x1 = x0 === x1 ? x1 + 1.e-6 : x1
y0 = draggable.y
y1 = y0
}
var dragReturn = addConstrainedDrag(Object.assign(options, {
draggable: draggable,
line: {
a: { x: x0, y: y0 },
b: { x: x1, y: y1 }
},
dragUpdate: dragUpdate,
dragEnd: options.dragEnd,
// updateClickableArray: updateClickableArray,
forceDragRelease: forceDragRelease,
allowDraggableClick: allowDraggableClick,
mouseWheelSpeed: mouseWheelSpeed,
releaseTolerance: releaseTolerance,
naturalScrolling: true,
loop: loop,
doLogging: doLogging
}))
var baseMoveToFraction = dragReturn.moveToFraction
/*
* The snippet scrollbar-movie-clip, passes in a callback function moveToFractionCallback and
* moveByDeltaCallback, so the scroll bar moves in sync with the scrollable
*/
var moveToFraction = function (options) {
var deltaObj = baseMoveToFraction(options)
updateClickableArray()
scrollableOptions.moveToFractionCallback && scrollableOptions.moveToFractionCallback(options)
return deltaObj
}
var baseMoveByDelta = dragReturn.moveByDelta
var moveByDelta = function (options) {
var deltaObj = baseMoveByDelta(options)
updateClickableArray()
scrollableOptions.moveByDeltaCallback && scrollableOptions.moveByDeltaCallback()
return deltaObj
}
dragReturn.moveToFraction = moveToFraction
dragReturn.moveByDelta = moveByDelta
dragReturn.startAutoScroll = startAutoScroll
dragReturn.stopAutoScroll = stopAutoScroll
dragReturn.restartAutoScroll = restartAutoScroll
/*
* Forward click event on draggable to item in clickableArray
*/
if (clickableArray.length) {
/*
* The bounds of each clickable movie clip is used to determine if the event should dispatched.
*/
var boundsArray = clickableArray.map(function (clickable) {
/*
* The target coordinate system is the parent parameter in getMousePoint
*/
return getMovieClipBounds({ movieClip: clickable, target: draggable })
})
/*
* Store a reference to all children of the clickableArray, to filter for the proper target of
* a click event outside the mask.
*/
var clickableChildren = [draggable]
var addChildren = function (parent) {
if (!parent.children) return
parent.children.forEach(function (child) {
clickableChildren.push(child)
addChildren(child)
})
}
/*
* Wait for children to be added to the parents
*/
setTimeout(function () {
clickableArray.forEach(function (clickable) {
addChildren(clickable)
})
// doLogging && console.log(clickableChildren)
}, 100)
/*
* CreateJS activates a click event at the end of drag on the mouseUp event. The distance between the mouseup and
* mousedown event is used to determine if the click event was a regular click or a drag mouseup.
*/
var lastMouseDownEvent = null
draggable.on('mousedown', function (evt) {
lastMouseDownEvent = evt
})
draggable.on('click', function (evt) {
evt.stopPropagation()
evt.preventDefault()
var eventDispatched = false
var mousePoint = dragReturn.getMousePoint({ event: evt, parent: draggable })
var maskBounds
var pointInMask
if (mask) {
maskBounds = getMovieClipBounds({ movieClip: mask, target: draggable })
pointInMask = pointInBounds({ pt: mousePoint, bounds: maskBounds })
} else {
/*
* If there is no mask, every click on the draggable is valid.
*/
pointInMask = true
}
/*
* The deltaTime filters drag events from activating a click handler unintentionally.
*/
if (pointInMask) {
var deltaTime = new Date() - dragUpdateTime
if (deltaTime > clickMsAfterDrag) {
var boundsFound = boundsArray.find(function (element) {
return pointInBounds({ pt: mousePoint, bounds: element })
})
if (boundsFound) {
var index = boundsArray.indexOf(boundsFound)
// console.log('index = ', index)
clickableArray[index].dispatchEvent(evt)
eventDispatched = true
}
}
} else {
doLogging && console.log('click point not within mask')
}
/*
* Since the draggable can be larger than the mask, it might intercept click events intended
* for underlying elements. Dispatch the event to the highest element with a click handler that
* is not in the clickableArray.
*/
if (!eventDispatched && !pointInMask && lastMouseDownEvent) {
/*
* Ignore the event if it was the duplicate click event sent after a drag.
*/
var dx = evt.stageX - lastMouseDownEvent.stageX
var dy = evt.stageY - lastMouseDownEvent.stageY
var dist = Math.sqrt(dx * dx + dy * dy)
/*
* Arbitrary distance of 10 pixels indicates it was not a simple click.
*/
if (dist > 10) {
console.log('Event was a drag and not a click')
return
}
var x = evt.stageX / window.$b.stage.scaleX
var y = evt.stageY / window.$b.stage.scaleY
var objs = window.$b.stage.getObjectsUnderPoint(x, y)
objs.shift()
var obj
while (objs.length) {
obj = objs.shift()
if (obj.hasEventListener('click')) {
if (clickableChildren.indexOf(obj) < 0) {
doLogging && console.log('dispatch event to:', obj)
obj.dispatchEvent(evt)
evt.stopPropagation()
break
}
}
}
}
})
}
var waitTimeToRestartAutoScrollMs = isNumber(options.waitTimeToRestartAutoScrollMs) ? options.waitTimeToRestartAutoScrollMs : 2000
var autoScrollIntervalMs = isNumber(options.autoScrollIntervalMs) ? options.autoScrollIntervalMs : 100
var startAutoScrollDelayMs = isNumber(options.startAutoScrollDelayMs) ? options.startAutoScrollDelayMs : 0
var autoScrollDx = 0
var autoScrollDy = 0
/*
* If autoScroll Dx or Dy is not specified, choose value so that endFraction is farther away than startFraction
*/
var startFraction = dragReturn.getFraction()
if (doVerticalScroll) {
// autoScrollDy = isNumber(options.autoScrollDy) ? options.autoScrollDy : 1
if (isNumber(options.autoScrollDy)) {
autoScrollDy = options.autoScrollDy
} else {
autoScrollDy = startFraction > 0.5 ? 1 : -1
}
} else {
// autoScrollDx = isNumber(options.autoScrollDx) ? options.autoScrollDx : 1
if (isNumber(options.autoScrollDx)) {
autoScrollDx = options.autoScrollDx
} else {
autoScrollDx = startFraction < 0.5 ? 1 : -1
}
}
var isAutoScrolling = false
var autoScrollWasStarted = false
var cancelAutoScroll = false
var restartAutoScrollTimerId
var intervalId = null
var endFraction
if (isNumber(options.endFraction)) {
endFraction = options.endFraction
} else {
if (doVerticalScroll) {
endFraction = autoScrollDy > 0 ? 0 : 1
} else {
endFraction = autoScrollDx < 0 ? 0 : 1
}
}
if (isNumber(options.startFraction)) {
startFraction = options.startFraction
} else {
startFraction = 1 - endFraction
}
/*
* Since original options object is used inside this function, use a new variable name for the input options.
*/
function startAutoScroll (startAutoScrollOptions) {
autoScrollWasStarted = true
startAutoScrollOptions = typeof startAutoScrollOptions === 'object' ? startAutoScrollOptions : {}
cancelAutoScroll = false
if (isAutoScrolling) return
var lastFraction = dragReturn.getFraction()
isAutoScrolling = true
var lastTimeStamp = 0
/*
* Using requestAnimationFrame instead of a setTimeout or setInterval, allows the maximum frame rate
* that the browser can deliver. This wrapper function returns if the next animation frame is less than
* the autoScrollInterval.
*/
var animationWrapper = function (timeStamp) {
if (cancelAutoScroll) return
intervalId = requestAnimationFrame(animationWrapper)
if (!timeStamp || (timeStamp - lastTimeStamp < autoScrollIntervalMs)) return
lastTimeStamp = timeStamp
moveDrag()
}
var moveDrag = function () {
var newFraction = dragReturn.getFraction()
// console.log('fraction: ', newFraction)
if (newFraction !== lastFraction) {
lastFraction = newFraction
window.cancelAnimationFrame(intervalId)
intervalId = null
isAutoScrolling = false
restartAutoScroll()
} else {
if (((endFraction === 0) && (newFraction > 0)) || ((endFraction === 1) && (newFraction < 1))) {
moveByDelta({ dx: autoScrollDx, dy: autoScrollDy })
} else {
loop && moveToFraction({ fraction: startFraction })
}
lastFraction = dragReturn.getFraction()
}
}
if (!isNumber(startAutoScrollDelayMs) || startAutoScrollOptions.delay === false) {
animationWrapper(null)
} else {
setTimeout(function () {
animationWrapper(null)
}, startAutoScrollDelayMs)
}
}
function stopAutoScroll () {
cancelAutoScroll = true
if (intervalId) {
// window.clearInterval(intervalId)
window.cancelAnimationFrame(intervalId)
intervalId = null
}
isAutoScrolling = false
}
function restartAutoScroll (options) {
if (cancelAutoScroll && !options.overrideCancel) return
if (!autoScrollWasStarted) return
if (restartAutoScrollTimerId) {
window.clearTimeout(restartAutoScrollTimerId)
}
restartAutoScrollTimerId = setTimeout(function () {
restartAutoScrollTimerId = null
startAutoScroll({ delay: false })
}, waitTimeToRestartAutoScrollMs)
}
return dragReturn
}
/**
* @function convertToMask
* @summary
* Use a mask movie clip to create a mask shape and add that to the contents movieClip.
* @description
* Typically, all maskableMovieClips will have the same parent, so they can be masked with
* the same object.
*
* @param options.maskMC {createjs.MovieClip} Movie Clip to use as a template for a mask
* @param options.maskableArray {Array<createjs.MovieClip>} Array of MovieClips to be masked
*/
function convertToMask (options) {
var maskMC = options.maskMC
if (!(maskMC instanceof createjs.MovieClip)) {
console.error('convertToMask must be passed a Movie Cip options.maskMC')
}
var maskableArray = options.maskableArray || []
maskableArray = maskableArray.filter(function (item) {
return item instanceof createjs.MovieClip
})
if (!maskableArray.length) {
console.error('convertToMask must be passed an array of Movie Clips to be masked options.maskableArray')
return
}
var container = maskableArray[0].parent
/*
* If all the maskables have the same parent, this mask will be used for all of them
*/
var mask = createMaskShape({
maskMC: maskMC,
container: container
})
maskMC.visible = false
if (maskableArray && maskableArray.length) {
maskableArray.forEach(function (maskable) {
/*
* Only create a separate mask shape if it is different than the first one
*/
if (maskable.parent !== container) {
maskable.mask = createMaskShape({
maskMC: maskMC,
container: maskable.parent
})
} else {
maskable.mask = mask
}
})
}
}
/**
* @function createMaskShape
* @summary
* Create and return a shape from a Movie Clip in coordinates of the container.
* @description
* Used by function convertToMask or can also be used independently
* Returned shape has alpha set to zero
*
* @param {Object} options
* @param {createjs.MovieClip} options.maskMC Movie Clip to use as a template for the mask.
* @param {createjs.MovieClip} options.container Container of the Movie Clip to be masked.
* @param options.color {String=} optional hex color, ex #000000
* @returns {createjs.Shape}
*/
function createMaskShape (options) {
var maskMC = options.maskMC
var container = options.container
var color = options.color || '#00ff00'
var width = maskMC.nominalBounds.width * maskMC.scaleX
var height = maskMC.nominalBounds.height * maskMC.scaleY
var mask = new window.createjs.Shape()
mask
.graphics
.beginFill(color)
.drawRect(0, 0, width, height)
mask._off = true
mask.alpha = 0
/*
* The offset accounts for an abitrary registration point.
* Use the unscaled coordinates, since localToLocal takes scaling into account.
*/
var maskX = maskMC.nominalBounds.x
var maskY = maskMC.nominalBounds.y
var offset = maskMC.localToLocal(maskX, maskY, container)
mask.x = offset.x
mask.y = offset.y
// console.log('mask x,y: ', mask.x, mask.y)
return mask
}
/**
* @function useMovieClipAsHitArea
* @summary
* Create a hitArea on the targetMovieClip based on the current relative coordinates of the hitAreaMovieClip
*
* @param {Object} options
* @param {createjs.MovieClip} options.targetMovieClip Movie Clip to add a hitArea to
* @param {createjs.MovieClip} options.hitAreaMovieClip Movie Clip to base the hitArea on
*/
function useMovieClipAsHitArea (options) {
var targetMovieClip = options.targetMovieClip
var hitAreaMovieClip = options.hitAreaMovieClip
if (!(targetMovieClip instanceof createjs.MovieClip)) {
console.error('useMovieClipAsHitArea must be passed options.targetMovieClip')
return
}
if (!(hitAreaMovieClip instanceof createjs.MovieClip)) {
console.error('useMovieClipAsHitArea must be passed options.hitAreaMovieClip')
return
}
var nb = hitAreaMovieClip.nominalBounds
var upperLeft = hitAreaMovieClip.localToLocal(nb.x, nb.y, targetMovieClip)
var lowerRight = hitAreaMovieClip.localToLocal(nb.x + nb.width, nb.y + nb.height, targetMovieClip)
var hitArea = new window.createjs.Shape()
hitArea
.graphics
.beginFill('#000')
.drawRect(upperLeft.x, upperLeft.y, lowerRight.x, lowerRight.y)
targetMovieClip.hitArea = hitArea
targetMovieClip.mouseChildren = false
return ({ upperLeft: upperLeft, lowerRight: lowerRight })
}
window.$b = window.$b || {}
window.$b.snippets = window.$b.snippets || {}
var snippets = window.$b.snippets
snippets.scrollableMovieClip = scrollableMovieClip
snippets.convertToMask = convertToMask
snippets.createMaskShape = createMaskShape
snippets.useMovieClipAsHitArea = useMovieClipAsHitArea