/** * 手势锁屏插件 * varstion 1.0.5 * by Houfeng * Houfeng@DCloud.io */ (function($, doc) { var touchSupport = ('ontouchstart' in document); var startEventName = touchSupport ? $.EVENT_START : 'mousedown'; var moveEventName = touchSupport ? $.EVENT_MOVE : 'mousemove'; var endEventName = touchSupport ? $.EVENT_END : 'mouseup'; var lockerHolderClassName = $.className('locker-holder'); var lockerClassName = $.className('locker'); var styleHolder = doc.querySelector('head') || doc.querySelector('body'); styleHolder.innerHTML += ""; var times = 2; function getElementLeft(element) {     var actualLeft = element.offsetLeft;     var current = element.offsetParent;     while (current !== null) {       actualLeft += current.offsetLeft;       current = current.offsetParent;     }     return actualLeft;   }   function getElementTop(element) {     var actualTop = element.offsetTop;     var current = element.offsetParent;     while (current !== null) {       actualTop += current.offsetTop;       current = current.offsetParent;     }     return actualTop;   } //定义 Locker 类 var Locker = $.Locker = $.Class.extend({ R: 26, CW: 400, CH: 320, OffsetX: 30, OffsetY: 30, /** * 构造函数 * */ init: function(holder, options) { var self = this; if (!holder) { throw "构造 Locker 时缺少容器元素"; } self.holder = holder; // options = options || {}; options.callback = options.callback || options.done || $.noop; options.times = options.times || times; self.options = options; self.holder.innerHTML = ''; // self.holder.classList.add(lockerHolderClassName); //初始化 var canvas = self.canvas = $.qsa('canvas', self.holder)[0]; canvas.on = canvas.addEventListener || function(name, handler, capture) { canvas.attachEvent('on' + name, handler, capture); }; canvas.off = canvas.removeEventListener || function(name, handler, capture) { canvas.detachEvent('on' + name, handler, capture); }; // if (self.options.width) self.holder.style.width = self.options.width + 'px'; if (self.options.height) self.holder.style.height = self.options.height + 'px'; self.CW = self.options.width || self.holder.offsetWidth || self.CW; self.CH = self.options.height || self.holder.offsetHeight || self.CH; //处理 “宽、高” 等数值, 全部扩大 times 倍 self.R *= self.options.times; self.CW *= self.options.times; self.CH *= self.options.times; self.OffsetX *= self.options.times; self.OffsetY *= self.options.times; // canvas.width = self.CW; canvas.height = self.CH; var cxt = self.cxt = canvas.getContext("2d"); //两个圆之间的外距离 就是说两个圆心的距离去除两个半径 var X = (self.CW - 2 * self.OffsetX - self.R * 2 * 3) / 2; var Y = (self.CH - 2 * self.OffsetY - self.R * 2 * 3) / 2; self.pointLocationArr = self.caculateNinePointLotion(X, Y); self.initEvent(canvas, cxt, self.holder); //console.log(X); self.draw(cxt, self.pointLocationArr, [], null); setTimeout(function() { self.draw(cxt, self.pointLocationArr, [], null); }, 0); }, /** * 计算 */ caculateNinePointLotion: function(diffX, diffY) { var self = this; var Re = []; for (var row = 0; row < 3; row++) { for (var col = 0; col < 3; col++) { var Point = { X: (self.OffsetX + col * diffX + (col * 2 + 1) * self.R), Y: (self.OffsetY + row * diffY + (row * 2 + 1) * self.R) }; Re.push(Point); } } return Re; }, /** * 绘制 */ draw: function(cxt, _PointLocationArr, _LinePointArr, touchPoint) { var self = this; var R = self.R; if (_LinePointArr.length > 0) { cxt.beginPath(); for (var i = 0; i < _LinePointArr.length; i++) { var pointIndex = _LinePointArr[i]; cxt.lineTo(_PointLocationArr[pointIndex].X, _PointLocationArr[pointIndex].Y); } cxt.lineWidth = (self.options.lindeWidth || 2) * self.options.times; cxt.strokeStyle = self.options.lineColor || "#999"; //连结线颜色 cxt.stroke(); cxt.closePath(); if (touchPoint != null) { var lastPointIndex = _LinePointArr[_LinePointArr.length - 1]; var lastPoint = _PointLocationArr[lastPointIndex]; cxt.beginPath(); cxt.moveTo(lastPoint.X, lastPoint.Y); cxt.lineTo(touchPoint.X, touchPoint.Y); cxt.stroke(); cxt.closePath(); } } for (var i = 0; i < _PointLocationArr.length; i++) { var Point = _PointLocationArr[i]; cxt.fillStyle = self.options.ringColor || "#888"; //圆圈边框颜色 cxt.beginPath(); cxt.arc(Point.X, Point.Y, R, 0, Math.PI * 2, true); cxt.closePath(); cxt.fill(); cxt.fillStyle = self.options.fillColor || "#f3f3f3"; //圆圈填充颜色 cxt.beginPath(); cxt.arc(Point.X, Point.Y, R - ((self.options.ringWidth || 2) * self.options.times), 0, Math.PI * 2, true); cxt.closePath(); cxt.fill(); if (_LinePointArr.indexOf(i) >= 0) { cxt.fillStyle = self.options.pointColor || "#777"; //圆圈中心点颜色 cxt.beginPath(); cxt.arc(Point.X, Point.Y, R - ((self.options.pointWidth || 16) * self.options.times), 0, Math.PI * 2, true); cxt.closePath(); cxt.fill(); } } }, isPointSelect: function(touches, linePoint) { var self = this; for (var i = 0; i < self.pointLocationArr.length; i++) { var currentPoint = self.pointLocationArr[i]; var xdiff = Math.abs(currentPoint.X - touches.elementX); var ydiff = Math.abs(currentPoint.Y - touches.elementY); var dir = Math.pow((xdiff * xdiff + ydiff * ydiff), 0.5); if (dir < self.R) { if (linePoint.indexOf(i) < 0) { linePoint.push(i); } break; } } }, initEvent: function(canvas, cxt, holder) { var self = this; var linePoint = []; var isDown = false; //针对鼠标事件 //start self._startHandler = function(e) { e.point = event.changedTouches ? event.changedTouches[0] : event; e.point.elementX = (e.point.pageX - getElementLeft(holder)) * self.options.times; e.point.elementY = (e.point.pageY - getElementTop(holder)) * self.options.times; self.isPointSelect(e.point, linePoint); isDown = true; }; canvas.on(startEventName, self._startHandler, false); //move self._moveHanlder = function(e) { if (!isDown) return; e.preventDefault(); e.point = event.changedTouches ? event.changedTouches[0] : event; e.point.elementX = (e.point.pageX - getElementLeft(holder)) * self.options.times; e.point.elementY = (e.point.pageY - getElementTop(holder)) * self.options.times; var touches = e.point; self.isPointSelect(touches, linePoint); cxt.clearRect(0, 0, self.CW, self.CH); self.draw(cxt, self.pointLocationArr, linePoint, { X: touches.elementX, Y: touches.elementY }); }; canvas.on(moveEventName, self._moveHanlder, false); //end self._endHandler = function(e) { e.point = event.changedTouches ? event.changedTouches[0] : event; e.point.elementX = (e.point.pageX - getElementLeft(holder)) * self.options.times; e.point.elementY = (e.point.pageY - getElementTop(holder)) * self.options.times; cxt.clearRect(0, 0, self.CW, self.CH); self.draw(cxt, self.pointLocationArr, linePoint, null); //事件数据 var eventData = { sender: self, points: linePoint }; /* * 回调完成事件 * * 备注: * 比较理想的做法是为 Locker 的实例启用事件机制,比如 locker.on('done',handler); * 在 mui 没有完整的公共事件模块前,此版本中 locker 实例暂通过 options.callback 处理 */ self.options.callback(eventData); //触发声明的DOM的自定义事件(暂定 done 为事件名,可以考虑更有针对的事件名 ) $.trigger(self.holder, 'done', eventData); //- linePoint = []; isDown = false; }; canvas.on(endEventName, self._endHandler, false); }, pointLocationArr: [], /** * 清除图形 * */ clear: function() { var self = this; //self.pointLocationArr = []; if (self.cxt) { self.cxt.clearRect(0, 0, self.CW, self.CH); self.draw(self.cxt, self.pointLocationArr, [], { X: 0, Y: 0 }); } }, /** * 释放资源 * */ dispose: function() { var self = this; self.cxt = null; self.canvas.off(startEventName, self._startHandler); self.canvas.off(moveEventName, self._moveHandler); self.canvas.off(endEventName, self._endHandler); self.holder.innerHTML = ''; self.canvas = null; } }); //添加 locker 插件 $.fn.locker = function(options) { //遍历选择的元素 this.each(function(i, element) { if (element.locker) return; if (options) { element.locker = new Locker(element, options); } else { var optionsText = element.getAttribute('data-locker-options'); var _options = optionsText ? JSON.parse(optionsText) : {}; _options.lineColor = element.getAttribute('data-locker-line-color') || _options.lineColor; _options.ringColor = element.getAttribute('data-locker-ring-color') || _options.ringColor; _options.fillColor = element.getAttribute('data-locker-fill-color') || _options.fillColor; _options.pointColor = element.getAttribute('data-locker-point-color') || _options.pointColor; _options.width = element.getAttribute('data-locker-width') || _options.width; _options.height = element.getAttribute('data-locker-height') || _options.height; element.locker = new Locker(element, _options); } }); return this[0] ? this[0].locker : null; }; //自动处理 class='mui-locker' 的 dom try { $('.' + lockerClassName).locker(); } catch (ex) {} $.ready(function() { $('.' + lockerClassName).locker(); }); }(mui, document));