diff --git a/docs/changelog/README.md b/docs/changelog/README.md index 05a3990d..6fdd67c3 100644 --- a/docs/changelog/README.md +++ b/docs/changelog/README.md @@ -1,3 +1,10 @@ +## [2.16.2](https://github.com/rigor789/vue-scrollto/compare/v2.16.1...v2.16.2) (2019-09-10) + + +### Bug Fixes + +* calculation for {force: false, offset: nonZero} ([#139](https://github.com/rigor789/vue-scrollto/issues/139)) ([f01ce23](https://github.com/rigor789/vue-scrollto/commit/f01ce23)), closes [#138](https://github.com/rigor789/vue-scrollto/issues/138) + ## [2.16.1](https://github.com/rigor789/vue-scrollto/compare/v2.16.0...v2.16.1) (2019-09-10) diff --git a/src/scrollTo.js b/src/scrollTo.js index 6a47d7c4..c8450428 100644 --- a/src/scrollTo.js +++ b/src/scrollTo.js @@ -196,7 +196,7 @@ export const scroller = () => { : container.offsetHeight; const containerTop = initialY; const containerBottom = containerTop + containerHeight; - const elementTop = targetY; + const elementTop = targetY - offset; const elementBottom = elementTop + element.offsetHeight; if ( elementTop >= containerTop && diff --git a/vue-scrollto.js b/vue-scrollto.js deleted file mode 100644 index 8982d870..00000000 --- a/vue-scrollto.js +++ /dev/null @@ -1,510 +0,0 @@ -/*! - * vue-scrollto v2.15.0 - * (c) 2019 Randjelovic Igor - * @license MIT - */ -(function (global, factory) { - typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : - typeof define === 'function' && define.amd ? define(factory) : - (global = global || self, global['vue-scrollto'] = factory()); -}(this, function () { 'use strict'; - - function _typeof(obj) { - if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { - _typeof = function (obj) { - return typeof obj; - }; - } else { - _typeof = function (obj) { - return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; - }; - } - - return _typeof(obj); - } - - function _extends() { - _extends = Object.assign || function (target) { - for (var i = 1; i < arguments.length; i++) { - var source = arguments[i]; - - for (var key in source) { - if (Object.prototype.hasOwnProperty.call(source, key)) { - target[key] = source[key]; - } - } - } - - return target; - }; - - return _extends.apply(this, arguments); - } - - /** - * https://github.com/gre/bezier-easing - * BezierEasing - use bezier curve for transition easing function - * by Gaëtan Renaudeau 2014 - 2015 – MIT License - */ - - // These values are established by empiricism with tests (tradeoff: performance VS precision) - var NEWTON_ITERATIONS = 4; - var NEWTON_MIN_SLOPE = 0.001; - var SUBDIVISION_PRECISION = 0.0000001; - var SUBDIVISION_MAX_ITERATIONS = 10; - - var kSplineTableSize = 11; - var kSampleStepSize = 1.0 / (kSplineTableSize - 1.0); - - var float32ArraySupported = typeof Float32Array === 'function'; - - function A (aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } - function B (aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } - function C (aA1) { return 3.0 * aA1; } - - // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. - function calcBezier (aT, aA1, aA2) { return ((A(aA1, aA2) * aT + B(aA1, aA2)) * aT + C(aA1)) * aT; } - - // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. - function getSlope (aT, aA1, aA2) { return 3.0 * A(aA1, aA2) * aT * aT + 2.0 * B(aA1, aA2) * aT + C(aA1); } - - function binarySubdivide (aX, aA, aB, mX1, mX2) { - var currentX, currentT, i = 0; - do { - currentT = aA + (aB - aA) / 2.0; - currentX = calcBezier(currentT, mX1, mX2) - aX; - if (currentX > 0.0) { - aB = currentT; - } else { - aA = currentT; - } - } while (Math.abs(currentX) > SUBDIVISION_PRECISION && ++i < SUBDIVISION_MAX_ITERATIONS); - return currentT; - } - - function newtonRaphsonIterate (aX, aGuessT, mX1, mX2) { - for (var i = 0; i < NEWTON_ITERATIONS; ++i) { - var currentSlope = getSlope(aGuessT, mX1, mX2); - if (currentSlope === 0.0) { - return aGuessT; - } - var currentX = calcBezier(aGuessT, mX1, mX2) - aX; - aGuessT -= currentX / currentSlope; - } - return aGuessT; - } - - function LinearEasing (x) { - return x; - } - - var src = function bezier (mX1, mY1, mX2, mY2) { - if (!(0 <= mX1 && mX1 <= 1 && 0 <= mX2 && mX2 <= 1)) { - throw new Error('bezier x values must be in [0, 1] range'); - } - - if (mX1 === mY1 && mX2 === mY2) { - return LinearEasing; - } - - // Precompute samples table - var sampleValues = float32ArraySupported ? new Float32Array(kSplineTableSize) : new Array(kSplineTableSize); - for (var i = 0; i < kSplineTableSize; ++i) { - sampleValues[i] = calcBezier(i * kSampleStepSize, mX1, mX2); - } - - function getTForX (aX) { - var intervalStart = 0.0; - var currentSample = 1; - var lastSample = kSplineTableSize - 1; - - for (; currentSample !== lastSample && sampleValues[currentSample] <= aX; ++currentSample) { - intervalStart += kSampleStepSize; - } - --currentSample; - - // Interpolate to provide an initial guess for t - var dist = (aX - sampleValues[currentSample]) / (sampleValues[currentSample + 1] - sampleValues[currentSample]); - var guessForT = intervalStart + dist * kSampleStepSize; - - var initialSlope = getSlope(guessForT, mX1, mX2); - if (initialSlope >= NEWTON_MIN_SLOPE) { - return newtonRaphsonIterate(aX, guessForT, mX1, mX2); - } else if (initialSlope === 0.0) { - return guessForT; - } else { - return binarySubdivide(aX, intervalStart, intervalStart + kSampleStepSize, mX1, mX2); - } - } - - return function BezierEasing (x) { - // Because JavaScript number are imprecise, we should guarantee the extremes are right. - if (x === 0) { - return 0; - } - if (x === 1) { - return 1; - } - return calcBezier(getTForX(x), mY1, mY2); - }; - }; - - var easings = { - ease: [0.25, 0.1, 0.25, 1.0], - linear: [0.00, 0.0, 1.00, 1.0], - "ease-in": [0.42, 0.0, 1.00, 1.0], - "ease-out": [0.00, 0.0, 0.58, 1.0], - "ease-in-out": [0.42, 0.0, 0.58, 1.0] - }; - - // https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md#feature-detection - var supportsPassive = false; - - try { - var opts = Object.defineProperty({}, "passive", { - get: function get() { - supportsPassive = true; - } - }); - window.addEventListener("test", null, opts); - } catch (e) {} - - var _ = { - $: function $(selector) { - if (typeof selector !== "string") { - return selector; - } - - return document.querySelector(selector); - }, - on: function on(element, events, handler) { - var opts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : { - passive: false - }; - - if (!(events instanceof Array)) { - events = [events]; - } - - for (var i = 0; i < events.length; i++) { - element.addEventListener(events[i], handler, supportsPassive ? opts : false); - } - }, - off: function off(element, events, handler) { - if (!(events instanceof Array)) { - events = [events]; - } - - for (var i = 0; i < events.length; i++) { - element.removeEventListener(events[i], handler); - } - }, - cumulativeOffset: function cumulativeOffset(element) { - var top = 0; - var left = 0; - - do { - top += element.offsetTop || 0; - left += element.offsetLeft || 0; - element = element.offsetParent; - } while (element); - - return { - top: top, - left: left - }; - } - }; - - var abortEvents = ["mousedown", "wheel", "DOMMouseScroll", "mousewheel", "keyup", "touchmove"]; - var defaults = { - container: "body", - duration: 500, - easing: "ease", - offset: 0, - force: true, - cancelable: true, - onStart: false, - onDone: false, - onCancel: false, - x: false, - y: true - }; - function setDefaults(options) { - defaults = _extends({}, defaults, options); - } - var scroller = function scroller() { - var element; // element to scroll to - - var container; // container to scroll - - var duration; // duration of the scrolling - - var easing; // easing to be used when scrolling - - var offset; // offset to be added (subtracted) - - var force; // force scroll, even if element is visible - - var cancelable; // indicates if user can cancel the scroll or not. - - var onStart; // callback when scrolling is started - - var onDone; // callback when scrolling is done - - var onCancel; // callback when scrolling is canceled / aborted - - var x; // scroll on x axis - - var y; // scroll on y axis - - var initialX; // initial X of container - - var targetX; // target X of container - - var initialY; // initial Y of container - - var targetY; // target Y of container - - var diffX; // difference - - var diffY; // difference - - var abort; // is scrolling aborted - - var abortEv; // event that aborted scrolling - - var abortFn = function abortFn(e) { - if (!cancelable) return; - abortEv = e; - abort = true; - }; - - var easingFn; - var timeStart; // time when scrolling started - - var timeElapsed; // time elapsed since scrolling started - - var progress; // progress - - function scrollTop(container) { - var scrollTop = container.scrollTop; - - if (container.tagName.toLowerCase() === "body") { - // in firefox body.scrollTop always returns 0 - // thus if we are trying to get scrollTop on a body tag - // we need to get it from the documentElement - scrollTop = scrollTop || document.documentElement.scrollTop; - } - - return scrollTop; - } - - function scrollLeft(container) { - var scrollLeft = container.scrollLeft; - - if (container.tagName.toLowerCase() === "body") { - // in firefox body.scrollLeft always returns 0 - // thus if we are trying to get scrollLeft on a body tag - // we need to get it from the documentElement - scrollLeft = scrollLeft || document.documentElement.scrollLeft; - } - - return scrollLeft; - } - - function step(timestamp) { - if (abort) return done(); - if (!timeStart) timeStart = timestamp; - timeElapsed = timestamp - timeStart; - progress = Math.min(timeElapsed / duration, 1); - progress = easingFn(progress); - topLeft(container, initialY + diffY * progress, initialX + diffX * progress); - timeElapsed < duration ? window.requestAnimationFrame(step) : done(); - } - - function done() { - if (!abort) topLeft(container, targetY, targetX); - timeStart = false; - - _.off(container, abortEvents, abortFn); - - if (abort && onCancel) onCancel(abortEv, element); - if (!abort && onDone) onDone(element); - } - - function topLeft(element, top, left) { - if (y) element.scrollTop = top; - if (x) element.scrollLeft = left; - - if (element.tagName.toLowerCase() === "body") { - // in firefox body.scrollTop doesn't scroll the page - // thus if we are trying to scrollTop on a body tag - // we need to scroll on the documentElement - if (y) document.documentElement.scrollTop = top; - if (x) document.documentElement.scrollLeft = left; - } - } - - function scrollTo(target, _duration) { - var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; - - if (_typeof(_duration) === "object") { - options = _duration; - } else if (typeof _duration === "number") { - options.duration = _duration; - } - - element = _.$(target); - - if (!element) { - return console.warn("[vue-scrollto warn]: Trying to scroll to an element that is not on the page: " + target); - } - - container = _.$(options.container || defaults.container); - duration = options.duration || defaults.duration; - easing = options.easing || defaults.easing; - offset = options.offset || defaults.offset; - force = options.hasOwnProperty("force") ? options.force !== false : defaults.force; - cancelable = options.hasOwnProperty("cancelable") ? options.cancelable !== false : defaults.cancelable; - onStart = options.onStart || defaults.onStart; - onDone = options.onDone || defaults.onDone; - onCancel = options.onCancel || defaults.onCancel; - x = options.x === undefined ? defaults.x : options.x; - y = options.y === undefined ? defaults.y : options.y; - - var cumulativeOffsetContainer = _.cumulativeOffset(container); - - var cumulativeOffsetElement = _.cumulativeOffset(element); - - if (typeof offset === "function") { - offset = offset(element, container); - } - - initialY = scrollTop(container); - targetY = cumulativeOffsetElement.top - cumulativeOffsetContainer.top + offset; - initialX = scrollLeft(container); - targetX = cumulativeOffsetElement.left - cumulativeOffsetContainer.left + offset; - abort = false; - diffY = targetY - initialY; - diffX = targetX - initialX; - - if (!force) { - var containerTop = initialY; - var containerBottom = containerTop + container.offsetHeight; - var elementTop = targetY; - var elementBottom = elementTop + element.offsetHeight; - - if (elementTop >= containerTop && elementBottom <= containerBottom) { - // make sure to call the onDone callback even if there is no need to - // scroll the container. Fixes #111 (ref #118) - onDone(element); - return; - } - } - - if (typeof easing === "string") { - easing = easings[easing] || easings["ease"]; - } - - easingFn = src.apply(src, easing); - if (!diffY && !diffX) return; - if (onStart) onStart(element); - - _.on(container, abortEvents, abortFn, { - passive: true - }); - - window.requestAnimationFrame(step); - return function () { - abortEv = null; - abort = true; - }; - } - - return scrollTo; - }; - - var _scroller = scroller(); - - var bindings = []; // store binding data - - function deleteBinding(el) { - for (var i = 0; i < bindings.length; ++i) { - if (bindings[i].el === el) { - bindings.splice(i, 1); - return true; - } - } - - return false; - } - - function findBinding(el) { - for (var i = 0; i < bindings.length; ++i) { - if (bindings[i].el === el) { - return bindings[i]; - } - } - } - - function getBinding(el) { - var binding = findBinding(el); - - if (binding) { - return binding; - } - - bindings.push(binding = { - el: el, - binding: {} - }); - return binding; - } - - function handleClick(e) { - e.preventDefault(); - var ctx = getBinding(this).binding; - - if (typeof ctx.value === "string") { - return _scroller(ctx.value); - } - - _scroller(ctx.value.el || ctx.value.element, ctx.value); - } - - var VueScrollTo = { - bind: function bind(el, binding) { - getBinding(el).binding = binding; - - _.on(el, "click", handleClick); - }, - unbind: function unbind(el) { - deleteBinding(el); - - _.off(el, "click", handleClick); - }, - update: function update(el, binding) { - getBinding(el).binding = binding; - }, - scrollTo: _scroller, - bindings: bindings - }; - - var install = function install(Vue, options) { - if (options) setDefaults(options); - Vue.directive("scroll-to", VueScrollTo); - Vue.prototype.$scrollTo = VueScrollTo.scrollTo; - }; - - if (typeof window !== "undefined" && window.Vue) { - window.VueScrollTo = VueScrollTo; - window.VueScrollTo.setDefaults = setDefaults; - window.Vue.use(install); - } - - VueScrollTo.install = install; - - return VueScrollTo; - -}));