濮阳12345web

mui.locker.js 9.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /**
  2. * 手势锁屏插件
  3. * varstion 1.0.5
  4. * by Houfeng
  5. * Houfeng@DCloud.io
  6. */
  7. (function($, doc) {
  8. var touchSupport = ('ontouchstart' in document);
  9. var startEventName = touchSupport ? 'touchstart' : 'mousedown';
  10. var moveEventName = touchSupport ? 'touchmove' : 'mousemove';
  11. var endEventName = touchSupport ? 'touchend' : 'mouseup';
  12. var lockerHolderClassName = $.className('locker-holder');
  13. var lockerClassName = $.className('locker');
  14. var styleHolder = doc.querySelector('head') || doc.querySelector('body');
  15. styleHolder.innerHTML += "<style>.mui-locker-holder{overflow:hidden;position:relative;padding:0px;}.mui-locker-holder canvas{width:100%;height:100%;}</style>";
  16. var times = 4;
  17. function getElementLeft(element) {    
  18. var actualLeft = element.offsetLeft;    
  19. var current = element.offsetParent;    
  20. while (current !== null) {      
  21. actualLeft += current.offsetLeft;      
  22. current = current.offsetParent;    
  23. }    
  24. return actualLeft;  
  25. }  
  26. function getElementTop(element) {    
  27. var actualTop = element.offsetTop;    
  28. var current = element.offsetParent;    
  29. while (current !== null) {      
  30. actualTop += current.offsetTop;      
  31. current = current.offsetParent;    
  32. }    
  33. return actualTop;  
  34. }
  35. //定义 Locker 类
  36. var Locker = $.Locker = $.Class.extend({
  37. R: 26,
  38. CW: 400,
  39. CH: 320,
  40. OffsetX: 30,
  41. OffsetY: 30,
  42. /**
  43. * 构造函数
  44. * */
  45. init: function(holder, options) {
  46. var self = this;
  47. if (!holder) {
  48. throw "构造 Locker 时缺少容器元素";
  49. }
  50. self.holder = holder;
  51. //避免重复初始化开始
  52. if (self.holder.__locker_inited) return;
  53. self.holder.__locker_inited = true;
  54. //避免重复初始化结束
  55. //
  56. self.options = options || {};
  57. self.options.callback = self.options.callback || self.options.done || $.noop;
  58. self.holder.innerHTML = '<canvas></canvas>';
  59. //
  60. self.holder.classList.add(lockerHolderClassName);
  61. //初始化
  62. var canvas = self.canvas = $.qsa('canvas', self.holder)[0];
  63. canvas.on = canvas.addEventListener || function(name, handler, capture) {
  64. canvas.attachEvent('on' + name, handler, capture);
  65. };
  66. canvas.off = canvas.removeEventListener || function(name, handler, capture) {
  67. canvas.detachEvent('on' + name, handler, capture);
  68. };
  69. //
  70. if (self.options.width) self.holder.style.width = self.options.width + 'px';
  71. if (self.options.height) self.holder.style.height = self.options.height + 'px';
  72. self.CW = self.options.width || self.holder.offsetWidth || self.CW;
  73. self.CH = self.options.height || self.holder.offsetHeight || self.CH;
  74. //处理 “宽、高” 等数值, 全部扩大 times 倍
  75. self.R *= times;
  76. self.CW *= times;
  77. self.CH *= times;
  78. self.OffsetX *= times;
  79. self.OffsetY *= times;
  80. //
  81. canvas.width = self.CW;
  82. canvas.height = self.CH;
  83. var cxt = self.cxt = canvas.getContext("2d");
  84. //两个圆之间的外距离 就是说两个圆心的距离去除两个半径
  85. var X = (self.CW - 2 * self.OffsetX - self.R * 2 * 3) / 2;
  86. var Y = (self.CH - 2 * self.OffsetY - self.R * 2 * 3) / 2;
  87. self.pointLocationArr = self.caculateNinePointLotion(X, Y);
  88. self.initEvent(canvas, cxt, self.holder);
  89. //console.log(X);
  90. self.draw(cxt, self.pointLocationArr, [], null);
  91. setTimeout(function() {
  92. self.draw(cxt, self.pointLocationArr, [], null);
  93. }, 0);
  94. },
  95. /**
  96. * 计算
  97. */
  98. caculateNinePointLotion: function(diffX, diffY) {
  99. var self = this;
  100. var Re = [];
  101. for (var row = 0; row < 3; row++) {
  102. for (var col = 0; col < 3; col++) {
  103. var Point = {
  104. X: (self.OffsetX + col * diffX + (col * 2 + 1) * self.R),
  105. Y: (self.OffsetY + row * diffY + (row * 2 + 1) * self.R)
  106. };
  107. Re.push(Point);
  108. }
  109. }
  110. return Re;
  111. },
  112. /**
  113. * 绘制
  114. */
  115. draw: function(cxt, _PointLocationArr, _LinePointArr, touchPoint) {
  116. var self = this;
  117. var R = self.R;
  118. if (_LinePointArr.length > 0) {
  119. cxt.beginPath();
  120. for (var i = 0; i < _LinePointArr.length; i++) {
  121. var pointIndex = _LinePointArr[i];
  122. cxt.lineTo(_PointLocationArr[pointIndex].X, _PointLocationArr[pointIndex].Y);
  123. }
  124. cxt.lineWidth = 2 * times;
  125. cxt.strokeStyle = self.options.lineColor || "#999"; //连结线颜色
  126. cxt.stroke();
  127. cxt.closePath();
  128. if (touchPoint != null) {
  129. var lastPointIndex = _LinePointArr[_LinePointArr.length - 1];
  130. var lastPoint = _PointLocationArr[lastPointIndex];
  131. cxt.beginPath();
  132. cxt.moveTo(lastPoint.X, lastPoint.Y);
  133. cxt.lineTo(touchPoint.X, touchPoint.Y);
  134. cxt.stroke();
  135. cxt.closePath();
  136. }
  137. }
  138. for (var i = 0; i < _PointLocationArr.length; i++) {
  139. var Point = _PointLocationArr[i];
  140. cxt.fillStyle = self.options.ringColor || "#888"; //圆圈边框颜色
  141. cxt.beginPath();
  142. cxt.arc(Point.X, Point.Y, R, 0, Math.PI * times, true);
  143. cxt.closePath();
  144. cxt.fill();
  145. cxt.fillStyle = self.options.fillColor || "#f3f3f3"; //圆圈填充颜色
  146. cxt.beginPath();
  147. cxt.arc(Point.X, Point.Y, R - (2 * times), 0, Math.PI * times, true);
  148. cxt.closePath();
  149. cxt.fill();
  150. if (_LinePointArr.indexOf(i) >= 0) {
  151. cxt.fillStyle = self.options.pointColor || "#777"; //圆圈中心点颜色
  152. cxt.beginPath();
  153. cxt.arc(Point.X, Point.Y, R - (16 * times), 0, Math.PI * times, true);
  154. cxt.closePath();
  155. cxt.fill();
  156. }
  157. }
  158. },
  159. isPointSelect: function(touches, linePoint) {
  160. var self = this;
  161. for (var i = 0; i < self.pointLocationArr.length; i++) {
  162. var currentPoint = self.pointLocationArr[i];
  163. var xdiff = Math.abs(currentPoint.X - touches.elementX);
  164. var ydiff = Math.abs(currentPoint.Y - touches.elementY);
  165. var dir = Math.pow((xdiff * xdiff + ydiff * ydiff), 0.5);
  166. if (dir < self.R) {
  167. if (linePoint.indexOf(i) < 0) {
  168. linePoint.push(i);
  169. }
  170. break;
  171. }
  172. }
  173. },
  174. initEvent: function(canvas, cxt, holder) {
  175. var self = this;
  176. var linePoint = [];
  177. var isDown = false; //针对鼠标事件
  178. //start
  179. self._startHandler = function(e) {
  180. e.point = event.changedTouches ? event.changedTouches[0] : event;
  181. e.point.elementX = (e.point.pageX - getElementLeft(holder)) * times;
  182. e.point.elementY = (e.point.pageY - getElementTop(holder)) * times;
  183. self.isPointSelect(e.point, linePoint);
  184. isDown = true;
  185. };
  186. canvas.on(startEventName, self._startHandler, false);
  187. //move
  188. self._moveHanlder = function(e) {
  189. if (!isDown) return;
  190. e.preventDefault();
  191. e.point = event.changedTouches ? event.changedTouches[0] : event;
  192. e.point.elementX = (e.point.pageX - getElementLeft(holder)) * times;
  193. e.point.elementY = (e.point.pageY - getElementTop(holder)) * times;
  194. var touches = e.point;
  195. self.isPointSelect(touches, linePoint);
  196. cxt.clearRect(0, 0, self.CW, self.CH);
  197. self.draw(cxt, self.pointLocationArr, linePoint, {
  198. X: touches.elementX,
  199. Y: touches.elementY
  200. });
  201. };
  202. canvas.on(moveEventName, self._moveHanlder, false);
  203. //end
  204. self._endHandler = function(e) {
  205. e.point = event.changedTouches ? event.changedTouches[0] : event;
  206. e.point.elementX = (e.point.pageX - getElementLeft(holder)) * times;
  207. e.point.elementY = (e.point.pageY - getElementTop(holder)) * times;
  208. cxt.clearRect(0, 0, self.CW, self.CH);
  209. self.draw(cxt, self.pointLocationArr, linePoint, null);
  210. //事件数据
  211. var eventData = {
  212. sender: self,
  213. points: linePoint
  214. };
  215. /*
  216. * 回调完成事件
  217. *
  218. * 备注:
  219. * 比较理想的做法是为 Locker 的实例启用事件机制,比如 locker.on('done',handler);
  220. * 在 mui 没有完整的公共事件模块前,此版本中 locker 实例暂通过 options.callback 处理
  221. */
  222. self.options.callback(eventData);
  223. //触发声明的DOM的自定义事件(暂定 done 为事件名,可以考虑更有针对的事件名 )
  224. $.trigger(self.holder, 'done', eventData);
  225. //-
  226. linePoint = [];
  227. isDown = false;
  228. };
  229. canvas.on(endEventName, self._endHandler, false);
  230. },
  231. pointLocationArr: [],
  232. /**
  233. * 清除图形
  234. * */
  235. clear: function() {
  236. var self = this;
  237. //self.pointLocationArr = [];
  238. if (self.cxt) {
  239. self.cxt.clearRect(0, 0, self.CW, self.CH);
  240. self.draw(self.cxt, self.pointLocationArr, [], {
  241. X: 0,
  242. Y: 0
  243. });
  244. }
  245. },
  246. /**
  247. * 释放资源
  248. * */
  249. dispose: function() {
  250. var self = this;
  251. self.cxt = null;
  252. self.canvas.off(startEventName, self._startHandler);
  253. self.canvas.off(moveEventName, self._moveHandler);
  254. self.canvas.off(endEventName, self._endHandler);
  255. self.holder.innerHTML = '';
  256. self.canvas = null;
  257. }
  258. });
  259. //添加 locker 插件
  260. $.fn.locker = function(options) {
  261. //遍历选择的元素
  262. this.each(function(i, element) {
  263. if (options) {
  264. new Locker(element, options);
  265. } else {
  266. var optionsText = element.getAttribute('data-locker-options');
  267. var options = optionsText ? JSON.parse(optionsText) : {};
  268. options.lineColor = element.getAttribute('data-locker-line-color') || options.lineColor;
  269. options.ringColor = element.getAttribute('data-locker-ring-color') || options.ringColor;
  270. options.fillColor = element.getAttribute('data-locker-fill-color') || options.fillColor;
  271. options.pointColor = element.getAttribute('data-locker-point-color') || options.pointColor;
  272. options.width = element.getAttribute('data-locker-width') || options.width;
  273. options.height = element.getAttribute('data-locker-height') || options.height;
  274. new Locker(element, options);
  275. }
  276. });
  277. return this;
  278. };
  279. //自动处理 class='mui-locker' 的 dom
  280. try {
  281. $('.' + lockerClassName).locker();
  282. } catch (ex) {}
  283. $.ready(function() {
  284. $('.' + lockerClassName).locker();
  285. });
  286. }(mui, document));