<!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"> let strokeData = []; 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(); strokeData.push(pointerObj.pos1.x); strokeData.push(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; 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 - 2]); _pts.unshift(pts[pts.length - 1]); _pts.unshift(pts[pts.length - 2]); _pts.push(pts[0]); _pts.push(pts[1]); } else { _pts.unshift(pts[1]); //copy 1. point and insert at beginning _pts.unshift(pts[0]); _pts.push(pts[pts.length - 2]); //copy last point and append _pts.push(pts[pts.length - 1]); } // ok, lets start.. // 1. loop goes through point array // 2. loop goes through each segment between the 2 pts + 1e point before and after for (i = 2; i < (_pts.length - 4); i += 2) { for (t = 0; t <= numOfSegments; t++) { // calc tension vectors t1x = (_pts[i + 2] - _pts[i - 2]) * tension; t2x = (_pts[i + 4] - _pts[i]) * tension; t1y = (_pts[i + 3] - _pts[i - 1]) * tension; t2y = (_pts[i + 5] - _pts[i + 1]) * 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 x = c1 * _pts[i] + c2 * _pts[i + 2] + c3 * t1x + c4 * t2x; y = c1 * _pts[i + 1] + c2 * _pts[i + 3] + c3 * t1y + c4 * t2y; //store points in array res.push(x); res.push(y); } } return res; } function drawLines(ctx, pts) { ctx.moveTo(pts[0], pts[1]); for (i = 2; i < pts.length - 1; i += 2) ctx.lineTo(pts[i], pts[i + 1]); } } </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> </body> </html>