famous-carousel
Advanced tools
Comparing version 0.9.14 to 1.0.0
@@ -59,3 +59,3 @@ "use strict"; | ||
carousel.pager.createPages(carousel.options); | ||
carousel.dots.createDots(carouselData.length); | ||
carousel.dots.createDots(carouselData.slides.length); | ||
@@ -104,5 +104,5 @@ _positionComponents(); | ||
if (carousel.options.initialIndex > carousel.options.carouselData.length - 1) { | ||
if (carousel.options.initialIndex > carousel.options.carouselData.slides.length - 1) { | ||
// Cap starting index to final page. | ||
carousel.options.initialIndex = carousel.options.carouselData.length - 1; | ||
carousel.options.initialIndex = carousel.options.carouselData.slides.length - 1; | ||
} | ||
@@ -120,3 +120,3 @@ | ||
parent: carousel.root, | ||
numPages: carousel.options.carouselData.length, | ||
numPages: carousel.options.carouselData.slides.length, | ||
initialIndex: carousel.options.initialIndex, | ||
@@ -182,3 +182,3 @@ width: carousel.options.dotWidth, | ||
var min = 0; | ||
var max = carousel.options.carouselData.length - 1; | ||
var max = carousel.options.carouselData.slides.length - 1; | ||
var floor = min; | ||
@@ -225,3 +225,3 @@ var ceiling = max; | ||
carousel.dots.pageChange(oldIndex, currentIndex); | ||
carousel.pager.pageChange(oldIndex, currentIndex); | ||
carousel.pager.pageChange(oldIndex, currentIndex, direction, payload.resumeFromCurrentPosition); | ||
} | ||
@@ -228,0 +228,0 @@ } |
@@ -16,6 +16,2 @@ "use strict"; | ||
var _PhysicsEngine = require("famous/physics/PhysicsEngine"); | ||
var _PhysicsEngine2 = _interopRequireDefault(_PhysicsEngine); | ||
var _FamousEngine = require("famous/core/FamousEngine"); | ||
@@ -29,19 +25,26 @@ | ||
var _physics = require("famous/physics"); | ||
var _PagerAlign = require("./PagerAlign"); | ||
var _physics2 = _interopRequireDefault(_physics); | ||
var PagerAlign = _interopRequireWildcard(_PagerAlign); | ||
var _math = require("famous/math"); | ||
var _PagerRotate = require("./PagerRotate"); | ||
var _math2 = _interopRequireDefault(_math); | ||
var PagerRotate = _interopRequireWildcard(_PagerRotate); | ||
var _PagerPosition = require("./PagerPosition"); | ||
var PagerPosition = _interopRequireWildcard(_PagerPosition); | ||
var _lodash = require("lodash.assign"); | ||
var _lodash2 = _interopRequireDefault(_lodash); | ||
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _instanceof(left, right) { if (right != null && right[Symbol.hasInstance]) { return right[Symbol.hasInstance](left); } else { return left instanceof right; } } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
var Box = _physics2.default.Box; | ||
var Spring = _physics2.default.Spring; | ||
var Vec3 = _math2.default.Vec3; | ||
var hideAngle = Math.PI / 2; | ||
var Pager = exports.Pager = (function () { | ||
@@ -59,5 +62,2 @@ function Pager(options) { | ||
// Add a physics simulation and update this instance using regular time updates from the clock. | ||
this.simulation = new _PhysicsEngine2.default(); | ||
var resizeComponent = { | ||
@@ -70,5 +70,2 @@ onSizeChange: function onSizeChange(x) { | ||
// .requestUpdate will call the .onUpdate method next frame, passing in the time stamp for that frame | ||
_FamousEngine2.default.requestUpdate(this); | ||
this.createPages(this.options); | ||
@@ -82,2 +79,4 @@ | ||
// Render animation frame by frame | ||
_createClass(Pager, [{ | ||
@@ -90,87 +89,210 @@ key: "onUpdate", | ||
this.simulation.update(time); | ||
var page; | ||
var physicsTransform; | ||
var p, r, xPos; | ||
for (var i = 0, len = this.pages.length; i < len; i++) { | ||
page = this.pages[i]; | ||
var transitionableXYZ; | ||
var xform; | ||
var requestUpdate = false; | ||
// Get the transform from the `Box` body | ||
physicsTransform = this.simulation.getTransform(page.box); | ||
p = physicsTransform.position; | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
// Set the `slide`s x-position to the `Box` body's x-position | ||
// Math.round is significantly faster than toFixed. | ||
xPos = Math.round(p[0] * this.pageWidth * 100) / 100; | ||
page.node.setPosition(xPos, 0, 0); | ||
try { | ||
for (var _iterator = this.pages[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var _page = _step.value; | ||
// Set the currently selected page's rotation to match the `Box` body's rotation | ||
if (i === this.currentIndex) { | ||
r = physicsTransform.rotation; | ||
page.node.setRotation(r[0], r[1], r[2], r[3]); | ||
//Fire user callback when sliding is done. | ||
if (Math.abs(xPos) === 0 && !page.animDoneCallbackFired) { | ||
page.animDoneCallbackFired = true; | ||
if (typeof this.options.animDoneCallback === "function") { | ||
this.options.animDoneCallback(page.node, i); | ||
if (_instanceof(_page.transitionable, Array) === false) { | ||
continue; | ||
} | ||
transitionableXYZ = []; | ||
for (var i = 0; i < _page.transitionable.length; i++) { | ||
if (_page.transitionable[i] && _page.transitionable[i].isActive()) { | ||
transitionableXYZ[i] = _page.transitionable[i].get(); | ||
} else { | ||
delete _page.currentTransform; | ||
} | ||
} | ||
} else { | ||
page.animDoneCallbackFired = false; | ||
if (transitionableXYZ.length > 0) { | ||
xform = this.selectPagerTransform(_page.currentTransform); | ||
xform.set(_page, transitionableXYZ); | ||
requestUpdate = true; | ||
} | ||
if (_page === this.pages[this.currentIndex] && transitionableXYZ.length === 0) { | ||
this.options.animDoneCallback(_page.node, this.currentIndex); | ||
} | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
_FamousEngine2.default.requestUpdateOnNextTick(this); | ||
if (requestUpdate) { | ||
_FamousEngine2.default.requestUpdateOnNextTick(this); | ||
} | ||
} | ||
// Calculate the position between matrices given percentage. | ||
}, { | ||
key: "pageChange", | ||
value: function pageChange(oldIndex, newIndex) { | ||
var xOffset; | ||
var reshuffle = false; | ||
var i; | ||
// Wrap-around cases shuffle pages to other side. | ||
if (oldIndex === this.pages.length - 1 && newIndex === 0) { | ||
xOffset = 1; | ||
reshuffle = true; | ||
} else if (oldIndex === 0 && newIndex === this.pages.length - 1) { | ||
xOffset = -1; | ||
reshuffle = true; | ||
key: "positionBetweenMatrices", | ||
value: function positionBetweenMatrices(startMatrix, endMatrix, percentage) { | ||
var result = []; | ||
var range; | ||
for (var i = 0; i < startMatrix.length; i++) { | ||
range = endMatrix[i] - startMatrix[i]; | ||
result[i] = range * percentage + startMatrix[i]; | ||
} | ||
return result; | ||
} | ||
if (reshuffle) { | ||
for (i = 0; i < this.pages.length; i++) { | ||
this.pages[i].anchor.set(xOffset, 0, 0); | ||
this.pages[i].node.setRotation(0, hideAngle, 0); | ||
} | ||
// Worker function that performs the slide positioning for dragging. | ||
// Similar to doTransition but enough differences to warrant a separate function. | ||
}, { | ||
key: "doDragPositioning", | ||
value: function doDragPositioning(slide, isForward, sequence, dragPercentage) { | ||
var transition; | ||
var startParams, endParams; | ||
var params; | ||
var xform; | ||
switch (sequence) { | ||
case "previous": | ||
transition = this.transitionForAction(slide, "exitTransition"); | ||
break; | ||
case "center": | ||
transition = this.transitionForAction(slide, "entryTransition"); | ||
break; | ||
case "next": | ||
default: | ||
return; | ||
} | ||
startParams = this.initialParamsForTransformType(slide, transition.transform); | ||
endParams = transition.transformParams; | ||
dragPercentage = 1 - dragPercentage; | ||
if (isForward) { | ||
// Swap start & end | ||
params = this.positionBetweenMatrices(endParams, startParams, dragPercentage); | ||
} else { | ||
// Non-wrapping cases | ||
xOffset = oldIndex < newIndex ? -1 : 1; | ||
this.pages[oldIndex].anchor.set(xOffset, 0, 0); | ||
this.pages[oldIndex].node.setRotation(0, hideAngle, 0); | ||
params = this.positionBetweenMatrices(startParams, endParams, dragPercentage); | ||
} | ||
xform = this.selectPagerTransform(transition.transform); | ||
slide.currentTransform = transition.transform; | ||
xform.set(slide, params); | ||
} | ||
}, { | ||
key: "restoreSlidePosition", | ||
value: function restoreSlidePosition(slide) { | ||
if (slide.currentTransform) { | ||
var xform = this.selectPagerTransform(slide.currentTransform); | ||
var startParams = xform.get(slide); | ||
var endParams = this.initialParamsForTransformType(slide, slide.currentTransform); | ||
xform.animate(slide, startParams, endParams); | ||
} | ||
} | ||
// Worker function that performs the slide animation for arrow navigation. | ||
}, { | ||
key: "doTransition", | ||
value: function doTransition(slide, isForward, sequence, resumeFromCurrentPosition) { | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, false); //Set to initial location (could be hidden) | ||
} | ||
var transition; | ||
var startParams, endParams; | ||
var xform; | ||
switch (sequence) { | ||
case "previous": | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, true); //Set to entry final location (this is where to start from). | ||
} | ||
transition = this.transitionForAction(slide, "exitTransition"); | ||
if (isForward) { | ||
//ToDo? merge initial with slide params | ||
startParams = this.initialParamsForTransformType(slide, transition.transform); | ||
endParams = transition.transformParams; | ||
} else { | ||
// Prep slide by moving to "previous" location (no animation) | ||
xform = this.selectPagerTransform(transition.transform); | ||
xform.set(slide, transition.transformParams); | ||
return; | ||
} | ||
break; | ||
case "center": | ||
if (isForward) { | ||
transition = this.transitionForAction(slide, "entryTransition"); | ||
startParams = this.initialParamsForTransformType(slide, transition.transform); | ||
endParams = transition.transformParams; | ||
} else { | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, true); //Set to entry final location (where it will end up). | ||
} | ||
// Reverse exitTransition | ||
transition = this.transitionForAction(slide, "exitTransition"); | ||
startParams = transition.transformParams; | ||
//ToDo? merge initial with slide params | ||
endParams = this.initialParamsForTransformType(slide, transition.transform); | ||
} | ||
break; | ||
case "next": | ||
if (isForward) { | ||
this.initSlideLocation(slide, false); //For resumeFromCurrentPosition | ||
return; // No-op for full transition | ||
} | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, true); //Set to entry final location (this is where to start from). | ||
} | ||
// Reverse entryTransition | ||
transition = this.transitionForAction(slide, "entryTransition"); | ||
startParams = transition.transformParams; | ||
//ToDo? merge initial with slide params | ||
endParams = this.initialParamsForTransformType(slide, transition.transform); | ||
break; | ||
} | ||
slide.currentTransform = transition.transform; | ||
slide.currentTransformOpts = { | ||
curve: transition.curve, | ||
duration: transition.duration | ||
}; | ||
xform = this.selectPagerTransform(transition.transform); | ||
if (resumeFromCurrentPosition) { | ||
startParams = xform.get(slide); | ||
} | ||
xform.animate(slide, startParams, endParams); | ||
} | ||
// Page change handler | ||
}, { | ||
key: "pageChange", | ||
value: function pageChange(oldIndex, newIndex, direction, resumeFromCurrentPosition) { | ||
var isForward = direction === 1; | ||
var visibleSlides = this.adjacentSlides(newIndex); | ||
var yRotation; | ||
for (i = 0; i < this.pages.length; i++) { | ||
yRotation = hideAngle; | ||
for (var i = 0; i < this.pages.length; i++) { | ||
for (var key in visibleSlides) { | ||
if (visibleSlides[key] === i) { | ||
yRotation = 0; | ||
switch (key) { | ||
case "left": | ||
xOffset = -1; | ||
break; | ||
case "center": | ||
xOffset = 0; | ||
break; | ||
case "right": | ||
xOffset = 1; | ||
break; | ||
} | ||
this.pages[i].anchor.set(xOffset, 0, 0); | ||
// key is previous, center, next | ||
this.doTransition(this.pages[i], isForward, key, resumeFromCurrentPosition); | ||
} | ||
} | ||
this.pages[i].node.setRotation(0, yRotation, 0); | ||
} | ||
@@ -180,21 +302,10 @@ | ||
// Callback hook for animation start | ||
if (typeof this.options.animStartCallback === "function") { | ||
this.options.animStartCallback(this.pages[this.currentIndex].node, this.currentIndex); | ||
} | ||
_FamousEngine2.default.requestUpdateOnNextTick(this); | ||
} | ||
}, { | ||
key: "removePages", | ||
value: function removePages() { | ||
for (var i = 0; i < this.pages.length; i++) { | ||
//DOMElement bug https://github.com/Famous/engine/issues/245 | ||
if (this.pages[i].el) { | ||
this.pages[i].el.setProperty("display", "none"); | ||
} | ||
this.pages[i].node.dismount(); | ||
this.options.parent.removeChild(this.pages[i].node); | ||
delete this.pages[i].node; | ||
} | ||
delete this.pages; | ||
} | ||
}, { | ||
key: "createPages", | ||
@@ -204,17 +315,17 @@ value: function createPages(options) { | ||
for (var i = 0; i < options.carouselData.length; i++) { | ||
var slide, el; | ||
var backgroundSize = options.carouselData[i].backgroundSize; | ||
for (var i = 0; i < options.carouselData.slides.length; i++) { | ||
var node, el; | ||
var backgroundSize = options.carouselData.slides[i].backgroundSize; | ||
if (options.carouselData[i].type === "node") { | ||
slide = options.carouselData[i].data; | ||
if (options.carouselData.slides[i].type === "node") { | ||
node = options.carouselData.slides[i].data; | ||
} else { | ||
slide = this.node.addChild(); | ||
el = new _DOMElement2.default(slide); | ||
node = this.node.addChild(); | ||
el = new _DOMElement2.default(node); | ||
if (typeof backgroundSize !== "string") { | ||
backgroundSize = "contain"; | ||
} | ||
switch (options.carouselData[i].type) { | ||
switch (options.carouselData.slides[i].type) { | ||
case "image": | ||
el.setProperty("backgroundImage", "url(" + options.carouselData[i].data + ")"); | ||
el.setProperty("backgroundImage", "url(" + options.carouselData.slides[i].data + ")"); | ||
el.setProperty("backgroundRepeat", "no-repeat"); | ||
@@ -225,13 +336,14 @@ el.setProperty("backgroundSize", backgroundSize); | ||
case "markup": | ||
el.setContent(options.carouselData[i].data); | ||
el.setContent(options.carouselData.slides[i].data); | ||
break; | ||
} | ||
el.setProperty("backfaceVisibility", "hidden"); | ||
el.setProperty("webkitBackfaceVisibility", "hidden"); | ||
} | ||
slide.setAlign(0.5, 0.5); | ||
slide.setMountPoint(0.5, 0.5); | ||
slide.setOrigin(0.5, 0.5); | ||
var gestureHandler = new _GestureHandler2.default(slide); | ||
var anchorXoffset; | ||
var gestureHandler = new _GestureHandler2.default(node); | ||
var isForward; | ||
var startPositionX; | ||
var previousVelocityX; | ||
var dragXPercentage = 0; | ||
/*eslint-disable */ | ||
@@ -242,15 +354,21 @@ gestureHandler.on("drag", (function (index, e) { | ||
this.draggedIndex = index; | ||
anchorXoffset = 0; | ||
return; | ||
case "move": | ||
if (this.draggedIndex === index) { | ||
var visibleSlides = this.adjacentSlides(index); | ||
if (typeof isForward === "undefined") { | ||
isForward = e.centerDelta.x / this.pages[index].node.getSize()[0]; | ||
if (isForward === 0) { | ||
isForward = undefined; | ||
return; // indeterminate direction | ||
} | ||
isForward = isForward < 0; | ||
} | ||
if (typeof startPositionX === "undefined") { | ||
startPositionX = e.center.x; | ||
} | ||
var visibleSlides = this.adjacentSlides(index + (isForward ? 1 : 0)); | ||
for (var key in visibleSlides) { | ||
var idx = visibleSlides[key]; | ||
if (isNaN(idx)) { | ||
continue; | ||
} | ||
anchorXoffset = e.centerDelta.x / this.pages[idx].node.getSize()[0]; | ||
anchorXoffset += this.pages[idx].anchor.x; | ||
this.pages[idx].anchor.set(anchorXoffset, 0, 0); | ||
dragXPercentage = Math.abs(startPositionX - e.pointers[0].position.x) / this.pages[idx].node.getSize()[0]; | ||
this.doDragPositioning(this.pages[idx], isForward, key, dragXPercentage); | ||
} | ||
@@ -260,33 +378,21 @@ } | ||
case "end": | ||
if (this.draggedIndex === index) { | ||
var direction = 0; | ||
if (anchorXoffset >= this.threshold) { | ||
direction = -1; // left | ||
} else if (anchorXoffset <= -this.threshold) { | ||
direction = 1; // right | ||
} | ||
if (direction === 0) { | ||
// Snap anchor back to center on release | ||
var visibleSlides = this.adjacentSlides(index); | ||
if (this.pages[index].anchor.x !== 0) { | ||
this.pages[index].anchor.set(0, 0, 0); | ||
if (!isNaN(visibleSlides.left)) { | ||
this.pages[visibleSlides.left].anchor.set(-1, 0, 0); | ||
} | ||
if (!isNaN(visibleSlides.right)) { | ||
this.pages[visibleSlides.right].anchor.set(1, 0, 0); | ||
} | ||
} | ||
} else { | ||
// Fire page change event if slide has moved beyond threshold | ||
this.options.context.emit("pageChange", { | ||
direction: direction, | ||
numSlidesToAdvance: this.options.manualSlidesToAdvance, | ||
stopAutoPlay: true | ||
}); | ||
if (dragXPercentage > this.threshold || Math.abs(e.centerVelocity.x) > 500) { | ||
this.options.context.emit("pageChange", { | ||
direction: isForward ? 1 : -1, | ||
numSlidesToAdvance: this.options.manualSlidesToAdvance, | ||
stopAutoPlay: true, | ||
resumeFromCurrentPosition: true | ||
}); | ||
} else if (dragXPercentage !== 0) { | ||
// restore slide to original position | ||
var visibleSlides = this.adjacentSlides(index); | ||
for (var key in visibleSlides) { | ||
var idx = visibleSlides[key]; | ||
this.restoreSlidePosition(this.pages[idx]); | ||
} | ||
_FamousEngine2.default.requestUpdateOnNextTick(this); | ||
} | ||
this.draggedIndex = -1; | ||
isForward = undefined; | ||
dragXPercentage = 0; | ||
startPositionX = undefined; | ||
return; | ||
@@ -299,45 +405,108 @@ default: | ||
// A `Box` body to relay simulation data back to the visual element | ||
var box = new Box({ | ||
mass: 100, | ||
size: [100, 100, 100] | ||
}); | ||
var page = { | ||
node: node, | ||
transitions: options.carouselData.slides[i].transitions, | ||
el: el, | ||
animDoneCallbackFired: false | ||
}; | ||
// Place all anchors off the screen & rotated, except for the | ||
// anchor belonging to the first/initial image node | ||
var anchor = new Vec3(1, 0, 0); //off-screen | ||
var yAngle = hideAngle; | ||
if (i === this.currentIndex) { | ||
anchor = new Vec3(0, 0, 0); //on-screen | ||
yAngle = 0; | ||
} | ||
slide.setRotation(0, yAngle, 0); | ||
pages.push(page); | ||
this.initSlideLocation(page, i === this.currentIndex); | ||
} | ||
// Attach the box to the anchor with a `Spring` force | ||
//ToDo: Add support for user-configurable transition | ||
var spring = new Spring(null, box, { | ||
period: 0.4, | ||
dampingRatio: 0.7, | ||
anchor: anchor | ||
}); | ||
this.pages = pages; | ||
} | ||
}, { | ||
key: "initSlideLocation", | ||
value: function initSlideLocation(slide, isCurrentIndex) { | ||
// Use initial settings from slide, falling back to global settings. | ||
var globalSlideTransitions = this.options.carouselData.transitions; | ||
var transitions = {}; | ||
(0, _lodash2.default)(transitions, globalSlideTransitions, slide.transitions); | ||
// Notify the physics engine to track the box and the springs | ||
this.simulation.add(box, spring); | ||
// Place the initial slide at its destination location. | ||
if (isCurrentIndex) { | ||
var xform = this.selectPagerTransform(transitions.entryTransition.transform); | ||
xform.set(slide, transitions.entryTransition.transformParams); | ||
return; | ||
} | ||
pages.push({ | ||
node: slide, | ||
el: el, | ||
box: box, | ||
spring: spring, | ||
anchor: anchor, | ||
animDoneCallbackFired: false | ||
}); | ||
if (_instanceof(transitions.initialAlign, Array)) { | ||
slide.node.setAlign(transitions.initialAlign[0], transitions.initialAlign[1], transitions.initialAlign[2]); | ||
} | ||
if (_instanceof(transitions.initialPosition, Array)) { | ||
slide.node.setPosition(transitions.initialPosition[0], transitions.initialPosition[1], transitions.initialPosition[2]); | ||
} | ||
if (_instanceof(transitions.initialMountPoint, Array)) { | ||
slide.node.setMountPoint(transitions.initialMountPoint[0], transitions.initialMountPoint[1], transitions.initialMountPoint[2]); | ||
} | ||
if (_instanceof(transitions.initialOrigin, Array)) { | ||
slide.node.setOrigin(transitions.initialOrigin[0], transitions.initialOrigin[1], transitions.initialOrigin[2]); | ||
} | ||
if (_instanceof(transitions.initialRotation, Array)) { | ||
slide.node.setRotation(transitions.initialRotation[0], transitions.initialRotation[1], transitions.initialRotation[2]); | ||
} | ||
} | ||
this.pages = pages; | ||
// Factory that returns the transform functions for the given type. | ||
}, { | ||
key: "selectPagerTransform", | ||
value: function selectPagerTransform(type) { | ||
switch (type) { | ||
case "align": | ||
return PagerAlign; | ||
case "position": | ||
return PagerPosition; | ||
case "rotate": | ||
return PagerRotate; | ||
case "mountPoint": | ||
return PagerMountPoint; //TBD | ||
case "origin": | ||
return PagerOrigin; //TBD | ||
case "physics": | ||
return PagerPhysics; //TBD | ||
} | ||
} | ||
// Return initial params based on the transform type | ||
}, { | ||
key: "initialParamsForTransformType", | ||
value: function initialParamsForTransformType(slide, type) { | ||
// Use initial settings from slide, falling back to global settings. | ||
var globalSlideTransitions = this.options.carouselData.transitions; | ||
var transitions = {}; | ||
(0, _lodash2.default)(transitions, globalSlideTransitions, slide.transitions); | ||
switch (type) { | ||
case "align": | ||
return transitions.initialAlign; | ||
case "position": | ||
return transitions.initialPosition; | ||
case "mountPoint": | ||
return transitions.initialMountPoint; | ||
case "origin": | ||
return transitions.initialOrigin; | ||
case "rotate": | ||
return transitions.initialRotation; | ||
} | ||
} | ||
// Return transition for action (e.g. entry or exit). | ||
// Search global as well as local slide overrides. | ||
}, { | ||
key: "transitionForAction", | ||
value: function transitionForAction(slide, action) { | ||
var globalTransition = this.options.carouselData.transitions ? this.options.carouselData.transitions[action] : {}; | ||
var slideTransition = slide.transitions ? slide.transitions[action] : {}; | ||
var transition = {}; | ||
(0, _lodash2.default)(transition, globalTransition, slideTransition); | ||
return transition; | ||
} | ||
// Find slides adjacent to the current index. Returns an object with keys | ||
// left, center, right. | ||
// If input slide is at either end, the left or right values are undefined. | ||
// previous, current, next. | ||
// If input slide is at either end, the previous or next values wrap around. | ||
@@ -347,8 +516,11 @@ }, { | ||
value: function adjacentSlides(centerIndex) { | ||
centerIndex = centerIndex < 0 ? this.pages.length - 1 : centerIndex; | ||
centerIndex = centerIndex >= this.pages.length ? 0 : centerIndex; | ||
var slides = {}; | ||
slides.left = centerIndex - 1; | ||
slides.right = centerIndex + 1; | ||
slides.previous = centerIndex - 1; | ||
slides.next = centerIndex + 1; | ||
slides.left = slides.left < 0 ? undefined : slides.left; | ||
slides.right = slides.right >= this.pages.length ? undefined : slides.right; | ||
slides.previous = slides.previous < 0 ? this.pages.length - 1 : slides.previous; | ||
slides.next = slides.next >= this.pages.length ? 0 : slides.next; | ||
slides.center = centerIndex; | ||
@@ -358,2 +530,16 @@ | ||
} | ||
}, { | ||
key: "removePages", | ||
value: function removePages() { | ||
for (var i = 0; i < this.pages.length; i++) { | ||
//DOMElement bug https://github.com/Famous/engine/issues/245 | ||
if (this.pages[i].el) { | ||
this.pages[i].el.setProperty("display", "none"); | ||
} | ||
this.pages[i].node.dismount(); | ||
this.options.parent.removeChild(this.pages[i].node); | ||
delete this.pages[i].node; | ||
} | ||
delete this.pages; | ||
} | ||
}]); | ||
@@ -360,0 +546,0 @@ |
@@ -1,28 +0,45 @@ | ||
[ | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background1.jpg"}, | ||
{ "type": "markup", | ||
"data": "<div class='center-element' style='color:white; text-shadow:-2px 0 black,0 1px black,1px 0 black,0 -1px black; font-family:sans-serif; font-size:30px; font-size:4vw'>Fade-in via<BR> animation callback</div>"}, | ||
{ "type": "markup", | ||
"data": "<div style='color:yellow; font-size:20px; font-family:sans-serif'>Embed any markup such as videos...</div><div style='position:absolute; top:30px; bottom: 0px; width:100%;'><iframe width='100%' height='100%' src='https://www.youtube.com/embed/76FsVGjMZeg' frameborder='0' allowfullscreen></iframe></div>"}, | ||
{ "type": "markup", | ||
"data": "<div style='color:yellow; font-size:20px; font-family:sans-serif'>...including entire web sites!</div><div style='position:absolute; top:30px; bottom: 0px; width:100%;'><iframe width='100%' height='100%' src='http://slashdot.org/' frameborder='0'></iframe></div>"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background3.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background4.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background5.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background6.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background7.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background8.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background9.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background10.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background11.jpg"} | ||
] | ||
{ | ||
"transitions": { | ||
"initialAlign": [1, 0, 0], | ||
"initialPosition": [0, 0, 0], | ||
"initialRotation": [0, 0, 0], | ||
"entryTransition": { | ||
"transform": "align", | ||
"transformParams": [0, 0, 0], | ||
"curve": "easeOut", | ||
"duration" : 600, | ||
}, | ||
"exitTransition": { | ||
"transform": "rotate", | ||
"transformParams": [0, -1.570796326795, 0], | ||
"curve": "easeOut", | ||
"duration" : 600, | ||
} | ||
}, | ||
"slides": [ | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background1.jpg"}, | ||
{ "type": "markup", | ||
"data": "<div class='center-element' style='color:white; text-shadow:-2px 0 black,0 1px black,1px 0 black,0 -1px black; font-family:sans-serif; font-size:30px; font-size:4vw'>Fade-in via<BR> animation callback</div>"}, | ||
{ "type": "markup", | ||
"data": "<div style='color:yellow; font-size:20px; font-family:sans-serif'>Embed any markup such as videos...</div><div style='position:absolute; top:30px; bottom: 0px; width:100%;'><iframe width='100%' height='100%' src='https://www.youtube.com/embed/76FsVGjMZeg' frameborder='0' allowfullscreen></iframe></div>"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background3.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background4.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background5.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background6.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background7.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background8.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background9.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background10.jpg"}, | ||
{ "type": "image", | ||
"data": "https://www.gstatic.com/cast/images/home/background11.jpg"} | ||
] | ||
} |
@@ -79,2 +79,4 @@ /** | ||
el.setProperty("backgroundPosition", "center"); | ||
el.setProperty("backfaceVisibility", "hidden"); | ||
el.setProperty("webkitBackfaceVisibility", "hidden"); | ||
node.setPosition(0, 0, -2); // -2 due to Chrome bug https://code.google.com/p/chromium/issues/detail?id=499397 | ||
@@ -92,2 +94,4 @@ } | ||
el.setProperty("fontSize", "2.5vw"); | ||
el.setProperty("backfaceVisibility", "hidden"); | ||
el.setProperty("webkitBackfaceVisibility", "hidden"); | ||
} | ||
@@ -94,0 +98,0 @@ |
{ | ||
"name": "famous-carousel", | ||
"version": "0.9.14", | ||
"version": "1.0.0", | ||
"author": "Peace Chen", | ||
@@ -22,9 +22,14 @@ "contributors": ["Tony Alves (https://github.com/talves)"], | ||
"build-commonjs": "browserify src/index.js -t [ babelify --modules common ] > dist/commonjs/famous-carousel.js", | ||
"build-es5": "npm run build-es5-index && npm run build-es5-carousel && npm run build-es5-dots && npm run build-es5-arrow && npm run build-es5-pager", | ||
"build-es5": "npm run build-es5-index && npm run build-es5-carousel && npm run build-es5-dots && npm run build-es5-arrow && npm run build-es5-pagers", | ||
"build-es5-index": "babel src/index.js > dist/es5/index.js", | ||
"build-es5-carousel": "babel src/Carousel.js > dist/es5/Carousel.js", | ||
"build-es5-pagers": "npm run build-es5-pager && npm run build-es5-pager-align && npm run build-es5-pager-rotate && npm run build-es5-pager-position && npm run build-es5-pager-physics", | ||
"build-es5-pager": "babel src/Pager.js > dist/es5/Pager.js", | ||
"build-es5-pager-align": "babel src/PagerAlign.js > dist/es5/PagerAlign.js", | ||
"build-es5-pager-rotate": "babel src/PagerRotate.js > dist/es5/PagerRotate.js", | ||
"build-es5-pager-position": "babel src/PagerPosition.js > dist/es5/PagerPosition.js", | ||
"build-es5-pager-physics": "babel src/PagerPhysics.js > dist/es5/PagerPhysics.js", | ||
"build-es5-dots": "babel src/Dots.js > dist/es5/Dots.js", | ||
"build-es5-arrow": "babel src/Arrow.js > dist/es5/Arrow.js", | ||
"test": "npm run lint-eslint && npm run lint-jscs", | ||
"test": "npm run lint-jscs", | ||
"lint-jscs": "jscs src/", | ||
@@ -54,4 +59,5 @@ "lint-eslint": "eslint --ignore-path .gitignore src/", | ||
"babel-polyfill": "^6.0.16", | ||
"famous": "git://github.com/peacechen/engine#af98b6c" | ||
"famous": "git://github.com/peacechen/engine#af98b6c", | ||
"lodash": "^4.13.1" | ||
} | ||
} |
@@ -6,15 +6,4 @@ ## Famo.us Carousel | ||
*** | ||
__UPDATE: 0.9.x introduces ES6 and a new require() path:__ | ||
CommonJS: | ||
var famousCarousel = require("famous-carousel").Carousel; | ||
var carousel = new famousCarousel( {...} ); | ||
Global: | ||
var carousel = famousCarousel.default( {...} ); | ||
__If you see any unusual behavior after upgrading, delete node\_modules and run _npm install_ again__ | ||
<BR> | ||
__BREAKING CHANGES: 1.0.0 introduces customizable transitions with an updated data format. | ||
Refer to the documentation and the example project.__ | ||
*** | ||
@@ -36,3 +25,17 @@ | ||
//------------------------------------------------- | ||
// CommonJS: | ||
var Carousel = require("famous-carousel").Carousel; | ||
// or... | ||
//------------------------------------------------- | ||
// ES6: | ||
import { Carousel } from "famous-carousel"; | ||
// or... | ||
//------------------------------------------------- | ||
// Global (boo) | ||
var Carousel = famousCarousel.default( {...} ); | ||
// Then create a new instance of the Carousel: | ||
var myCarousel = new Carousel("myDivSelector", { | ||
@@ -44,4 +47,2 @@ // add options here | ||
#### _ES6_ is now supported | ||
import { Carousel } from "famous-carousel"; | ||
@@ -58,21 +59,42 @@ ### Carousel Options | ||
* #### carouselData (required) | ||
Type: `Array`<BR> | ||
This specifies the content of the slides. It is an array of objects, each containing _type_, _data_, and optionally _backgroundSize_ keys.<BR> | ||
Type: `Object`<BR> | ||
This specifies the content of the slides and optional custom transitions.<BR> | ||
The _transitions_ key specifies the global entry and exit transitions. Each slide may have its own transitions which overrides the global ones. | ||
```JSON | ||
"transitions": { | ||
"initialAlign": [x, y, z], // 0 < x, y, z < 1 | ||
"initialPosition": [x, y, z], | ||
"initialRotation": [x, y, z], // 0 < x, y, z < 1 | ||
"entryTransition": { | ||
"transform": string, // "align", "rotate", "position" | ||
"transformParams": [x, y, z], | ||
"curve": string, // famous fixed curves | ||
"duration" : number, // ms | ||
}, | ||
"exitTransition": { | ||
// Same keys as entryTransition | ||
} | ||
} | ||
``` | ||
The _slides_ key is an array of objects, each containing _type_, _data_, and optionally _backgroundSize_ & _transition_ keys.<BR> | ||
_type_: may be `image`, `markup`, or `node`.<BR> | ||
_data_: must be a url for image, any valid html for markup, or a Famo.us node object.<BR> | ||
_backgroundSize_: [optional] CSS background-size attribute (default `contain`)<BR> | ||
_transition_: [optional] custom transition for the given slide only (see above for format).<BR> | ||
Example data:<BR> | ||
```JSON | ||
[ | ||
{ "type": "image", | ||
"data": "http://myDomain/myPicture.jpg", | ||
"backgroundSize": "cover" | ||
}, | ||
{ "type": "markup", | ||
"data": "<div style='color:blue'>Hello World<BR><BR>It's me!</div>" | ||
}, | ||
{ "type": "node", | ||
"data": myFamousNode | ||
} | ||
] | ||
"slide": { | ||
[ | ||
{ "type": "image", | ||
"data": "http://myDomain/myPicture.jpg", | ||
"backgroundSize": "cover" | ||
}, | ||
{ "type": "markup", | ||
"data": "<div style='color:blue'>Hello World<BR><BR>It's me!</div>" | ||
}, | ||
{ "type": "node", | ||
"data": myFamousNode | ||
} | ||
] | ||
} | ||
``` | ||
@@ -172,3 +194,3 @@ | ||
### Building | ||
To build a self-contained bundles: | ||
To build self-contained bundles: | ||
@@ -190,3 +212,3 @@ $ npm run build | ||
Run tests (linter & style checks for now): | ||
Run tests (~~linter &~~ style checks for now): | ||
@@ -223,7 +245,12 @@ npm run test | ||
**Q:** I upgraded the famous-carousel version and everything broke.<BR> | ||
**A1:** Delete node\_modules and run _npm install_ again.<BR> | ||
**A2:** Check that the data format matches what is required by the given version of famous-carousel. | ||
### To Do | ||
Pull requests are welcome. When submitting a PR, please make sure _npm run test_ passes. | ||
* Unit tests. | ||
* Add exit transition. | ||
* Add more user-configurable options such as slide transitions, nav arrow images... | ||
* ~~Add exit transition.~~ | ||
* Add more user-configurable options such as ~~slide transitions~~, nav arrow images... | ||
* Re-implement physics option for customizable transitions. | ||
* Option to auto-hide navigation arrows & dots. | ||
@@ -230,0 +257,0 @@ * Navigate by clicking on dots. |
@@ -46,3 +46,3 @@ /** | ||
carousel.pager.createPages(carousel.options); | ||
carousel.dots.createDots(carouselData.length); | ||
carousel.dots.createDots(carouselData.slides.length); | ||
@@ -91,5 +91,5 @@ _positionComponents(); | ||
if (carousel.options.initialIndex > carousel.options.carouselData.length - 1) { | ||
if (carousel.options.initialIndex > carousel.options.carouselData.slides.length - 1) { | ||
// Cap starting index to final page. | ||
carousel.options.initialIndex = carousel.options.carouselData.length - 1; | ||
carousel.options.initialIndex = carousel.options.carouselData.slides.length - 1; | ||
} | ||
@@ -107,3 +107,3 @@ | ||
parent: carousel.root, | ||
numPages: carousel.options.carouselData.length, | ||
numPages: carousel.options.carouselData.slides.length, | ||
initialIndex: carousel.options.initialIndex, | ||
@@ -169,3 +169,3 @@ width: carousel.options.dotWidth, | ||
var min = 0; | ||
var max = carousel.options.carouselData.length - 1; | ||
var max = carousel.options.carouselData.slides.length - 1; | ||
var floor = min; | ||
@@ -212,3 +212,3 @@ var ceiling = max; | ||
carousel.dots.pageChange(oldIndex, currentIndex); | ||
carousel.pager.pageChange(oldIndex, currentIndex); | ||
carousel.pager.pageChange(oldIndex, currentIndex, direction, payload.resumeFromCurrentPosition); | ||
} | ||
@@ -215,0 +215,0 @@ } |
505
src/Pager.js
@@ -6,14 +6,9 @@ /** | ||
import DOMElement from "famous/dom-renderables/DOMElement"; | ||
import PhysicsEngine from "famous/physics/PhysicsEngine"; | ||
import FamousEngine from "famous/core/FamousEngine"; | ||
import GestureHandler from "famous/components/GestureHandler"; | ||
import * as PagerAlign from "./PagerAlign"; | ||
import * as PagerRotate from "./PagerRotate"; | ||
import * as PagerPosition from "./PagerPosition"; | ||
import assign from "lodash.assign"; | ||
import physics from "famous/physics"; | ||
import math from "famous/math"; | ||
var Box = physics.Box; | ||
var Spring = physics.Spring; | ||
var Vec3 = math.Vec3; | ||
var hideAngle = Math.PI / 2; | ||
export class Pager { | ||
@@ -27,5 +22,2 @@ constructor(options) { | ||
// Add a physics simulation and update this instance using regular time updates from the clock. | ||
this.simulation = new PhysicsEngine(); | ||
var resizeComponent = { | ||
@@ -36,5 +28,2 @@ onSizeChange: x => this.pageWidth = x | ||
// .requestUpdate will call the .onUpdate method next frame, passing in the time stamp for that frame | ||
FamousEngine.requestUpdate(this); | ||
this.createPages(this.options); | ||
@@ -48,2 +37,3 @@ | ||
// Render animation frame by frame | ||
onUpdate(time) { | ||
@@ -54,86 +44,175 @@ if (!this.node) { | ||
this.simulation.update(time); | ||
var page; | ||
var physicsTransform; | ||
var p, r, xPos; | ||
for (var i = 0, len = this.pages.length; i < len; i++) { | ||
page = this.pages[i]; | ||
var transitionableXYZ; | ||
var xform; | ||
var requestUpdate = false; | ||
// Get the transform from the `Box` body | ||
physicsTransform = this.simulation.getTransform(page.box); | ||
p = physicsTransform.position; | ||
// Set the `slide`s x-position to the `Box` body's x-position | ||
// Math.round is significantly faster than toFixed. | ||
xPos = Math.round(p[0] * this.pageWidth * 100) / 100; | ||
page.node.setPosition(xPos, 0, 0); | ||
// Set the currently selected page's rotation to match the `Box` body's rotation | ||
if (i === this.currentIndex) { | ||
r = physicsTransform.rotation; | ||
page.node.setRotation(r[0], r[1], r[2], r[3]); | ||
//Fire user callback when sliding is done. | ||
if (Math.abs(xPos) === 0 && !page.animDoneCallbackFired) { | ||
page.animDoneCallbackFired = true; | ||
if (typeof this.options.animDoneCallback === "function") { | ||
this.options.animDoneCallback(page.node, i); | ||
} | ||
for (let page of this.pages) { | ||
if (page.transitionable instanceof Array === false) { | ||
continue; | ||
} | ||
transitionableXYZ = []; | ||
for (let i = 0; i < page.transitionable.length; i++) { | ||
if (page.transitionable[i] && page.transitionable[i].isActive()) { | ||
transitionableXYZ[i] = page.transitionable[i].get(); | ||
} else { | ||
delete page.currentTransform; | ||
} | ||
} else { | ||
page.animDoneCallbackFired = false; | ||
} | ||
if (transitionableXYZ.length > 0) { | ||
xform = this.selectPagerTransform(page.currentTransform); | ||
xform.set(page, transitionableXYZ); | ||
requestUpdate = true; | ||
} | ||
if (page === this.pages[this.currentIndex] && transitionableXYZ.length === 0) { | ||
this.options.animDoneCallback(page.node, this.currentIndex); | ||
} | ||
} | ||
FamousEngine.requestUpdateOnNextTick(this); | ||
if (requestUpdate) { | ||
FamousEngine.requestUpdateOnNextTick(this); | ||
} | ||
} | ||
pageChange(oldIndex, newIndex) { | ||
var xOffset; | ||
var reshuffle = false; | ||
var i; | ||
// Wrap-around cases shuffle pages to other side. | ||
if (oldIndex === this.pages.length - 1 && newIndex === 0) { | ||
xOffset = 1; | ||
reshuffle = true; | ||
} else if (oldIndex === 0 && newIndex === this.pages.length - 1) { | ||
xOffset = -1; | ||
reshuffle = true; | ||
// Calculate the position between matrices given percentage. | ||
positionBetweenMatrices(startMatrix, endMatrix, percentage) { | ||
var result = []; | ||
var range; | ||
for (let i = 0; i < startMatrix.length; i++) { | ||
range = endMatrix[i] - startMatrix[i]; | ||
result[i] = range * percentage + startMatrix[i]; | ||
} | ||
return result; | ||
} | ||
if (reshuffle) { | ||
for (i = 0; i < this.pages.length; i++) { | ||
this.pages[i].anchor.set(xOffset, 0, 0); | ||
this.pages[i].node.setRotation(0, hideAngle, 0); | ||
} | ||
// Worker function that performs the slide positioning for dragging. | ||
// Similar to doTransition but enough differences to warrant a separate function. | ||
doDragPositioning(slide, isForward, sequence, dragPercentage) { | ||
var transition; | ||
var startParams, endParams; | ||
var params; | ||
var xform; | ||
switch (sequence) { | ||
case "previous": | ||
transition = this.transitionForAction(slide, "exitTransition"); | ||
break; | ||
case "center": | ||
transition = this.transitionForAction(slide, "entryTransition"); | ||
break; | ||
case "next": | ||
default: | ||
return; | ||
} | ||
startParams = this.initialParamsForTransformType(slide, transition.transform); | ||
endParams = transition.transformParams; | ||
dragPercentage = 1 - dragPercentage; | ||
if (isForward) { | ||
// Swap start & end | ||
params = this.positionBetweenMatrices(endParams, startParams, dragPercentage); | ||
} else { | ||
// Non-wrapping cases | ||
xOffset = (oldIndex < newIndex) ? -1 : 1; | ||
this.pages[oldIndex].anchor.set(xOffset, 0, 0); | ||
this.pages[oldIndex].node.setRotation(0, hideAngle, 0); | ||
params = this.positionBetweenMatrices(startParams, endParams, dragPercentage); | ||
} | ||
xform = this.selectPagerTransform(transition.transform); | ||
slide.currentTransform = transition.transform; | ||
xform.set(slide, params); | ||
} | ||
restoreSlidePosition(slide) { | ||
if (slide.currentTransform) { | ||
var xform = this.selectPagerTransform(slide.currentTransform); | ||
var startParams = xform.get(slide); | ||
var endParams = this.initialParamsForTransformType(slide, slide.currentTransform); | ||
xform.animate(slide, startParams, endParams); | ||
} | ||
} | ||
// Worker function that performs the slide animation for arrow navigation. | ||
doTransition(slide, isForward, sequence, resumeFromCurrentPosition) { | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, false); //Set to initial location (could be hidden) | ||
} | ||
var transition; | ||
var startParams, endParams; | ||
var xform; | ||
switch (sequence) { | ||
case "previous": | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, true); //Set to entry final location (this is where to start from). | ||
} | ||
transition = this.transitionForAction(slide, "exitTransition"); | ||
if (isForward) { | ||
//ToDo? merge initial with slide params | ||
startParams = this.initialParamsForTransformType(slide, transition.transform); | ||
endParams = transition.transformParams; | ||
} else { | ||
// Prep slide by moving to "previous" location (no animation) | ||
xform = this.selectPagerTransform(transition.transform); | ||
xform.set(slide, transition.transformParams); | ||
return; | ||
} | ||
break; | ||
case "center": | ||
if (isForward) { | ||
transition = this.transitionForAction(slide, "entryTransition"); | ||
startParams = this.initialParamsForTransformType(slide, transition.transform); | ||
endParams = transition.transformParams; | ||
} else { | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, true); //Set to entry final location (where it will end up). | ||
} | ||
// Reverse exitTransition | ||
transition = this.transitionForAction(slide, "exitTransition"); | ||
startParams = transition.transformParams; | ||
//ToDo? merge initial with slide params | ||
endParams = this.initialParamsForTransformType(slide, transition.transform); | ||
} | ||
break; | ||
case "next": | ||
if (isForward) { | ||
this.initSlideLocation(slide, false); //For resumeFromCurrentPosition | ||
return; // No-op for full transition | ||
} | ||
if (!resumeFromCurrentPosition) { | ||
this.initSlideLocation(slide, true); //Set to entry final location (this is where to start from). | ||
} | ||
// Reverse entryTransition | ||
transition = this.transitionForAction(slide, "entryTransition"); | ||
startParams = transition.transformParams; | ||
//ToDo? merge initial with slide params | ||
endParams = this.initialParamsForTransformType(slide, transition.transform); | ||
break; | ||
} | ||
slide.currentTransform = transition.transform; | ||
slide.currentTransformOpts = { | ||
curve: transition.curve, | ||
duration: transition.duration | ||
}; | ||
xform = this.selectPagerTransform(transition.transform); | ||
if (resumeFromCurrentPosition) { | ||
startParams = xform.get(slide); | ||
} | ||
xform.animate(slide, startParams, endParams); | ||
} | ||
// Page change handler | ||
pageChange(oldIndex, newIndex, direction, resumeFromCurrentPosition) { | ||
var isForward = direction === 1; | ||
var visibleSlides = this.adjacentSlides(newIndex); | ||
var yRotation; | ||
for (i = 0; i < this.pages.length; i++) { | ||
yRotation = hideAngle; | ||
for (var i = 0; i < this.pages.length; i++) { | ||
for (var key in visibleSlides) { | ||
if (visibleSlides[key] === i) { | ||
yRotation = 0; | ||
switch (key) { | ||
case "left": | ||
xOffset = -1; | ||
break; | ||
case "center": | ||
xOffset = 0; | ||
break; | ||
case "right": | ||
xOffset = 1; | ||
break; | ||
} | ||
this.pages[i].anchor.set(xOffset, 0, 0); | ||
if (visibleSlides[key] === i) { // key is previous, center, next | ||
this.doTransition(this.pages[i], isForward, key, resumeFromCurrentPosition); | ||
} | ||
} | ||
this.pages[i].node.setRotation(0, yRotation, 0); | ||
} | ||
@@ -143,18 +222,8 @@ | ||
// Callback hook for animation start | ||
if (typeof this.options.animStartCallback === "function") { | ||
this.options.animStartCallback(this.pages[this.currentIndex].node, this.currentIndex); | ||
} | ||
} | ||
removePages() { | ||
for (var i = 0; i < this.pages.length; i++) { | ||
//DOMElement bug https://github.com/Famous/engine/issues/245 | ||
if (this.pages[i].el) { | ||
this.pages[i].el.setProperty("display", "none"); | ||
} | ||
this.pages[i].node.dismount(); | ||
this.options.parent.removeChild(this.pages[i].node); | ||
delete this.pages[i].node; | ||
} | ||
delete this.pages; | ||
FamousEngine.requestUpdateOnNextTick(this); | ||
} | ||
@@ -165,17 +234,17 @@ | ||
for (var i = 0; i < options.carouselData.length; i++) { | ||
var slide, el; | ||
var backgroundSize = options.carouselData[i].backgroundSize; | ||
for (var i = 0; i < options.carouselData.slides.length; i++) { | ||
var node, el; | ||
var backgroundSize = options.carouselData.slides[i].backgroundSize; | ||
if (options.carouselData[i].type === "node") { | ||
slide = options.carouselData[i].data; | ||
if (options.carouselData.slides[i].type === "node") { | ||
node = options.carouselData.slides[i].data; | ||
} else { | ||
slide = this.node.addChild(); | ||
el = new DOMElement(slide); | ||
node = this.node.addChild(); | ||
el = new DOMElement(node); | ||
if (typeof backgroundSize !== "string") { | ||
backgroundSize = "contain"; | ||
} | ||
switch (options.carouselData[i].type) { | ||
switch (options.carouselData.slides[i].type) { | ||
case "image": | ||
el.setProperty("backgroundImage", "url(" + options.carouselData[i].data + ")"); | ||
el.setProperty("backgroundImage", "url(" + options.carouselData.slides[i].data + ")"); | ||
el.setProperty("backgroundRepeat", "no-repeat"); | ||
@@ -186,13 +255,14 @@ el.setProperty("backgroundSize", backgroundSize); | ||
case "markup": | ||
el.setContent(options.carouselData[i].data); | ||
el.setContent(options.carouselData.slides[i].data); | ||
break; | ||
} | ||
el.setProperty("backfaceVisibility", "hidden"); | ||
el.setProperty("webkitBackfaceVisibility", "hidden"); | ||
} | ||
slide.setAlign(0.5, 0.5); | ||
slide.setMountPoint(0.5, 0.5); | ||
slide.setOrigin(0.5, 0.5); | ||
var gestureHandler = new GestureHandler(slide); | ||
var anchorXoffset; | ||
var gestureHandler = new GestureHandler(node); | ||
var isForward; | ||
var startPositionX; | ||
var previousVelocityX; | ||
var dragXPercentage = 0; | ||
/*eslint-disable */ | ||
@@ -203,15 +273,21 @@ gestureHandler.on("drag", function(index, e) { | ||
this.draggedIndex = index; | ||
anchorXoffset = 0; | ||
return; | ||
case "move": | ||
if (this.draggedIndex === index) { | ||
var visibleSlides = this.adjacentSlides(index); | ||
if (typeof isForward === "undefined") { | ||
isForward = e.centerDelta.x / this.pages[index].node.getSize()[0]; | ||
if (isForward === 0) { | ||
isForward = undefined; | ||
return; // indeterminate direction | ||
} | ||
isForward = isForward < 0; | ||
} | ||
if (typeof startPositionX === "undefined") { | ||
startPositionX = e.center.x; | ||
} | ||
var visibleSlides = this.adjacentSlides(index + (isForward ? 1 : 0)); | ||
for (var key in visibleSlides) { | ||
var idx = visibleSlides[key]; | ||
if (isNaN(idx)) { | ||
continue; | ||
} | ||
anchorXoffset = e.centerDelta.x / this.pages[idx].node.getSize()[0]; | ||
anchorXoffset += this.pages[idx].anchor.x; | ||
this.pages[idx].anchor.set(anchorXoffset, 0, 0); | ||
dragXPercentage = Math.abs(startPositionX - e.pointers[0].position.x) / this.pages[idx].node.getSize()[0]; | ||
this.doDragPositioning(this.pages[idx], isForward, key, dragXPercentage); | ||
} | ||
@@ -221,35 +297,21 @@ } | ||
case "end": | ||
if (this.draggedIndex === index) { | ||
var direction = 0; | ||
if (anchorXoffset >= this.threshold) { | ||
direction = -1; // left | ||
if (dragXPercentage > this.threshold || Math.abs(e.centerVelocity.x) > 500) { | ||
this.options.context.emit("pageChange", { | ||
direction: isForward ? 1 : -1, | ||
numSlidesToAdvance: this.options.manualSlidesToAdvance, | ||
stopAutoPlay: true, | ||
resumeFromCurrentPosition: true | ||
}); | ||
} else if (dragXPercentage !== 0) { | ||
// restore slide to original position | ||
var visibleSlides = this.adjacentSlides(index); | ||
for (var key in visibleSlides) { | ||
var idx = visibleSlides[key]; | ||
this.restoreSlidePosition(this.pages[idx]); | ||
} | ||
else if (anchorXoffset <= -this.threshold) { | ||
direction = 1; // right | ||
} | ||
if (direction === 0) { | ||
// Snap anchor back to center on release | ||
var visibleSlides = this.adjacentSlides(index); | ||
if (this.pages[index].anchor.x !== 0) { | ||
this.pages[index].anchor.set(0, 0, 0); | ||
if (!isNaN(visibleSlides.left)) { | ||
this.pages[visibleSlides.left].anchor.set(-1, 0, 0); | ||
} | ||
if (!isNaN(visibleSlides.right)) { | ||
this.pages[visibleSlides.right].anchor.set(1, 0, 0); | ||
} | ||
} | ||
} | ||
else { | ||
// Fire page change event if slide has moved beyond threshold | ||
this.options.context.emit("pageChange", { | ||
direction: direction, | ||
numSlidesToAdvance: this.options.manualSlidesToAdvance, | ||
stopAutoPlay: true | ||
}); | ||
} | ||
FamousEngine.requestUpdateOnNextTick(this); | ||
} | ||
this.draggedIndex = -1; | ||
isForward = undefined; | ||
dragXPercentage = 0; | ||
startPositionX = undefined; | ||
return; | ||
@@ -263,52 +325,108 @@ default: | ||
// A `Box` body to relay simulation data back to the visual element | ||
var box = new Box({ | ||
mass: 100, | ||
size: [100, 100, 100] | ||
}); | ||
var page = { | ||
node: node, | ||
transitions: options.carouselData.slides[i].transitions, | ||
el: el, | ||
animDoneCallbackFired: false | ||
}; | ||
// Place all anchors off the screen & rotated, except for the | ||
// anchor belonging to the first/initial image node | ||
var anchor = new Vec3(1, 0, 0); //off-screen | ||
var yAngle = hideAngle; | ||
if (i === this.currentIndex) { | ||
anchor = new Vec3(0, 0, 0); //on-screen | ||
yAngle = 0; | ||
} | ||
slide.setRotation(0, yAngle, 0); | ||
pages.push(page); | ||
this.initSlideLocation(page, i === this.currentIndex); | ||
} | ||
// Attach the box to the anchor with a `Spring` force | ||
//ToDo: Add support for user-configurable transition | ||
var spring = new Spring(null, box, { | ||
period: 0.4, | ||
dampingRatio: 0.7, | ||
anchor: anchor | ||
}); | ||
this.pages = pages; | ||
} | ||
// Notify the physics engine to track the box and the springs | ||
this.simulation.add(box, spring); | ||
initSlideLocation(slide, isCurrentIndex) { | ||
// Use initial settings from slide, falling back to global settings. | ||
var globalSlideTransitions = this.options.carouselData.transitions; | ||
var transitions = {}; | ||
assign(transitions, globalSlideTransitions, slide.transitions); | ||
pages.push({ | ||
node: slide, | ||
el: el, | ||
box: box, | ||
spring: spring, | ||
anchor: anchor, | ||
animDoneCallbackFired: false | ||
}); | ||
// Place the initial slide at its destination location. | ||
if (isCurrentIndex) { | ||
var xform = this.selectPagerTransform(transitions.entryTransition.transform); | ||
xform.set(slide, transitions.entryTransition.transformParams); | ||
return; | ||
} | ||
this.pages = pages; | ||
if (transitions.initialAlign instanceof Array) { | ||
slide.node.setAlign(transitions.initialAlign[0], transitions.initialAlign[1], transitions.initialAlign[2]); | ||
} | ||
if (transitions.initialPosition instanceof Array) { | ||
slide.node.setPosition(transitions.initialPosition[0], transitions.initialPosition[1], transitions.initialPosition[2]); | ||
} | ||
if (transitions.initialMountPoint instanceof Array) { | ||
slide.node.setMountPoint(transitions.initialMountPoint[0], transitions.initialMountPoint[1], transitions.initialMountPoint[2]); | ||
} | ||
if (transitions.initialOrigin instanceof Array) { | ||
slide.node.setOrigin(transitions.initialOrigin[0], transitions.initialOrigin[1], transitions.initialOrigin[2]); | ||
} | ||
if (transitions.initialRotation instanceof Array) { | ||
slide.node.setRotation(transitions.initialRotation[0], transitions.initialRotation[1], transitions.initialRotation[2]); | ||
} | ||
} | ||
// Factory that returns the transform functions for the given type. | ||
selectPagerTransform(type) { | ||
switch (type) { | ||
case "align": | ||
return PagerAlign; | ||
case "position": | ||
return PagerPosition; | ||
case "rotate": | ||
return PagerRotate; | ||
case "mountPoint": | ||
return PagerMountPoint; //TBD | ||
case "origin": | ||
return PagerOrigin; //TBD | ||
case "physics": | ||
return PagerPhysics; //TBD | ||
} | ||
} | ||
// Return initial params based on the transform type | ||
initialParamsForTransformType(slide, type) { | ||
// Use initial settings from slide, falling back to global settings. | ||
var globalSlideTransitions = this.options.carouselData.transitions; | ||
var transitions = {}; | ||
assign(transitions, globalSlideTransitions, slide.transitions); | ||
switch (type) { | ||
case "align": | ||
return transitions.initialAlign; | ||
case "position": | ||
return transitions.initialPosition; | ||
case "mountPoint": | ||
return transitions.initialMountPoint; | ||
case "origin": | ||
return transitions.initialOrigin; | ||
case "rotate": | ||
return transitions.initialRotation; | ||
} | ||
} | ||
// Return transition for action (e.g. entry or exit). | ||
// Search global as well as local slide overrides. | ||
transitionForAction(slide, action) { | ||
var globalTransition = this.options.carouselData.transitions ? this.options.carouselData.transitions[action] : {}; | ||
var slideTransition = slide.transitions ? slide.transitions[action] : {}; | ||
var transition = {}; | ||
assign(transition, globalTransition, slideTransition); | ||
return transition; | ||
} | ||
// Find slides adjacent to the current index. Returns an object with keys | ||
// left, center, right. | ||
// If input slide is at either end, the left or right values are undefined. | ||
// previous, current, next. | ||
// If input slide is at either end, the previous or next values wrap around. | ||
adjacentSlides(centerIndex) { | ||
centerIndex = centerIndex < 0 ? this.pages.length - 1 : centerIndex; | ||
centerIndex = centerIndex >= this.pages.length ? 0 : centerIndex; | ||
var slides = {}; | ||
slides.left = centerIndex - 1; | ||
slides.right = centerIndex + 1; | ||
slides.previous = centerIndex - 1; | ||
slides.next = centerIndex + 1; | ||
slides.left = slides.left < 0 ? undefined : slides.left; | ||
slides.right = slides.right >= this.pages.length ? undefined : slides.right; | ||
slides.previous = slides.previous < 0 ? this.pages.length - 1 : slides.previous; | ||
slides.next = slides.next >= this.pages.length ? 0 : slides.next; | ||
slides.center = centerIndex; | ||
@@ -319,2 +437,15 @@ | ||
removePages() { | ||
for (var i = 0; i < this.pages.length; i++) { | ||
//DOMElement bug https://github.com/Famous/engine/issues/245 | ||
if (this.pages[i].el) { | ||
this.pages[i].el.setProperty("display", "none"); | ||
} | ||
this.pages[i].node.dismount(); | ||
this.options.parent.removeChild(this.pages[i].node); | ||
delete this.pages[i].node; | ||
} | ||
delete this.pages; | ||
} | ||
} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Long strings
Supply chain riskContains long string literals, which may be a sign of obfuscated or packed code.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
36
1
257
0
2
104717
3
2123
+ Addedlodash@^4.13.1
+ Addedlodash@4.17.21(transitive)