Last active
July 19, 2024 12:42
-
-
Save bencentra/91350fe91c377c1ca574 to your computer and use it in GitHub Desktop.
Example of using HTML5 canvas with both mouse and (single) touch input
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE HTML> | |
<html> | |
<head> | |
<meta charset="utf-8"> | |
<meta http-equiv="X-UA-Compatible" content="IE=edge"> | |
<meta name="viewport" content="width=device-width, initial-scale=1"> | |
<meta name="description" content=""> | |
<meta name="keywords" content=""> | |
<meta name="author" content=""> | |
<title>E-Signature</title> | |
<!-- Styles --> | |
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css"> | |
<style> | |
body { | |
padding-top: 20px; | |
padding-bottom: 20px; | |
} | |
#sig-canvas { | |
border: 2px dotted #CCCCCC; | |
border-radius: 5px; | |
cursor: crosshair; | |
} | |
#sig-dataUrl { | |
width: 100%; | |
} | |
</style> | |
</head> | |
<body> | |
<!-- Content --> | |
<div class="container"> | |
<div class="row"> | |
<div class="col-md-12"> | |
<h1>E-Signature</h1> | |
<p>Sign in the canvas below and save your signature as an image!</p> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-12"> | |
<canvas id="sig-canvas" width="620" height="160"> | |
Get a better browser, bro. | |
</canvas> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-12"> | |
<button class="btn btn-primary" id="sig-submitBtn"> | |
Submit Signature | |
</button> | |
<button class="btn btn-default" id="sig-clearBtn"> | |
Clear Signature | |
</button> | |
</div> | |
</div> | |
<br/> | |
<div class="row"> | |
<div class="col-md-12"> | |
<textarea id="sig-dataUrl" class="form-control" rows="5"> | |
Data URL for your signature will go here! | |
</textarea> | |
</div> | |
</div> | |
<br/> | |
<div class="row"> | |
<div class="col-md-12"> | |
<img id="sig-image" src="" alt="Your signature will go here!"/> | |
</div> | |
</div> | |
</div> | |
<!-- Scripts --> | |
<script src="https://code.jquery.com/jquery-2.1.0.min.js"></script> | |
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script> | |
<!--<script src="https://code.angularjs.org/snapshot/angular.min.js"></script>--> | |
<script> | |
(function() { | |
// Get a regular interval for drawing to the screen | |
window.requestAnimFrame = (function (callback) { | |
return window.requestAnimationFrame || | |
window.webkitRequestAnimationFrame || | |
window.mozRequestAnimationFrame || | |
window.oRequestAnimationFrame || | |
window.msRequestAnimaitonFrame || | |
function (callback) { | |
window.setTimeout(callback, 1000/60); | |
}; | |
})(); | |
// Set up the canvas | |
var canvas = document.getElementById("sig-canvas"); | |
var ctx = canvas.getContext("2d"); | |
ctx.strokeStyle = "#222222"; | |
ctx.lineWith = 2; | |
// Set up the UI | |
var sigText = document.getElementById("sig-dataUrl"); | |
var sigImage = document.getElementById("sig-image"); | |
var clearBtn = document.getElementById("sig-clearBtn"); | |
var submitBtn = document.getElementById("sig-submitBtn"); | |
clearBtn.addEventListener("click", function (e) { | |
clearCanvas(); | |
sigText.innerHTML = "Data URL for your signature will go here!"; | |
sigImage.setAttribute("src", ""); | |
}, false); | |
submitBtn.addEventListener("click", function (e) { | |
var dataUrl = canvas.toDataURL(); | |
sigText.innerHTML = dataUrl; | |
sigImage.setAttribute("src", dataUrl); | |
}, false); | |
// Set up mouse events for drawing | |
var drawing = false; | |
var mousePos = { x:0, y:0 }; | |
var lastPos = mousePos; | |
canvas.addEventListener("mousedown", function (e) { | |
drawing = true; | |
lastPos = getMousePos(canvas, e); | |
}, false); | |
canvas.addEventListener("mouseup", function (e) { | |
drawing = false; | |
}, false); | |
canvas.addEventListener("mousemove", function (e) { | |
mousePos = getMousePos(canvas, e); | |
}, false); | |
// Set up touch events for mobile, etc | |
canvas.addEventListener("touchstart", function (e) { | |
mousePos = getTouchPos(canvas, e); | |
var touch = e.touches[0]; | |
var mouseEvent = new MouseEvent("mousedown", { | |
clientX: touch.clientX, | |
clientY: touch.clientY | |
}); | |
canvas.dispatchEvent(mouseEvent); | |
}, false); | |
canvas.addEventListener("touchend", function (e) { | |
var mouseEvent = new MouseEvent("mouseup", {}); | |
canvas.dispatchEvent(mouseEvent); | |
}, false); | |
canvas.addEventListener("touchmove", function (e) { | |
var touch = e.touches[0]; | |
var mouseEvent = new MouseEvent("mousemove", { | |
clientX: touch.clientX, | |
clientY: touch.clientY | |
}); | |
canvas.dispatchEvent(mouseEvent); | |
}, false); | |
// Prevent scrolling when touching the canvas | |
document.body.addEventListener("touchstart", function (e) { | |
if (e.target == canvas) { | |
e.preventDefault(); | |
} | |
}, false); | |
document.body.addEventListener("touchend", function (e) { | |
if (e.target == canvas) { | |
e.preventDefault(); | |
} | |
}, false); | |
document.body.addEventListener("touchmove", function (e) { | |
if (e.target == canvas) { | |
e.preventDefault(); | |
} | |
}, false); | |
// Get the position of the mouse relative to the canvas | |
function getMousePos(canvasDom, mouseEvent) { | |
var rect = canvasDom.getBoundingClientRect(); | |
return { | |
x: mouseEvent.clientX - rect.left, | |
y: mouseEvent.clientY - rect.top | |
}; | |
} | |
// Get the position of a touch relative to the canvas | |
function getTouchPos(canvasDom, touchEvent) { | |
var rect = canvasDom.getBoundingClientRect(); | |
return { | |
x: touchEvent.touches[0].clientX - rect.left, | |
y: touchEvent.touches[0].clientY - rect.top | |
}; | |
} | |
// Draw to the canvas | |
function renderCanvas() { | |
if (drawing) { | |
ctx.moveTo(lastPos.x, lastPos.y); | |
ctx.lineTo(mousePos.x, mousePos.y); | |
ctx.stroke(); | |
lastPos = mousePos; | |
} | |
} | |
// Clear the canvas | |
function clearCanvas() { | |
canvas.width = canvas.width; | |
} | |
// Allow for animation | |
(function drawLoop () { | |
requestAnimFrame(drawLoop); | |
renderCanvas(); | |
})(); | |
})(); | |
</script> | |
</body> | |
</html> |
Good Job!!!
For working with Chrome Mobile replace all preventDefault calls :
document.body.addEventListener("touchstart", function (e) { if (e.target == canvas) { e.preventDefault(); } }, false);
with
document.body.addEventListener("touchstart", function (e) { if (e.target == canvas) { e.preventDefault(); } }, {passive: false});
I don't quite understand how these parts work:
// Get a regular interval for drawing to the screen
window.requestAnimFrame = (function (callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimaitonFrame ||
function (callback) {
window.setTimeout(callback, 1000/60);
};
})();
and
// Allow for animation
(function drawLoop () {
requestAnimFrame(drawLoop);
renderCanvas();
})();
Can you explain how it works and what is does?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
in chrome mobile mode there is an error at e.preventDefault();
"Unable to preventDefault inside passive event listener due to target being treated as passive. See https://www.chromestatus.com/features/5093566007214080"
in opera mini the scroll is enable even drawing the canvas.