<!DOCTYPE html>
<html>
<head>
<title>PHPoC</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<meta charset="utf-8">
<style>
body { text-align: center; font-size: width/2pt; }
h1 { font-weight: bold; font-size: width/2pt; }
h2 { font-weight: bold; font-size: width/2pt; }
button {font-weight: bold; font-size: width/2pt;}
</style>
<script>
var width = window.innerWidth - 10;
var ratio = width / 800;
if(ratio > 1)
ratio = 1;
var CMD_AUTH = 0;
var CMD_CTRL = 1;
var ACCESS_ACCEPTED = 0;
var ACCESS_UNAUTHORIZED = 1;
var DOOR_STATE_OPEN = 2;
var DOOR_STATE_CLOSE = 3;
var ws;
var authorized = false;
/* lock variable */
var canvas_width = 800 * ratio;
var canvas_height = 1300 * ratio;
var lock_edge = 40 * ratio;
var pad = 50 * ratio;
var handle_width = 500 * ratio;
var handle_height = 120 * ratio;
var lock_width = (canvas_width - 2 * lock_edge - handle_width) * 2;
var lock_height = canvas_height - 2 * lock_edge;
var pattern_width = lock_width;
var pattern_height = lock_width;
var pattern_inner_radius = 14 * ratio;
var pattern_middle_radius = 22 * ratio;
var pattern_outer_radius = 34 * ratio;
var pattern_gap = lock_width / 3;
var body_width = lock_width;
var body_height = canvas_height - lock_edge * 2 - pattern_height - pad - (handle_width - lock_width / 2);
var knob_center_x = lock_edge + body_width / 2;
var knob_center_y = lock_edge + pattern_height + pad + body_height - body_width / 2;
var touch_x = 0, touch_y = 0;
var pattern_touch_state = 0;
var pattern_touch_list = new Array();
var handle_angle = 0;
var handle_last_angle = 0;
var handle_touch_state = 0;
var mouse_state = "MOUSE_UP";
var is_door_open = false;
function init()
{
var lock = document.getElementById("lock");
lock.width = canvas_width;
lock.height = canvas_height;
lock.addEventListener("touchstart", mouse_down);
lock.addEventListener("touchend", mouse_up);
lock.addEventListener("touchmove", mouse_move);
lock.addEventListener("mousedown", mouse_down);
lock.addEventListener("mouseup", mouse_up);
lock.addEventListener("mousemove", mouse_move);
var ctx = lock.getContext("2d");
ctx.lineCap="round";
ctx.lineJoin="round";
update_view();
var ws_host_addr = "<?echo _SERVER("HTTP_HOST")?>";
if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "["))
{
// network resource identifier to UNC path name conversion
ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
ws_host_addr = ws_host_addr.replace(/:/g, "-");
ws_host_addr += ".ipv6-literal.net";
}
ws = new WebSocket("ws://" + ws_host_addr + "/web_pattern", "text.phpoc");
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
}
function ws_onopen()
{
update_view();
}
function ws_onclose()
{
alert("CANNOT connect to PHPoC!");
ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
authorized = false;
update_view();
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
var resp = parseInt(e_msg.data);
if(resp == ACCESS_ACCEPTED)
authorized = true;
else if(resp == ACCESS_UNAUTHORIZED)
authorized = false;
else if(resp == DOOR_STATE_OPEN)
is_door_open = true;
else if(resp == DOOR_STATE_CLOSE)
{
is_door_open = false;
handle_last_angle = 0;
handle_angle = 0;
}
else
console.log("unknown:" + resp);
update_view();
}
function update_view()
{
var pattern_area = document.getElementById('pattern_area');
var control_area = document.getElementById('control_area');
var lock = document.getElementById("lock");
var ctx = lock.getContext("2d");
ctx.clearRect(0, 0, canvas_width, canvas_height);
// draw boder
ctx.shadowBlur = 10;
ctx.shadowColor = "LightGray";
ctx.fillStyle = "#6A4439";
ctx.beginPath();
ctx.lineTo(0, 0);
ctx.lineTo(body_width + 2 * lock_edge , 0);
ctx.arc(knob_center_x, knob_center_y, body_width / 2 + lock_edge, 0, Math.PI);
ctx.closePath();
ctx.fill();
// draw pattern password background
ctx.fillStyle = "black";
ctx.fillRect(lock_edge, lock_edge, pattern_width, pattern_height);
// draw status indicator
if(authorized)
ctx.fillStyle = "Cyan";
else
ctx.fillStyle = "white";
ctx.fillRect(lock_edge, lock_edge + pattern_height, pattern_width, pad);
ctx.font = "22px Arial"
ctx.textBaseline = "middle";
ctx.textAlign = "center";
ctx.fillStyle = "black";
var text = "";
if(is_door_open)
text += "Openned, ";
else
text += "Closed, ";
if(authorized)
text += "Access permitted!";
else
text += "Access denied!";
ctx.fillText(text, lock_edge + pattern_width / 2, lock_edge + pattern_height + pad / 2);
// draw body background
ctx.fillStyle = "#A07B72";
ctx.beginPath();
ctx.lineTo(lock_edge, lock_edge + pattern_height + pad);
ctx.lineTo(lock_edge + body_width , lock_edge + pattern_height + pad);
ctx.arc(knob_center_x, knob_center_y, body_width / 2, 0, Math.PI);
ctx.closePath();
ctx.fill();
// draw knob
ctx.save();
ctx.translate(knob_center_x, knob_center_y);
if(authorized)
ctx.fillStyle = "Cyan";
else
ctx.fillStyle = "white";
ctx.shadowBlur = 1;
ctx.shadowColor = "black";
ctx.beginPath();
ctx.arc(0, 0, body_width / 2 * 0.8, 0, 2 * Math.PI);
ctx.fill();
ctx.fillStyle = "black";
ctx.shadowBlur = 1;
ctx.shadowColor = "black";
ctx.beginPath();
ctx.arc(0, 0, body_width / 2 * 0.6, 0, 2 * Math.PI);
ctx.fill();
// draw handle
ctx.rotate(handle_angle * Math.PI / 180);
var grd = ctx.createLinearGradient(0, 0, handle_width, 0);
grd.addColorStop(0, "#6A4439");
grd.addColorStop(0.2, "#A07B72");
grd.addColorStop(0.8, "#A07B72");
grd.addColorStop(1, "#6A4439");
ctx.fillStyle = grd;
ctx.shadowBlur = 10;
ctx.shadowColor = "black";
ctx.beginPath();
ctx.arc(0, 0, handle_height / 2, 0.5 * Math.PI, 1.5 * Math.PI);
ctx.arc(handle_width - handle_height / 2 * 0.7, 0, handle_height / 2 * 0.78, 1.5 * Math.PI, 0.5 * Math.PI);
ctx.closePath();
ctx.fill();
ctx.restore();
// draw touched point and line
ctx.save();
ctx.shadowBlur = 20;
ctx.shadowColor = "LightGray";
ctx.lineWidth = 10;
ctx.strokeStyle="white";
ctx.globalAlpha=1;
ctx.beginPath();
ctx.translate(pattern_width/2 + lock_edge, pattern_height/2 + lock_edge);
for (var i = 0; i < pattern_touch_list.length; i++)
{
var temp = pattern_touch_list[i] - 1;
var x = temp % 3 - 1;
var y = Math.floor(temp / 3) - 1;
ctx.lineTo(x*pattern_gap, y*pattern_gap);
}
if(pattern_touch_state)
ctx.lineTo(touch_x, touch_y);
ctx.stroke();
for (var i = 0; i < pattern_touch_list.length; i++)
{
var temp = pattern_touch_list[i] - 1;
var x = temp % 3 - 1;
var y = Math.floor(temp / 3) - 1;
ctx.globalAlpha=0.2;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x*pattern_gap, y*pattern_gap, pattern_outer_radius, 0, 2 * Math.PI);
ctx.fill();
}
// draw base
for(var y = -1; y <= 1; y++)
{
for(var x = -1; x <= 1; x++)
{
ctx.globalAlpha=0.5;
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(x*pattern_gap, y*pattern_gap, pattern_middle_radius, 0, 2 * Math.PI);
ctx.fill();
ctx.globalAlpha=1;
ctx.fillStyle = "Cyan";
ctx.beginPath();
ctx.arc(x*pattern_gap, y*pattern_gap, pattern_inner_radius, 0, 2 * Math.PI);
ctx.fill();
}
}
ctx.restore();
}
function process_event(event)
{
if(event.offsetX)
{
touch_x = event.offsetX;
touch_y = event.offsetY;
}
else if(event.layerX)
{
touch_x = event.layerX;
touch_y = event.layerY;
}
else
{
touch_x = (Math.round(event.touches[0].pageX - event.touches[0].target.offsetLeft));
touch_y = (Math.round(event.touches[0].pageY - event.touches[0].target.offsetTop));
}
if(touch_x > lock_edge && touch_x < (lock_edge + pattern_width) && touch_y > lock_edge && touch_y < (lock_edge + pattern_height))
{ // pattern password area
touch_x -= (lock_edge + pattern_width / 2);
touch_y -= (lock_edge + pattern_height / 2);
for(var i = 1; i <= 9; i++)
{
if(i == pattern_touch_list[pattern_touch_list.length - 1])
continue;
var idx_x = (i-1)%3 - 1;
var idx_y = Math.floor((i-1)/3) - 1;
var knob_center_x = idx_x * pattern_gap;
var knob_center_y = idx_y * pattern_gap;
var dist = Math.sqrt( (touch_x - knob_center_x)*(touch_x - knob_center_x) + (touch_y - knob_center_y)*(touch_y - knob_center_y) );
if(dist < pattern_outer_radius)
{
pattern_touch_list.push(i);
break;
}
}
pattern_touch_state = 1;
}
else
{
pattern_touch_state = 0;
if(!authorized)
return;
var knob_center_x = lock_edge + body_width / 2;
var knob_center_y = lock_edge + pattern_height + pad + body_height - body_width / 2;
touch_x -= knob_center_x;
touch_y -= knob_center_y;
var current_angle = Math.atan2(touch_y, touch_x) * 180 / Math.PI;
/* rotate coordinate */
var radian = -handle_angle / 180 * Math.PI;
var rc_x = touch_x * Math.cos(radian) - touch_y * Math.sin(radian);
var rc_y = touch_x * Math.sin(radian) + touch_y * Math.cos(radian);
if(mouse_state == "MOUSE_DOWN")
{
if(rc_x > (handle_width * 0.3) && rc_x < handle_width && rc_y > (-handle_height / 2) && rc_y < (handle_height / 2))
{
handle_last_angle = current_angle;
handle_touch_state = 1;
}
}
else
if(mouse_state == "MOUSE_MOVE" && handle_touch_state == 1)
{
var angle = current_angle - handle_last_angle;
if((handle_angle + angle) > 0 && (handle_angle + angle) <= 45)
{
handle_angle += angle;
handle_last_angle = current_angle;
if(handle_angle < 30)
send_to_Arduino(CMD_CTRL, 1);
}
}
}
update_view();
}
function mouse_down()
{
if(ws == null)
return;
event.preventDefault();
mouse_state = "MOUSE_DOWN";
process_event(event);
}
function mouse_up()
{
if(ws == null)
return;
event.preventDefault();
if(ws != null && pattern_touch_state)
send_to_Arduino(CMD_AUTH, pattern_touch_list.toString());
pattern_touch_state = 0;
mouse_state = "MOUSE_UP";
pattern_touch_list.splice(0, pattern_touch_list.length);
update_view();
}
function mouse_move()
{
if(ws == null)
return;
event.preventDefault();
mouse_state = "MOUSE_MOVE";
process_event(event);
}
function send_to_Arduino(cmd, data)
{
if(ws.readyState == 1)
{
ws.send(cmd + ":" + data + "\r\n");
}
}
window.onload = init;
</script>
</head>
<body>
<div id="pattern_area" style="display:block;">
<canvas id="lock"></canvas>
</div>
</body>
</html>
Comments
Please log in or sign up to comment.