scale.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. define(function(require, exports, module) {
  2. "use strict";
  3. var Util = require('../util'),
  4. Base = require('../base');
  5. // reduced scale rate
  6. var SCALE_RATE = 0.7;
  7. var SCALE_TO_DURATION = 300;
  8. /**
  9. * A scalable plugin for xscroll.
  10. * @constructor
  11. * @param {object} cfg
  12. * @param {number} cfg.minScale min value for scale
  13. * @param {number} cfg.maxScale max value for scale
  14. * @param {number} cfg.duration duration for scale animation
  15. * @extends {Base}
  16. */
  17. var Scale = function(cfg) {
  18. Scale.superclass.constructor.call(this, cfg);
  19. this.userConfig = Util.mix({
  20. minScale: 1,
  21. maxScale: 2,
  22. duration: SCALE_TO_DURATION
  23. }, cfg);
  24. }
  25. Util.extend(Scale, Base, {
  26. /**
  27. * a pluginId
  28. * @memberOf Scale
  29. * @type {string}
  30. */
  31. pluginId: "scale",
  32. /**
  33. * plugin initializer
  34. * @memberOf Scale
  35. * @override Scale
  36. * @return {Infinite}
  37. */
  38. pluginInitializer: function(xscroll) {
  39. var self = this;
  40. self.scale = 1;
  41. self.xscroll = xscroll.render();
  42. self.initialContainerWidth = xscroll.containerWidth;
  43. self.initialContainerHeight = xscroll.containerHeight;
  44. self.minScale = self.userConfig.minScale || Math.max(xscroll.width / xscroll.containerWidth, xscroll.height / xscroll.containerHeight);
  45. self.maxScale = self.userConfig.maxScale || 1;
  46. self._bindEvt();
  47. return self;
  48. },
  49. /**
  50. * detroy the plugin
  51. * @memberOf Scale
  52. * @override Base
  53. * @return {Scale}
  54. */
  55. pluginDestructor: function() {
  56. var self = this;
  57. var xscroll = self.xscroll;
  58. xscroll.off("doubletap", self._doubleTapHandler, self);
  59. xscroll.off("pinchstart", self._pinchStartHandler, self);
  60. xscroll.off("pinchmove", self._pinchHandler, self);
  61. xscroll.off("pinchend pinchcancel", self._pinchEndHandler, self);
  62. return self;
  63. },
  64. _doubleTapHandler: function(e) {
  65. var self = this;
  66. var xscroll = self.xscroll;
  67. var minScale = self.userConfig.minScale;
  68. var maxScale = self.userConfig.maxScale;
  69. var duration = self.userConfig.duration;
  70. self.originX = (e.center.x - xscroll.x) / xscroll.containerWidth;
  71. self.originY = (e.center.y - xscroll.y) / xscroll.containerHeight;
  72. xscroll.scale > self.minScale ? self.scaleTo(minScale, self.originX, self.originY, duration) : self.scaleTo(maxScale, self.originX, self.originY, duration);
  73. return self;
  74. },
  75. _pinchStartHandler: function(e) {
  76. var self = this;
  77. var xscroll = self.xscroll;
  78. //disable pan gesture
  79. self.disablePan();
  80. xscroll.stop();
  81. self.isScaling = false;
  82. self.scale = xscroll.scale;
  83. self.originX = (e.center.x - xscroll.x) / xscroll.containerWidth;
  84. self.originY = (e.center.y - xscroll.y) / xscroll.containerHeight;
  85. },
  86. _pinchHandler: function(e) {
  87. var self = this;
  88. var scale = self.scale;
  89. var xscroll = self.xscroll;
  90. var originX = self.originX;
  91. var originY = self.originY;
  92. var __scale = scale * e.scale;
  93. if (__scale <= self.userConfig.minScale) {
  94. // s = 1/2 * a * 2^(s/a)
  95. __scale = 0.5 * self.userConfig.minScale * Math.pow(2, __scale / self.userConfig.minScale);
  96. }
  97. if (__scale >= self.userConfig.maxScale) {
  98. // s = 2 * a * 1/2^(a/s)
  99. __scale = 2 * self.userConfig.maxScale * Math.pow(0.5, self.userConfig.maxScale / __scale);
  100. }
  101. self._scale(__scale, originX, originY);
  102. self.xscroll.translate(xscroll.x, xscroll.y, __scale, 'e.scale', e.scale);
  103. },
  104. disablePan: function() {
  105. this.xscroll.mc.get("pan").set({
  106. enable: false
  107. });
  108. return this;
  109. },
  110. enablePan: function() {
  111. this.xscroll.mc.get("pan").set({
  112. enable: true
  113. });
  114. return this;
  115. },
  116. _pinchEndHandler: function(e) {
  117. var self = this;
  118. var originX = self.originX;
  119. var originY = self.originY;
  120. var xscroll = self.xscroll;
  121. if (xscroll.scale < self.minScale) {
  122. self.scaleTo(self.minScale, originX, originY, SCALE_TO_DURATION, "ease-out", self.enablePan);
  123. } else if (xscroll.scale > self.maxScale) {
  124. self.scaleTo(self.maxScale, originX, originY, SCALE_TO_DURATION, "ease-out", self.enablePan);
  125. } else {
  126. self.enablePan();
  127. }
  128. },
  129. _bindEvt: function() {
  130. var self = this;
  131. var xscroll = self.xscroll;
  132. xscroll.on("doubletap", self._doubleTapHandler, self);
  133. xscroll.on("pinchstart", self._pinchStartHandler, self);
  134. xscroll.on("pinchmove", self._pinchHandler, self);
  135. xscroll.on("pinchend pinchcancel", self._pinchEndHandler, self);
  136. return self;
  137. },
  138. _scale: function(scale, originX, originY) {
  139. var self = this;
  140. var xscroll = self.xscroll;
  141. var boundry = self.xscroll.boundry;
  142. if (xscroll.scale == scale || !scale) return;
  143. if (!self.isScaling) {
  144. self.scaleBegin = xscroll.scale;
  145. self.isScaling = true;
  146. self.scaleBeginX = xscroll.x;
  147. self.scaleBeginY = xscroll.y;
  148. }
  149. if (originX) {
  150. self.originX = originX;
  151. }
  152. if (originY) {
  153. self.originY = originY;
  154. }
  155. var containerWidth = scale * self.initialContainerWidth;
  156. var containerHeight = scale * self.initialContainerHeight;
  157. xscroll.containerWidth = Math.round(containerWidth > xscroll.width ? containerWidth : xscroll.width);
  158. xscroll.containerHeight = Math.round(containerHeight > xscroll.height ? containerHeight : xscroll.height);
  159. xscroll.scale = scale;
  160. var x = originX * (self.initialContainerWidth * self.scaleBegin - xscroll.containerWidth) + self.scaleBeginX;
  161. var y = originY * (self.initialContainerHeight * self.scaleBegin - xscroll.containerHeight) + self.scaleBeginY;
  162. if (x > boundry.left) {
  163. x = boundry.left;
  164. }
  165. if (y > boundry.top) {
  166. y = boundry.top;
  167. }
  168. if (x < boundry.right - xscroll.containerWidth) {
  169. x = boundry.right - xscroll.containerWidth;
  170. }
  171. if (y < boundry.bottom - xscroll.containerHeight) {
  172. y = boundry.bottom - xscroll.containerHeight;
  173. }
  174. xscroll.x = x;
  175. xscroll.y = y;
  176. },
  177. /**
  178. * scale with an animation
  179. * @memberOf Scale
  180. * @param {number} scale
  181. * @param {number} originX 0~1
  182. * @param {number} originY 0~1
  183. * @param {number} duration
  184. * @param {string} easing
  185. * @param {function} callback
  186. */
  187. scaleTo: function(scale, originX, originY, duration, easing, callback) {
  188. var self = this;
  189. var xscroll = self.xscroll;
  190. //unscalable
  191. if (xscroll.scale == scale || !scale) return;
  192. var duration = duration || SCALE_TO_DURATION;
  193. var easing = easing || "ease-out";
  194. self.scaleStart = xscroll.scale || 1;
  195. // transitionStr = [transformStr, " ", duration , "s ", easing, " 0s"].join("");
  196. self._scale(scale, originX, originY);
  197. xscroll._animate("x", "translateX(" + xscroll.x + "px) scale(" + scale + ")", duration, easing, function(e) {
  198. callback && callback.call(self, e);
  199. });
  200. xscroll._animate("y", "translateY(" + xscroll.y + "px)", duration, easing, function(e) {
  201. callback && callback.call(self, e);
  202. });
  203. xscroll.__timers.x.timer.off("run", self.scaleHandler, self);
  204. xscroll.__timers.x.timer.off("stop", self.scaleendHandler, self);
  205. self.scaleHandler = function(e) {
  206. var _scale = (scale - self.scaleStart) * e.percent + self.scaleStart;
  207. //trigger scroll event
  208. self.trigger("scale", {
  209. scale: _scale,
  210. origin: {
  211. x: originX,
  212. y: originY
  213. }
  214. });
  215. };
  216. self.scaleendHandler = function(e) {
  217. self.isScaling = false;
  218. //enable pan gesture
  219. self.enablePan();
  220. self.trigger("scaleend", {
  221. type: "scaleend",
  222. scale: self.scale,
  223. origin: {
  224. x: originX,
  225. y: originY
  226. }
  227. })
  228. }
  229. xscroll.__timers.x.timer.on("run", self.scaleHandler, self);
  230. xscroll.__timers.x.timer.on("stop", self.scaleendHandler, self);
  231. self.trigger("scaleanimate", {
  232. type:"scaleanimate",
  233. scale: xscroll.scale,
  234. duration: duration,
  235. easing: easing,
  236. offset: {
  237. x: xscroll.x,
  238. y: xscroll.y
  239. },
  240. origin: {
  241. x: originX,
  242. y: originY
  243. }
  244. });
  245. }
  246. });
  247. if (typeof module == 'object' && module.exports) {
  248. module.exports = Scale;
  249. }
  250. /** ignored by jsdoc **/
  251. else if (window.XScroll && window.XScroll.Plugins) {
  252. return XScroll.Plugins.Scale = Scale;
  253. }
  254. });