HTML5 canvas drawing board - touch support - javascript

I am using this simple script to enable users to enter their signatures. Unfortunately, this does not work on mobile devices.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var container = document.getElementById('container');
var container_style = getComputedStyle(container);
canvas.width = 400;
canvas.height = 300;
var mouse = {x: 0, y: 0};
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = "black";
function getSize(size){ctx.lineWidth = size;}
canvas.addEventListener('mousedown', function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
#canvas {
border: 1px solid rgba(0,0,0,.5);
}
<div id="container">
<canvas id="canvas"></canvas>
</div>
Is there an easy way to add touch support to this script?

Make these changes to your code:
Use pointer events (instead of mouse events): pointerdown, pointerup, and pointermove. Pointer events work for both mouse and touch interactions.
Add touch-action: none to your canvas CSS. This prevents the dragging of your finger from triggering the device's panning action (which stops your drawing).
Set your "mouse" coordinates upon pointerdown. This will stop previous lines from being connected to new ones.
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var container = document.getElementById('container');
canvas.width = 400;
canvas.height = 300;
var mouse = {x: 0, y: 0};
canvas.addEventListener('pointermove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';
canvas.addEventListener('pointerdown', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('pointermove', onPaint, false);
}, false);
canvas.addEventListener('pointerup', function() {
canvas.removeEventListener('pointermove', onPaint, false);
}, false);
var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
#canvas {
border: 1px solid rgba(0,0,0,.5);
touch-action: none;
}
<div id="container">
<canvas id="canvas"></canvas>
</div>

Related

Draw a straight line between two points selected in a mouse down event

I have code which draws a line as I move my mouse while clicking the mouse (mousedown event and mousemove event).
I also want a straight line to be drawn from the beginning of the point (where I first clicked the point, mousedown event) to the end (where I lift the mouse event, mouseup event).
(function() {
var canvas = document.querySelector('#paint');
var ctx = canvas.getContext('2d');
var sketch = document.querySelector('#sketch');
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
var mouse = {
x: 0,
y: 0
};
var last_mouse = {
x: 0,
y: 0
};
/* Mouse Capturing Work */
canvas.addEventListener('mousemove', function(e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
/* Drawing on Paint App */
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';
canvas.addEventListener('mousedown', function(e) {
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.beginPath();
ctx.moveTo(last_mouse.x, last_mouse.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.closePath();
ctx.stroke();
};
}());
#sketch{
width: 100%;
height: 200px;
background-color: #CCCCCC;
}
<div id="sketch">
<canvas id="paint">
</canvas>
</div>
You want to store the coordinates of the mouseDown event and then use them to draw a single line to the coordinates of the mouseUp event. I modified your code to show a way that can be done:
(function() {
var canvas = document.querySelector('#paint');
var ctx = canvas.getContext('2d');
var sketch = document.querySelector('#sketch');
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
var mouse = {
x: 0,
y: 0
};
var last_mouse = {
x: 0,
y: 0
};
/* Mouse Capturing Work */
canvas.addEventListener('mousemove', function(e) {
last_mouse.x = mouse.x;
last_mouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
/* Drawing on Paint App */
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'black';
canvas.addEventListener('mousedown', function(e) {
initialPoint = {x:mouse.x, y:mouse.y}
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
drawStraightLine()
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.beginPath();
ctx.moveTo(last_mouse.x, last_mouse.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.strokeStyle = "#000000";
ctx.closePath();
ctx.stroke();
};
let initialPoint
const drawStraightLine = function() {
ctx.beginPath();
ctx.moveTo(initialPoint.x, initialPoint.y);
ctx.lineTo(mouse.x, mouse.y);
ctx.strokeStyle = "#FF000077";
ctx.stroke();
}
}());
#sketch{
width: 100%;
height: 180px;
background-color: #DDDDDD;
}
<div id="sketch">
<canvas id="paint" />
</div>
initialPoint is the mouse position when the button is pressed and drawStarightLine() is the method executed when said button is released. Also added different colors to the lines to make it obvious.
Just add another position object eg
const mouseDownAt = {x: 0, y: 0};
Then when the mouse down event happens record that position
canvas.addEventListener('mousedown', function(e) {
mouseDownAt.x = e.pageX - this.offsetLeft;
mouseDownAt.y = e.pageY - this.offsetTop;
canvas.addEventListener('mousemove', onPaint, false);
}, false);
On the mouse up event draw the closing line
canvas.addEventListener('mouseup', function() {
lastMouse.x = mouse.x;
lastMouse.y = mouse.y;
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
// if mouse has moved?? draw the last little bit
if (mouse.x !== last_mouse.x || mouse.y !== last_mouse.y) {
onPaint();
}
// set the end position
lastMouse.x = mouse.x;
lastMouse.y = mouse.y;
// use the mouse down at pos as the new position
mouse.x = mouseDownAt.x;
mouse.y = mouseDownAt.y;
// draw the line
onPaint();
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
BTW I am not sure if you know that using closePath as you do will render the path segment twice and will reduce the quality of the line (too strong alphas on the anti aliasing) . closePath is like lineTo (draws a line segment) and not related to ctx.beginPath
function onPaint () {
ctx.beginPath();
ctx.lineTo(lastMouse.x, lastMouse.y); // after beginPath lineTo is the same
// moveTo
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};

How can I make canvas drawing work on mobile

My canvas drawing interface works perfectly on desktop but fails to work on iPhone.
When I try to draw, it just makes a dot where my thumb goes. When I drag my thumb, there is no line and the page continues to scroll...
Code:
var clearButton = document.getElementById('doodle-bin');
var canvascontainer = document.getElementById('doodle-canvas-container');
var canvas = document.getElementById('doodle-canvas');
var context = canvas.getContext('2d');
var radius = (document.getElementById('doodle-canvas-container').clientWidth + document.getElementById('doodle-canvas-container').clientHeight) / 150;
var dragging = false;
function getMousePosition(e) {
var mouseX = e.offsetX * canvas.width / canvas.clientWidth | 0;
var mouseY = e.offsetY * canvas.height / canvas.clientHeight | 0;
return {x: mouseX, y: mouseY};
}
context.mozImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
canvas.width = 1280;
canvas.height = 720;
canvas.style.width = '100%';
canvas.style.height = '100%';
/* CLEAR CANVAS */
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
clearButton.addEventListener('click', clearCanvas);
var putPoint = function (e) {
if (dragging) {
context.lineTo(getMousePosition(e).x, getMousePosition(e).y);
context.lineWidth = radius * 2;
context.stroke();
context.beginPath();
context.arc(getMousePosition(e).x, getMousePosition(e).y, radius, 0, Math.PI * 2);
context.fill();
context.beginPath();
context.moveTo(getMousePosition(e).x, getMousePosition(e).y);
}
};
var engage = function (e) {
dragging = true;
putPoint(e);
};
var disengage = function () {
dragging = false;
context.beginPath();
};
canvas.addEventListener('mousedown', engage);
canvas.addEventListener('mousemove', putPoint);
canvas.addEventListener('mouseup', disengage);
document.addEventListener('mouseup', disengage);
canvas.addEventListener('contextmenu', disengage);
canvas.addEventListener('touchstart', engage, false);
canvas.addEventListener('touchmove', putPoint, false);
canvas.addEventListener('touchend', disengage, false);
Any help would be greatly appreciated! Thank you
In your putPoint function cancel the default events and propagation.
var putPoint = function (e) {
e.preventDefault();
e.stopPropagation();
if (dragging) {
....
Then look at Using Touch Events with the HTML5 Canvas to handle how to convert your touch coordinates to mouse coordinates.
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);

Draw on HTML5 canvas on touch devices

I am trying to get a signatur pad to work.
I managed to make it work with the mouse no issue with a piece of code I found here: http://demos.ijasoneverett.com/html5-sigpad.php
However it does not seem to work on mobile devices, I do not understand why since I have added the event listeners
canvas.addEventListener("touchstart", mouseDown, false);
canvas.addEventListener("touchmove", mouseXY, true);
canvas.addEventListener("touchend", mouseUp, false);
Here is my all jQuery:
$(document).ready(function () {
//User Variables
var canvas = document.getElementById('canvas'); //canvas element
var context = canvas.getContext("2d"); //context element
var clickX = new Array();
var clickY = new Array();
var clickDrag = new Array();
var paint;
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
document.body.addEventListener("mouseup", mouseUp, false);
//For mobile
canvas.addEventListener("touchstart", mouseDown, false);
canvas.addEventListener("touchmove", mouseXY, true);
canvas.addEventListener("touchend", mouseUp, false);
document.body.addEventListener("touchcancel", mouseUp, false);
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height); // Clears the canvas
context.strokeStyle = "#000000"; //set the "ink" color
context.lineJoin = "miter"; //line join
context.lineWidth = 2; //"ink" width
for (var i = 0; i < clickX.length; i++) {
context.beginPath(); //create a path
if (clickDrag[i] && i) {
context.moveTo(clickX[i - 1], clickY[i - 1]); //move to
} else {
context.moveTo(clickX[i] - 1, clickY[i]); //move to
}
context.lineTo(clickX[i], clickY[i]); //draw a line
context.stroke(); //filled with "ink"
context.closePath(); //close path
}
}
function addClick(x, y, dragging) {
clickX.push(x);
clickY.push(y);
clickDrag.push(dragging);
}
function mouseXY(e) {
if (paint) {
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop - 40, true);
draw();
}
}
function mouseUp() {
paint = false;
}
function mouseDown(e)
{
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
paint = true;
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop - 40);
draw();
}
//Clear the Zig
document.getElementById("clearSig").onclick = function () {
clickX = new Array();
clickY = new Array();
clickDrag = new Array();
context.clearRect(0, 0, canvas.width, canvas.height);
$("#imgData").html('');
};
});
To get correct value of pageX and pageY you have to use e.touches(e.changedTouches) for mobile devices. For example:
function mouseXY (e) {
var touches = e.touches || [];
var touch = touches[0] || {};
if (paint) {
addClick(touch.pageX - this.offsetLeft, touch.pageY - this.offsetTop - 40, true);
draw();
}
}
See more about it on https://developer.mozilla.org/en-US/docs/Web/API/Touch_events

drawing a rectange over an image on canvas using dragging event

I am trying to draw a rectangle on an image using the mouse and dragging events on HTML5.
My code is shown below. When I draw the rectangle below, the actual image on the canvas disappears. Could you tell me what I am doing wrong? My intended goal is to have the rectangle on top of the image. I have attached a picture of what I actually want to see as the end result.
What am I doing wrong ?
<!DOCTYPE HTML>
<html>
<head>
<style>
body {
margin: 0px;
padding: 0px;
}
</style>
</head>
<body>
<canvas id="myCanvas" width="578" height="400"></canvas>
<script>
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var imageObj = new Image();
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50);
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg';
// ctx.globalAlpha = 0.5;
rect = {},
drag = false;
var rectStartXArray = new Array() ;
var rectStartYArray = new Array() ;
var rectWArray = new Array() ;
var rectHArray = new Array() ;
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
function mouseDown(e) {
rect.startX = e.pageX - this.offsetLeft;
rect.startY = e.pageY - this.offsetTop;
drag = true;
}
function mouseUp() {
rectStartXArray[rectStartXArray.length] = rect.startX;
rectStartYArray[rectStartYArray.length] = rect.startY;
rectWArray[rectWArray.length] = rect.w;
rectHArray[rectHArray.length] = rect.h;
drag = false;
}
function mouseMove(e) {
if (drag) {
rect.w = (e.pageX - this.offsetLeft) - rect.startX;
rect.h = (e.pageY - this.offsetTop) - rect.startY;
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
}
//drawOldShapes();
}
function draw() {
ctx.beginPath();
ctx.fillStyle="#FF0000";
ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);
ctx.stroke();
}
function drawOldShapes(){
for(var i=0;i<rectStartXArray.length;i++)
{
if(rectStartXArray[i]!= rect.startX && rectStartYArray[i] != rect.startY && rectWArray[i] != rect.w && rectHArray[i] != rect.h)
{
ctx.beginPath();
ctx.fillStyle="#FF0000";
ctx.fillRect(rectStartXArray[i], rectStartYArray[i], rectWArray[i], rectHArray[i]);
ctx.stroke();
}
}
}
init();
</script>
</body>
</html>
You are clearing the whole canvas inside draw() by calling ctx.fillRect(rect.startX, rect.startY, rect.w, rect.h);. Remove the line and it works. Fiddle - http://jsfiddle.net/da8wv75k/

JS variable not updating when button is clicked in HTML

I am making a Drawing/Canvas App on a webpage. I wanted to change the colours via buttons but the variables are not updating the colour. I debugged the code and noticed that it does update but the colour itself has not changed when drawing on the canvas.
HTML:
<div id="sketch">
<canvas id="paint"></canvas>
</div>
<button onClick="changecolour('blue')">Blue</button>
<button onClick="test()">DEBUG</button>
JavaScript:
var canvas = document.querySelector('#paint');
var ctx = canvas.getContext('2d');
var sketch = document.querySelector('#sketch');
var sketch_style = getComputedStyle(sketch);
canvas.width = parseInt(sketch_style.getPropertyValue('width'));
canvas.height = parseInt(sketch_style.getPropertyValue('height'));
var mouse = {x: 0, y: 0};
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop;
}, false);
var colour = "black";
function changecolour(choice){
colour = choice;
}
function test(click){
alert("You choose " + colour);
}
ctx.lineWidth = 5;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = colour;
canvas.addEventListener('mousedown', function(e) {
ctx.beginPath();
ctx.moveTo(mouse.x, mouse.y);
canvas.addEventListener('mousemove', onPaint, false);
}, false);
canvas.addEventListener('mouseup', function() {
canvas.removeEventListener('mousemove', onPaint, false);
}, false);
var onPaint = function() {
ctx.lineTo(mouse.x, mouse.y);
ctx.stroke();
};
You need to change the variable strokeStyle again.
function changecolour(choice){
colour = choice;
ctx.strokeStyle = colour;
}
You should affect the ctx.strokeStyle itself. When you first set his value, colour = 'black', which means you set it to black. It then stays black even tho you change the "colour" value. So in that case, you just have to do this:
function changecolour(choice){
ctx.strokeStyle = choice;
}
Hope that helps

Categories

Resources