snap.js 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. define(function(require, exports, module) {
  2. "use strict";
  3. var Util = require('../util');
  4. var Base = require('../base');
  5. /**
  6. * a snap plugin for xscroll,wich support vertical and horizontal snap.
  7. * @constructor
  8. * @param {object} cfg
  9. * @param {number} cfg.snapColIndex initial col index
  10. * @param {number} cfg.snapRowIndex initial row index
  11. * @param {number} cfg.snapDuration duration for snap animation
  12. * @param {string} cfg.snapEasing easing for snap animation
  13. * @param {number} cfg.snapOffsetLeft an offset from left boundry for snap wich default value is 0
  14. * @param {number} cfg.snapOffsetTop an offset from top boundry for snap wich default value is 0
  15. * @param {boolean} cfg.autoStep which step is based on scroll velocity
  16. * @extends {Base}
  17. */
  18. var Snap = function(cfg) {
  19. Snap.superclass.constructor.call(this, cfg);
  20. this.userConfig = Util.mix({
  21. snapColIndex: 0,
  22. snapRowIndex: 0,
  23. snapDuration: 500,
  24. snapEasing: "ease",
  25. snapOffsetLeft: 0,
  26. snapOffsetTop: 0,
  27. autoStep: false //autostep
  28. }, cfg);
  29. }
  30. Util.extend(Snap, Base, {
  31. /**
  32. * a pluginId
  33. * @memberOf Snap
  34. * @type {string}
  35. */
  36. pluginId: "snap",
  37. /**
  38. * plugin initializer
  39. * @memberOf Snap
  40. * @override Base
  41. * @return {Snap}
  42. */
  43. pluginInitializer: function(xscroll) {
  44. var self = this;
  45. self.xscroll = xscroll.render();
  46. self.snapColIndex = self.userConfig.snapColIndex;
  47. self.snapRowIndex = self.userConfig.snapRowIndex;
  48. self.render();
  49. },
  50. /**
  51. * detroy the plugin
  52. * @memberOf Snap
  53. * @override Base
  54. */
  55. pluginDestructor: function() {
  56. var self = this;
  57. var xscroll = self.xscroll;
  58. xscroll.on("panend", xscroll._onpanend, xscroll);
  59. xscroll.off("panend", self._snapAnimate, self);
  60. },
  61. /**
  62. * scroll to a col and row with animation
  63. * @memberOf Snap
  64. * @param {number} col col-index
  65. * @param {number} row row-index
  66. * @param {number} duration duration for animation ms
  67. * @param {string} easing easing for animation
  68. * @param {function} callback callback function after animation
  69. * @return {Snap}
  70. */
  71. snapTo: function(col, row, duration, easing, callback) {
  72. this.snapToCol(col, duration, easing, callback);
  73. this.snapToRow(row, duration, easing, callback);
  74. return this;
  75. },
  76. /**
  77. * scroll to a col with animation
  78. * @memberOf Snap
  79. * @param {number} col col-index
  80. * @param {number} duration duration for animation ms
  81. * @param {string} easing easing for animation
  82. * @param {function} callback callback function after animation
  83. * @return {Snap}
  84. */
  85. snapToCol: function(col, duration, easing, callback) {
  86. var self = this;
  87. var xscroll = self.xscroll;
  88. var userConfig = self.userConfig;
  89. var duration = duration || userConfig.snapDuration;
  90. var easing = easing || userConfig.snapEasing;
  91. var snapWidth = userConfig.snapWidth;
  92. var snapColsNum = userConfig.snapColsNum;
  93. var snapOffsetLeft = userConfig.snapOffsetLeft;
  94. col = col >= snapColsNum ? snapColsNum - 1 : col < 0 ? 0 : col;
  95. self.prevColIndex = self.snapColIndex;
  96. self.snapColIndex = col;
  97. var left = self.snapColIndex * snapWidth + snapOffsetLeft;
  98. if(left > xscroll.containerWidth - xscroll.boundry.width){
  99. left = xscroll.containerWidth - xscroll.boundry.width;
  100. }
  101. xscroll.scrollLeft(left, duration, easing, callback);
  102. return self;
  103. },
  104. _colChange: function(e) {
  105. var self = this;
  106. if (self.prevColIndex != self.snapColIndex) {
  107. self.trigger('colchange',Util.mix(e,{
  108. type:'colchange',
  109. curColIndex: self.snapColIndex,
  110. prevColIndex: self.prevColIndex
  111. }));
  112. }
  113. return self;
  114. },
  115. /**
  116. * scroll to a row with animation
  117. * @memberOf Snap
  118. * @param {number} row row-index
  119. * @param {number} duration duration for animation ms
  120. * @param {string} easing easing for animation
  121. * @param {function} callback callback function after animation
  122. * @return {Snap}
  123. */
  124. snapToRow: function(row, duration, easing, callback) {
  125. var self = this;
  126. var xscroll = self.xscroll;
  127. var userConfig = self.userConfig;
  128. var duration = duration || userConfig.snapDuration;
  129. var easing = easing || userConfig.snapEasing;
  130. var snapHeight = userConfig.snapHeight;
  131. var snapRowsNum = userConfig.snapRowsNum;
  132. var snapOffsetTop = userConfig.snapOffsetTop;
  133. row = row >= snapRowsNum ? snapRowsNum - 1 : row < 0 ? 0 : row;
  134. self.prevRowIndex = self.snapRowIndex;
  135. self.snapRowIndex = row;
  136. var top = self.snapRowIndex * snapHeight + snapOffsetTop;
  137. if(top > xscroll.containerHeight - xscroll.boundry.height){
  138. top = xscroll.containerHeight - xscroll.boundry.height;
  139. }
  140. self.xscroll.scrollTop(top, duration, easing,callback);
  141. return self;
  142. },
  143. _rowChange: function(e) {
  144. var self = this;
  145. if (self.prevRowIndex != self.snapRowIndex) {
  146. self.trigger('rowchange', Util.mix(e,{
  147. type:'rowchange',
  148. curRowIndex: self.snapRowIndex,
  149. prevRowIndex: self.prevRowIndex,
  150. }));
  151. }
  152. return self;
  153. },
  154. /*
  155. left => 2;
  156. right => 4;
  157. up => 8;
  158. down => 16;
  159. */
  160. _snapAnimate: function(e) {
  161. var self = this;
  162. var userConfig = self.userConfig;
  163. var snapWidth = userConfig.snapWidth;
  164. var snapHeight = userConfig.snapHeight;
  165. self.xscroll.__topstart = null;
  166. self.xscroll.__leftstart = null;
  167. var cx = snapWidth / 2;
  168. var cy = snapHeight / 2;
  169. var direction = e.direction;
  170. if (Math.abs(e.velocity) <= 0.2) {
  171. var left = self.xscroll.getScrollLeft();
  172. var top = self.xscroll.getScrollTop();
  173. var snapColIndex = Math.round(left / snapWidth);
  174. var snapRowIndex = Math.round(top / snapHeight);
  175. self.snapTo(snapColIndex, snapRowIndex);
  176. } else if (userConfig.autoStep) {
  177. var transX = self.xscroll.computeScroll("x", e.velocityX);
  178. var transY = self.xscroll.computeScroll("y", e.velocityY);
  179. var snapColIndex = transX && transX.pos ? Math.round(transX.pos / snapWidth) : self.snapColIndex;
  180. var snapRowIndex = transY && transY.pos ? Math.round(transY.pos / snapHeight) : self.snapRowIndex;
  181. var duration = Math.ceil(transX && transX.duration, transY && transY.duration);
  182. if (transX && transX.status == "inside") {
  183. self.snapToCol(snapColIndex, duration, transX && transX.easing, function() {
  184. self.xscroll.boundryCheckX();
  185. });
  186. } else if (transX) {
  187. self.xscroll.scrollLeft(transX.pos, transX.duration, transX.easing, function() {
  188. self.xscroll.boundryCheckX();
  189. self.prevColIndex = self.snapColIndex;
  190. self.snapColIndex = Math.round(Math.abs(self.xscroll.getScrollLeft()) / snapWidth);
  191. });
  192. }
  193. if (transY && transY.status == "inside") {
  194. self.snapToRow(snapRowIndex, duration, transY && transY.easing, function() {
  195. self.xscroll.boundryCheckY();
  196. });
  197. } else if (transY) {
  198. self.xscroll.scrollTop(transY.pos, transY.duration, transY.easing, function() {
  199. self.xscroll.boundryCheckY();
  200. self.prevRowIndex = self.snapRowIndex;
  201. self.snapRowIndex = Math.round(Math.abs(self.xscroll.getScrollTop()) / snapHeight);
  202. });
  203. }
  204. } else {
  205. direction == 2 ? self.snapColIndex++ : direction == 4 ? self.snapColIndex-- : undefined;
  206. direction == 8 ? self.snapRowIndex++ : direction == 16 ? self.snapRowIndex-- : undefined;
  207. self.snapTo(self.snapColIndex, self.snapRowIndex);
  208. }
  209. },
  210. /**
  211. * render snap plugin
  212. * @memberOf Snap
  213. * @return {Snap}
  214. */
  215. render: function() {
  216. var self = this;
  217. var xscroll = self.xscroll;
  218. self.userConfig.snapWidth = self.userConfig.snapWidth || xscroll.width || 100;
  219. self.userConfig.snapHeight = self.userConfig.snapHeight || xscroll.height || 100;
  220. self.userConfig.snapColsNum = self.userConfig.snapColsNum || Math.max(Math.round(xscroll.containerWidth / xscroll.width), 1);
  221. self.userConfig.snapRowsNum = self.userConfig.snapRowsNum || Math.max(Math.round(xscroll.containerHeight / xscroll.height), 1);
  222. //remove default listener
  223. xscroll.off("panend", xscroll._onpanend);
  224. xscroll.on("panend", self._snapAnimate, self);
  225. self._bindEvt();
  226. return self;
  227. },
  228. _bindEvt:function(){
  229. var self =this;
  230. var xscroll = self.xscroll;
  231. if(self._isEvtBinded) return;
  232. self._isEvtBinded = true;
  233. xscroll.on("scrollend",function(e){
  234. if(e.zoomType == 'y' && !xscroll.isBoundryOutTop() && !xscroll.isBoundryOutBottom()){
  235. self._rowChange(e);
  236. }
  237. })
  238. xscroll.on("scrollend",function(e){
  239. if(e.zoomType == 'x' && !xscroll.isBoundryOutLeft() && !xscroll.isBoundryOutRight()){
  240. self._colChange(e);
  241. }
  242. })
  243. }
  244. });
  245. if (typeof module == 'object' && module.exports) {
  246. module.exports = Snap;
  247. }
  248. /** ignored by jsdoc **/
  249. else if (window.XScroll && window.XScroll.Plugins) {
  250. return XScroll.Plugins.Snap = Snap;
  251. }
  252. });