/
**
* blog:
http://www.jcore.cn/
* Created by zjj on 15-1-1.
*/
// 迷宫锁
函数
var MazeLock = (function(global,do
C){
var _canvas,_co
ntext,_circles,_call
BACk,
_isAndroid = navigator.userAgent.match(/android/i),
_isTouch = document.hasOwnProperty("ontouchstart"), // 判断是否
支持手机事件
_touchStart = _isTouch ? 'touchstart' : 'mousedown', // 点击
_touchMove = _isTouch ? 'touchmove' : 'mousemove', // 拖动
_touchEnd = _isTouch ? 'touchend' : 'mouseup'; // 抬起
//
获取画布 Co
ntext
function Co
ntext(con
fig)
{
var _con
fig = con
fig ||
{},
_wrap = _con
fig.wrap;
_canvas = doc.createElement("canvas"
); // 构造canvas
/*
解决某些andriod机重影的bug */
_wrap.style
.overflow = "visible" ;
_wrap.style.webkitTransform = "translateZ(0)";
/* 阻止滑动时屏幕跟随移动 */
_canva
s.addEventListener(_touchMove,function(
E){e.preventDefault(
);}
);
_wrap.appendChild(_canvas
);
return
{
init : function(
BoxSiz
E){
// 初始化画布宽高
_canva
s.width =
BoxSize;
_canva
s.height =
BoxSize;
_co
ntext = _canva
s.getCo
ntext("2d"
);
}
}
}
// 画圆
函数
function Circles(con
fig)
{
var _con
fig = con
fig ||
{},
_circle =
{ // 初始化参数
radius : _con
fig.radius || 30,// 半径
gap : _con
fig.gap || 10,// 间隔
size : _con
fig.size || 3, // 行列个数
lineColor : _con
fig.lineColor || "#46
c017" // 线颜色
},
_radius = _circle.radius, // 半径
_gap = _circle.gap, // 间隔
_size = _circle.size, // 行列个数
_lineColor = _circle.lineColor,// 线颜色
_circles = [],// 圆数组存储
_circlesList = [],// 选中的圆
_radiu
stemp = (_radius + _ga
p),// 单个圆的范围
_
BoxSize = (_radius + _ga
p) * 2 * _size,// 迷宫锁范围大小
_self = this;
/* 基础圆
函数 */
function Circle(x,y,index,hasChoos
E){
return
{ // 圆对象
x : x,// x轴
y : y,// y轴
index : index,// 下标
hasChoose : hasChoose ||
false // 是否选中
};
}
/* 画圆
函数 */
function DrawCircle(index,con
fig)
{
var _con
fig = con
fig ||
{},
_x = _circles[index].x,// 圆X轴
_y = _circles[index].y,// 圆Y轴
_solid = _con
fig.solid ||
false, // 是否实心
_c1 = _con
fig.c1 || "#46
c017",// 圆颜色
_c2 = _con
fig.c2 || "#cbeac0"; // 圆颜色
_co
ntext.globalAlpha
=0.7; // 设置透明度
if(!_solid)
{ // 空心圆
_co
ntext
.beginPath(
);
var x = _circles[index].x;
var y = _circles[index].y;
_co
ntext.arc(x,_radius,Math.PI*2,tru
E);
_co
ntext.lineWidth = 1.0;
_co
ntext.
strokeStyle = "#ffffff";
_co
ntext.
stroke(
);
_co
ntext.closePath(
);
} else
{ // 实心圆
//画外面的圆
_co
ntext
.beginPath(
);
_co
ntext.arc(_x,_y,tru
E);
_co
ntext.fillStyle = _c2;
_co
ntext.lineWidth = 1.0;
_co
ntext.
strokeStyle = _c1;
_co
ntext.fill(
);
_co
ntext.
stroke(
);
_co
ntext.closePath(
);
//画小圆
_co
ntext
.beginPath(
);
_co
ntext.arc(_x,10,tru
E);
_co
ntext.fillStyle = _c1;
_co
ntext.fill(
);
_co
ntext.closePath(
);
}
}
/
**
*
生成一条线连接两个圆
* @param star
Tindex起始圆的位置
* @param endIndex结束圆的位置
*/
function ConnectCircle(star
Tindex,endIndex,color)
{
var _x1 = _circles[star
Tindex].x,
_y1 = _circles[star
Tindex].y,
_x2 = _circles[endIndex].x,
_y2 = _circles[endIndex].y;
_co
ntext
.beginPath(
); // 开始路径绘制
_co
ntext.moveTo(_x1,_y1
);
_co
ntext.lineTo(_x2,_y2
);
_co
ntext.lineWidth = 3.0; // 设置线宽
_co
ntext.
strokeStyle = color || _lineColor ; // 设置线的颜色
_co
ntext.
stroke(
); // 进行线的着色,这时整条线才变得可见
_co
ntext.closePath(
);
}
/
**
* 画正在移动的线
* @param startX 起始点的X
* @param startY 起始点的Y
* @param
posx 结束点的X
* @param
posy 结束点的Y
*/
function DrawMoveLine(startX,startY,
posx,
posy)
{
_co
ntext
.beginPath(
);
_co
ntext.moveTo(startX,startY
);
_co
ntext.lineTo(
posx,
posy);
_co
ntext.lineWidth = 3.0;
_co
ntext.
strokeStyle = _lineColor;
_co
ntext.
stroke(
);
_co
ntext.closePath(
);
}
/* x,y轴是否在圆内,选中返回下标,否则返回 null */
function
checkInCircle(x,y)
{
var col = Math.floor(x / _radiu
stemp / 2
);
var row = Math.floor(y / _radiu
stemp / 2
);
if(col >= _size || row >= _size || col < 0 || row < 0)
{
return null;
}
var circle = _circles[row * _size + col];
if( x <= circle.x + _radius && x >= circle.x - _radius &&
y <= circle.y + _radius && y >= circle.y - _radius
)
{
return circle.index;
}else
{
return null;
}
}
return
{
list : _circles,// 所有圆数组
SELEcted : _circlesList,// 进过选中圆数组
BoxSize : _
BoxSize,// 初始化圆范围
/* 初始化圆
函数 */
init : function()
{
for(var i = 0 ; i < _size ; i++)
{ //rows
for(var j = 0; j < _size ; j++)
{ //cols
var x = _radiu
stemp + j * _radiu
stemp * 2,
y = _radiu
stemp + i * _radiu
stemp * 2,
index = _circle
s.length;
_circle
s.push(Circle(x,inde
X));
DrawCircle(inde
X);
}
}
},
/* 是否在圆的范围之内
函数 */
checkInCircle :
checkInCircle,
DrawMoveLine : DrawMoveLine,
DrawClearCircle : function()
{
clearCanvas(
); // 清空画布
for(var i = 0; i< _circle
s.length ; i++)
{
_circles[i].hasChoose =
false;
DrawCircle(_circles[i].inde
X); // 重新画空心圆
}
thi
s.SELEcted = []; // 清空选中格子
},
Draw
successCircle : function()
{
clearCanvas(
); // 清空画布
for(var i = 0 ; i < _circle
s.length; i++)
{ // 画正确圆
DrawCircle(i,_circles[i].hasChoose ?
{ solid : true } :
null);
}
for(var i = 0 ; i < thi
s.SELEcted.length - 1; i++)
{ // 画正确圆循环连接线
connectCircle(thi
s.SELEcted[i],thi
s.SELEcted[i+1]
);
}
},
DrawErrorCircle : function(call
BACk)
{
clearCanvas(
); // 清空画布
for(var i = 0 ; i < _circle
s.length; i++)
{ // 画
错误圆
DrawCircle(i,_circles[i].hasChoose ?
{ solid : true,c1: '#f7574b',c2: '#f8d0cd' } :
null);
}
for(var i = 0 ; i < thi
s.SELEcted.length - 1; i++)
{ // 画
错误圆循环连接线
connectCircle(thi
s.SELEcted[i],thi
s.SELEcted[i+1],'#f7574b'
);
}
if(call
BACk) call
BACk(
);
}
}
}
/
**
* 捕捉坐标
函数
* @param element 触摸节点对象
* @returns
{{x: null,y: null,isPressed:
Boolean,event: null}}
*/
function CapturesCoord(element)
{
var body_scrollLeft = doc
.body.scrollLeft,// body左滚动位置
body_scrollTop = doc
.body.scrollTop, // body上滚动位置
element_scrollLeft = doc.documentElement.scrollLeft,// 节点左滚动位置
element_scrollTop = doc.documentElement.scrollTop, // 节点上滚动位置
offsetLeft = element
.offsetLeft,// 节点左移动位置
offsetTop = element
.offsetTop; // 节点上移动位置
function Coord(x,isPressed,isMove,event)
{
return
{
x: x || null,// x轴
y: y || null,// y轴
isPressed: isPressed ||
false,// 是否点击
isMove: isMove ||
false,// 是否移动
event: event || null // 目标事件
}
}
/* 点击坐标
函数 */
function StartCoord(event)
{
var coord = new Coord(
);
var _coord = GetCoord(event
);
coord.isPressed = true;
coord.x = _coord.x;
coord.y = _coord.y;
coord.event = event;
return coord;
}
/* 结束坐标
函数 */
function EndCoord(event)
{
var coord = new Coord(
);
coord.isPressed =
false;
coord.isMove =
false;
coord.x = null;
coord.y = null;
coord.event = event;
return coord;
}
/* 移动坐标
函数 */
function MoveCoord(event)
{
var coord = new Coord(
);
var _coord = GetCoord(event
);
coord.isMove = true;
coord.x = _coord.x;
coord.y = _coord.y;
coord.event = event;
return coord;
}
/*
获取坐标 */
function GetCoord(event)
{
var x,_event = _isTouch ? event.touches
[0] : event;
if (_event.pageX || _event.pageY)
{
x = _event.pageX;
y = _event.pageY;
} else
{
x = _event.clientX + body_scrollLeft + element_scrollLeft;
y = _event.clientY + body_scrollTop + element_scrollTop;
}
x -= offsetLeft;
y -= offsetTop;
return
{ x : x,y : y }
}
/* 返回当前坐标
函数 */
return
{
StartCoord : StartCoord,
MoveCoord : MoveCoord,
EndCoord : EndCoord
};
};
/* 监听事件 */
function Listeners(element)
{
var _capturesCoord = new CapturesCoord(element),// 坐标
函数
_point =
{},// 临时点
函数
_drawing =
false; // 是否选中
/* 点击事件监听器 */
function StartListener(event)
{
event.preventDefault(
);
if(_drawing) return;
log("start..."
);
var _coord = _capturesCoord.StartCoord(event
);
_point = _coord;
var _index = _circle
s.checkInCircle(_coord.x,_coord.y
);
if(_index
!==null)
{
_drawing = true;
var _circlesList = _circle
s.list[_index];
_circle
s.SELEcted.push(_inde
X);
_circlesList.hasChoose = true;
_circle
s.Draw
successCircle(
);
}
//
添加移动和离开事件
element.addEventListener(_touchMove,MoveListener,
fals
E);
element.addEventListener(_touchEnd, EndListener,
fals
E);
}
/* 拖动事件监听器 */
function MoveListener(event)
{
event.preventDefault(
);
if(!_drawing) return;
log("move..."
);
var _coord = _capturesCoord.MoveCoord(event
);
var _index = _circle
s.checkInCircle(_coord.x,_coord.y
);
_circle
s.Draw
successCircle(
);
var _circlesList = _circle
s.list[_index];
if(_index===null || _circlesList.hasChoos
E){
var _startX = _point.x,
_startY = _point.y,
_
posx = _coord.x,
_
posy = _coord.y;
_circle
s.DrawMoveLine(_startX,_startY,_
posx,_
posy);
}else
{
_point["x"] = _circlesList.x;
_point["y"] = _circlesList.y;
_circle
s.SELEcted.push(_inde
X);
_circlesList.hasChoose = true;
}
}
/* 离开事件监听器 */
function EndListener(event)
{
event.preventDefault(
);
if(!_drawing) return;
log("end..."
);
_capturesCoor
d.endCoord(event
);
_call
BACk(_circle
s.SELEcted
);
_drawing =
false;
// 移除移动和离开事件
element.removeEventListener(_touchMove,
fals
E);
element.removeEventListener(_touchEnd,
fals
E);
}
/* 返回监听
函数 */
return
{
StartListener : StartListener,
MoveListener : MoveListener,
EndListener : EndListener
}
}
/
**
* 清空canvas画布的
内容
*/
function clearCanvas()
{
_co
ntext.clearRect(0,_canva
s.width,_canva
s.height
);
if( _isAndroid )
{ /* 安卓下clearRect无效时的hack */
_canva
s.style.display = 'none';// Detach from DOM
_canva
s.offsetHeight; // Force the detach
_canva
s.style.display = 'inherit'; // Reattach to DOM
}
}
/
**
* 简易日志
函数
* @param infoStr 日志字符串
*/
function Log( infoStr )
{
//console.log( infoStr
);
}
// 返回
函数体
return function(con
fig)
{
var _con
fig = con
fig ||
{},
_wrap = _con
fig.wrap || doc.query
SELEctor("body"),
_co
ntext = new Co
ntext(
{ wrap : _wrap}),
_listeners = new Listeners(_canvas
);
_call
BACk = _con
fig.call
BACk || function()
{}
_circles = new Circles(
{
radius : _con
fig.radius, // 半径
gap : _con
fig.gap, // 间隔
size : _con
fig.size // 行列个数
})
return
{
init : function()
{
_co
ntext.init(_circle
s.BoxSiz
E)
_circle
s.init(
);
_canva
s.addEventListener(_touchStart,_listener
s.StartListener,
fals
E); // 绑定点击事件
},
drawClearPanel : function()
{
_circle
s.DrawClearCircle(
);
},
drawErrorPanel : function()
{
_circle
s.DrawErrorCircle(function()
{
setTimeout(function()
{
_circle
s.DrawClearCircle(
);
},300
);
}
);
},
clearCanvas : function()
{
clearCanvas(
);
//
删除画布事件
_canva
s.removeEventListener(_touchStart,
fals
E);
_canva
s.removeEventListener(_touchMove, _listener
s.MoveListener,
fals
E);
_canva
s.removeEventListener(_touchEnd, _listener
s.EndListener,
fals
E);
}
}
}
@H_
674_493@})(window,document
);
@H_
674_493@核心类库
@H_
674_493@
调用方式
@H_
674_493@<script type="text/javascript">
var count = 0,
mazeLock = new MazeLock(
{ wrap : document.query
SELEctor("#wrap"),
radius : 30,
gap : 22,
size : 3,
call
BACk : function
(SELEcted)
{ var msg = document.query
SELEctor("#msg"
); if
(SELEcted.join(",")=="0,4,8,7,6")
{ mazeLock.clearCanvas(
); msg.innerHTML = "成功";
setTimeout(function()
{ window.
LOCATIOn.href = "
http://www.jcore.cn/"
},1000
); }else
{ //mazeLock.drawClearPanel(
); mazeLock.drawErrorPanel(
); msg.innerHTML = "<span style='color: red;'>
错误 " +(++count)+ "
次数</span>";
}
}
}
); mazeLock.init(
); console.log(mazeLock
); </script>
@H_
674_493@body 的 css
@H_
674_493@
<style type="text/css">
body
{ -webkit-touch-callout: none;
-moz-touch-callout: none;
-ms-touch-callout: none;
-o-touch-callout: none;
touch-callout: none;
-webkit-user-
SELEct: none;
-moz-user-
SELEct: none;
-ms-user-
SELEct: none;
-o-user-
SELEct: none;
user-
SELEct: none;
}
</style>
@H_
674_493@密码背景
@H_
674_493@div.phone
{ width: 300px;
height: 300px;
position: absolute;
overflow: hidden;
BACkground: url(../images/bg.png) no-repeat;
}
@H_
674_493@原
文章
@H_
674_493@
http://www.jcore.cn/
resources/demo/2015/01/01/unlock/index.html