You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

303 lines
9.9 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

/**
* 手势锁屏插件
* 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 += "<style>.mui-locker-holder{overflow:hidden;position:relative;padding:0px;}.mui-locker-holder canvas{width:100%;height:100%;}</style>";
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 = '<canvas></canvas>';
//
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));