ScrollToPlugin.js 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. /*!
  2. * VERSION: 1.8.1
  3. * DATE: 2017-01-17
  4. * UPDATES AND DOCS AT: http://greensock.com
  5. *
  6. * @license Copyright (c) 2008-2017, GreenSock. All rights reserved.
  7. * This work is subject to the terms at http://greensock.com/standard-license or for
  8. * Club GreenSock members, the software agreement that was issued with your membership.
  9. *
  10. * @author: Jack Doyle, jack@greensock.com
  11. **/
  12. var _gsScope = (typeof(module) !== "undefined" && module.exports && typeof(global) !== "undefined") ? global : this || window; //helps ensure compatibility with AMD/RequireJS and CommonJS/Node
  13. (_gsScope._gsQueue || (_gsScope._gsQueue = [])).push( function() {
  14. "use strict";
  15. var _doc = document.documentElement,
  16. _window = _gsScope,
  17. _max = function(element, axis) {
  18. var dim = (axis === "x") ? "Width" : "Height",
  19. scroll = "scroll" + dim,
  20. client = "client" + dim,
  21. body = document.body;
  22. return (element === _window || element === _doc || element === body) ? Math.max(_doc[scroll], body[scroll]) - (_window["inner" + dim] || _doc[client] || body[client]) : element[scroll] - element["offset" + dim];
  23. },
  24. _unwrapElement = function(value) {
  25. if (typeof(value) === "string") {
  26. value = TweenLite.selector(value);
  27. }
  28. if (value.length && value !== _window && value[0] && value[0].style && !value.nodeType) {
  29. value = value[0];
  30. }
  31. return (value === _window || (value.nodeType && value.style)) ? value : null;
  32. },
  33. _buildGetter = function(e, axis) { //pass in an element and an axis ("x" or "y") and it'll return a getter function for the scroll position of that element (like scrollTop or scrollLeft, although if the element is the window, it'll use the pageXOffset/pageYOffset or the documentElement's scrollTop/scrollLeft or document.body's. Basically this streamlines things and makes a very fast getter across browsers.
  34. var p = "scroll" + ((axis === "x") ? "Left" : "Top");
  35. if (e === _window) {
  36. if (e.pageXOffset != null) {
  37. p = "page" + axis.toUpperCase() + "Offset";
  38. } else if (_doc[p] != null) {
  39. e = _doc;
  40. } else {
  41. e = document.body;
  42. }
  43. }
  44. return function() {
  45. return e[p];
  46. };
  47. },
  48. _getOffset = function(element, container) {
  49. var rect = _unwrapElement(element).getBoundingClientRect(),
  50. isRoot = (!container || container === _window || container === document.body),
  51. cRect = (isRoot ? _doc : container).getBoundingClientRect(),
  52. offsets = {x: rect.left - cRect.left, y: rect.top - cRect.top};
  53. if (!isRoot && container) { //only add the current scroll position if it's not the window/body.
  54. offsets.x += _buildGetter(container, "x")();
  55. offsets.y += _buildGetter(container, "y")();
  56. }
  57. return offsets;
  58. },
  59. _parseVal = function(value, target, axis) {
  60. var type = typeof(value);
  61. if (type === "number" || (type === "string" && value.charAt(1) === "=")) {
  62. return value;
  63. } else if (value === "max") {
  64. return _max(target, axis);
  65. }
  66. return Math.min(_max(target, axis), _getOffset(value, target)[axis]);
  67. },
  68. ScrollToPlugin = _gsScope._gsDefine.plugin({
  69. propName: "scrollTo",
  70. API: 2,
  71. global: true,
  72. version:"1.8.1",
  73. //called when the tween renders for the first time. This is where initial values should be recorded and any setup routines should run.
  74. init: function(target, value, tween) {
  75. this._wdw = (target === _window);
  76. this._target = target;
  77. this._tween = tween;
  78. if (typeof(value) !== "object") {
  79. value = {y:value}; //if we don't receive an object as the parameter, assume the user intends "y".
  80. if (typeof(value.y) === "string" && value.y !== "max" && value.y.charAt(1) !== "=") {
  81. value.x = value.y;
  82. }
  83. } else if (value.nodeType) {
  84. value = {y:value, x:value};
  85. }
  86. this.vars = value;
  87. this._autoKill = (value.autoKill !== false);
  88. this.getX = _buildGetter(target, "x");
  89. this.getY = _buildGetter(target, "y");
  90. this.x = this.xPrev = this.getX();
  91. this.y = this.yPrev = this.getY();
  92. if (value.x != null) {
  93. this._addTween(this, "x", this.x, _parseVal(value.x, target, "x") - (value.offsetX || 0), "scrollTo_x", true);
  94. this._overwriteProps.push("scrollTo_x");
  95. } else {
  96. this.skipX = true;
  97. }
  98. if (value.y != null) {
  99. this._addTween(this, "y", this.y, _parseVal(value.y, target, "y") - (value.offsetY || 0), "scrollTo_y", true);
  100. this._overwriteProps.push("scrollTo_y");
  101. } else {
  102. this.skipY = true;
  103. }
  104. return true;
  105. },
  106. //called each time the values should be updated, and the ratio gets passed as the only parameter (typically it's a value between 0 and 1, but it can exceed those when using an ease like Elastic.easeOut or Back.easeOut, etc.)
  107. set: function(v) {
  108. this._super.setRatio.call(this, v);
  109. var x = (this._wdw || !this.skipX) ? this.getX() : this.xPrev,
  110. y = (this._wdw || !this.skipY) ? this.getY() : this.yPrev,
  111. yDif = y - this.yPrev,
  112. xDif = x - this.xPrev,
  113. threshold = ScrollToPlugin.autoKillThreshold;
  114. if (this.x < 0) { //can't scroll to a position less than 0! Might happen if someone uses a Back.easeOut or Elastic.easeOut when scrolling back to the top of the page (for example)
  115. this.x = 0;
  116. }
  117. if (this.y < 0) {
  118. this.y = 0;
  119. }
  120. if (this._autoKill) {
  121. //note: iOS has a bug that throws off the scroll by several pixels, so we need to check if it's within 7 pixels of the previous one that we set instead of just looking for an exact match.
  122. if (!this.skipX && (xDif > threshold || xDif < -threshold) && x < _max(this._target, "x")) {
  123. this.skipX = true; //if the user scrolls separately, we should stop tweening!
  124. }
  125. if (!this.skipY && (yDif > threshold || yDif < -threshold) && y < _max(this._target, "y")) {
  126. this.skipY = true; //if the user scrolls separately, we should stop tweening!
  127. }
  128. if (this.skipX && this.skipY) {
  129. this._tween.kill();
  130. if (this.vars.onAutoKill) {
  131. this.vars.onAutoKill.apply(this.vars.onAutoKillScope || this._tween, this.vars.onAutoKillParams || []);
  132. }
  133. }
  134. }
  135. if (this._wdw) {
  136. _window.scrollTo((!this.skipX) ? this.x : x, (!this.skipY) ? this.y : y);
  137. } else {
  138. if (!this.skipY) {
  139. this._target.scrollTop = this.y;
  140. }
  141. if (!this.skipX) {
  142. this._target.scrollLeft = this.x;
  143. }
  144. }
  145. this.xPrev = this.x;
  146. this.yPrev = this.y;
  147. }
  148. }),
  149. p = ScrollToPlugin.prototype;
  150. ScrollToPlugin.max = _max;
  151. ScrollToPlugin.getOffset = _getOffset;
  152. ScrollToPlugin.autoKillThreshold = 7;
  153. p._kill = function(lookup) {
  154. if (lookup.scrollTo_x) {
  155. this.skipX = true;
  156. }
  157. if (lookup.scrollTo_y) {
  158. this.skipY = true;
  159. }
  160. return this._super._kill.call(this, lookup);
  161. };
  162. }); if (_gsScope._gsDefine) { _gsScope._gsQueue.pop()(); }
  163. //export to AMD/RequireJS and CommonJS/Node (precursor to full modular build system coming at a later date)
  164. (function(name) {
  165. "use strict";
  166. var getGlobal = function() {
  167. return (_gsScope.GreenSockGlobals || _gsScope)[name];
  168. };
  169. if (typeof(define) === "function" && define.amd) { //AMD
  170. define(["TweenLite"], getGlobal);
  171. } else if (typeof(module) !== "undefined" && module.exports) { //node
  172. require("../TweenLite.js");
  173. module.exports = getGlobal();
  174. }
  175. }("ScrollToPlugin"));