Newer
Older
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
#board {
touch-action: none;
border: 0.5px solid rgba(0, 0, 0, 0.1);
box-shadow: 1px 1px 1px 0.5px rgba(0, 0, 0, 0.1);
cursor: crosshair;
}
</style>
<script type="application/javascript" src="js/main.js"></script>
<script type="application/javascript" src="js/Board.js"></script>
<script type="application/javascript" src="js/Pen.js"></script>
<script type="application/javascript" src="js/Pointer.js"></script>
<script type="application/javascript">
function init() {
Board.init("board");
Pen.init(Board.ctx);
//Pointer.onEmpty = _.debounce(Board.storeMemory.bind(Board), 1500);
// Attach event listener
var pointerDown = function pointerDown(e) {
if (e.pointerType == "pen") {
// Initialise pointer
var pointer = new Pointer(e.pointerId);
pointer.set(Board.getPointerPos(e));
// Get function type
Pen.setFuncType(e);
if (Pen.funcType === Pen.funcTypes.menu) Board.clearMemory();
else drawOnCanvas(e, pointer, Pen);
}
}
var pointerMove = function pointerMove(e) {
if (Pen.funcType && (Pen.funcType.indexOf(Pen.funcTypes.draw) !== -1)) {
var pointer = Pointer.get(e.pointerId);
drawOnCanvas(e, pointer, Pen);
}
}
var pointerCancel = function pointerLeave(e) {
var tension = 0.5;
drawCurve(Board.ctx, strokeData, tension);
Pointer.destruct(e.pointerId);
}
Board.dom.addEventListener('pointerdown', pointerDown);
Board.dom.addEventListener('pointermove', pointerMove);
Board.dom.addEventListener('pointerup', pointerCancel);
Board.dom.addEventListener('pointerleave', pointerCancel);
// Draw method
function drawOnCanvas(e, pointerObj, Pen) {
if (pointerObj) {
pointerObj.set(Board.getPointerPos(e));
Pen.setPen(Board.ctx, e);
if (pointerObj.pos0.x < 0) {
pointerObj.pos0.x = pointerObj.pos1.x - 1;
pointerObj.pos0.y = pointerObj.pos1.y - 1;
}
Board.ctx.beginPath();
Board.ctx.moveTo(pointerObj.pos0.x, pointerObj.pos0.y)
Board.ctx.lineTo(pointerObj.pos1.x, pointerObj.pos1.y);
Board.ctx.closePath();
Board.ctx.stroke();

Andreas Horn
committed
strokeData.push({x: pointerObj.pos1.x, y: pointerObj.pos1.y});
pointerObj.pos0.x = pointerObj.pos1.x;
pointerObj.pos0.y = pointerObj.pos1.y;
}
}
function drawCurve(ctx, ptsa, tension, isClosed, numOfSegments, showPoints) {
ctx.beginPath();
var oldStyle = ctx.strokeStyle;
ctx.strokeStyle = "#FF0000";
ctx.lineWidth = 5;
drawLines(ctx, getCurvePoints(ptsa, tension, isClosed, numOfSegments));
if (showPoints) {
ctx.beginPath();
for (var i = 0; i < ptsa.length - 1; i += 2)
ctx.rect(ptsa[i] - 2, ptsa[i + 1] - 2, 4, 4);
}
ctx.stroke();
ctx.strokeStyle = oldStyle;
}
function getCurvePoints(pts, tension, isClosed, numOfSegments) {
// use input value if provided, or use a default value
tension = (typeof tension != 'undefined') ? tension : 0.5;
isClosed = isClosed ? isClosed : false;
numOfSegments = numOfSegments ? numOfSegments : 16;

Andreas Horn
committed
var _pts = [], res = [], // clone array
x, y, // our x,y coords
t1x, t2x, t1y, t2y, // tension vectors
c1, c2, c3, c4, // cardinal points
st, t, i; // steps based on num. of segments
// clone array so we don't change the original
_pts = pts.slice(0);
// The algorithm require a previous and next point to the actual point array.
// Check if we will draw closed or open curve.
// If closed, copy end points to beginning and first points to end
// If open, duplicate first points to befinning, end points to end
if (isClosed) {
_pts.unshift(pts[pts.length - 1]);
_pts.unshift(pts[pts.length - 1]);
_pts.push(pts[0]);
}
else {

Andreas Horn
committed
_pts.unshift(pts[0]); //copy 1. point and insert at beginning
_pts.push(pts[pts.length - 1]); //copy last point and append
}
// ok, lets start..
// 1. loop goes through point array
// 2. loop goes through each segment between the 2 pts + 1e point before and after

Andreas Horn
committed
for (var i = 1; i < (_pts.length - 2); i++) {
for (var t = 0; t <= numOfSegments; t++) {

Andreas Horn
committed
t1x = (_pts[i + 1].x - _pts[i - 1].x) * tension;
t2x = (_pts[i + 2].x - _pts[i].x) * tension;

Andreas Horn
committed
t1y = (_pts[i + 1].y - _pts[i - 1].y) * tension;
t2y = (_pts[i + 2].y - _pts[i].y) * tension;
// calc step
st = t / numOfSegments;
// calc cardinals
c1 = 2 * Math.pow(st, 3) - 3 * Math.pow(st, 2) + 1;
c2 = -(2 * Math.pow(st, 3)) + 3 * Math.pow(st, 2);
c3 = Math.pow(st, 3) - 2 * Math.pow(st, 2) + st;
c4 = Math.pow(st, 3) - Math.pow(st, 2);
// calc x and y cords with common control vectors

Andreas Horn
committed
x = c1 * _pts[i].x + c2 * _pts[i + 1].x + c3 * t1x + c4 * t2x;
y = c1 * _pts[i].y + c2 * _pts[i + 1].y + c3 * t1y + c4 * t2y;

Andreas Horn
committed
res.push({x: x, y: y});
}
}
return res;
}
function drawLines(ctx, pts) {

Andreas Horn
committed
ctx.moveTo(pts[0].x, pts[0].y);
for (i = 1; i < pts.length - 1; i++) {
ctx.lineTo(pts[i].x, pts[i].y);
}
}
</script>
</head>
<body onload="init();">
<canvas touch-action="none" id="board" width="640" height="640" style="width:320px; height:320px;">
Opps, you cannot play draw N guess with this browser!
</canvas>
<button style="z-index: 9001; position:absolute; top:100px; left: 100px; width: 200px;"
onclick="Board.storeMemory();">save</button>
<button style="z-index: 9001; position:absolute; top:100px; left: 320px; width: 200px;"
onclick="Board.clearMemory();">clear</button>