I started studying canvas and ran into a problem, drawing with the help of the canvas with the mouse onmousedown, onmousemove, onmouseup works and for the touchpanel the iPad used touchstart, touchmove, touchend however the code for the touchpanel does not work. I commented out the non-working code, I will be grateful for the help and guidance of the true path.
The code for drawing canvas in ipad does not work
canvas.ontouchstart,canvas.touchstart,canvas.touchmove,canvas.touchend
function unit(){
canvasOffset = canvas.getBoundingClientRect();
ctx.lineJoin = "round";
canvas.onmousedown = function(e) {
drawing = true;
ctx.beginPath();
}
//canvas.ontouchstart = function(e) {
// if (e.touches) e = e.touches[0];
// return false;
//}
//canvas.touchstart = function(e) {
// drawing = true;
// ctx.beginPath();
//}
canvas.onmousemove = function(e) {
if (drawing) {
var mousePosition = getMousePosition(e);
ctx.lineTo(mousePosition[0], mousePosition[1]);
myColor = document.getElementById('myColor').style.background;
ctx.strokeStyle = myColor;
ctx.stroke();
}
};
//canvas.touchmove = function(e) {
// if (drawing) {
// var mousePosition = getMousePosition(e);
// ctx.lineTo(mousePosition[0], mousePosition[1]);
// myColor = document.getElementById('myColor').style.background;
// ctx.strokeStyle = myColor;
// ctx.stroke();
// }
//};
canvas.onmouseup = function(e) {
drawing = false;
ctx.closePath();
}
//canvas.touchend = function(e) {
// drawing = false;
// ctx.closePath();
//}
function getMousePosition(mouseEvent) {
return [Math.floor(event.offsetX), Math.floor(event.offsetY)];
}
}
Related
I'm having some issues setting up a drawing canvas. My web app allows users to draw a single digit on a canvas and then have that digit classified using machine learning. However, the canvas does not work on mobile devices. When I try to draw on a mobile device, nothing happens, I just scroll up, down, left, or right. Below is my canvas javascript code, all help is appreciated.
//window.addEventListener("load", () => {
const canvas = document.querySelector('#canvas');
const ctx = canvas.getContext('2d');
var rect = canvas.getBoundingClientRect();
ctx.translate(-rect.x, -rect.y);
let painting = false;
function startPosition(e) {
painting = true;
draw(e);
}
function finishedPosition() {
painting = false;
ctx.beginPath();
}
function draw(e) {
if (!painting) return;
ctx.lineWidth = 20;
ctx.lineCap = 'round';
ctx.strokeStyle = "black";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
function translateCanvasResize(e) {
var rect2 = canvas.getBoundingClientRect();
ctx.translate(rect.x-rect2.x, rect.y-rect2.y)
rect = rect2
}
function translateCanvasScroll(e) {
var rect2 = canvas.getBoundingClientRect();
ctx.translate(rect.x-rect2.x, rect.y-rect2.y)
rect = rect2
}
canvas.addEventListener('mousedown', startPosition);
canvas.addEventListener('mouseup', finishedPosition);
canvas.addEventListener('mouseout', finishedPosition);
canvas.addEventListener('mousemove', draw);
canvas.addEventListener('touchstart', startPosition);
canvas.addEventListener('touchend', finishedPosition);
canvas.addEventListener('touchmove', draw);
window.addEventListener('resize', translateCanvasResize);
window.addEventListener('scroll', translateCanvasScroll);
//});
canvas{
border: 1px solid black;
}
<canvas id=canvas width=500 height=200></canvas>
You need to call event.preventDefault on your touch events:
function draw(e) {
e.preventDefault();
I want to pick my color from the color picker and then draw with this color in my canvas.
I get the Error:
Uncaught TypeError: colors.addEventListener is not a function
at window.onload
I use the npm color picker.
I get the Error at the call of the function:
colors.addEventListener('click', function(event)
My html:
<div class="picker"
acp-color="#EFE9E7"
acp-palette="#f44336|#e91e63|#9c27b0|#673ab7|#3f51b5|#2196f3|#03a9f4|#00bcd4|
#009688|#4caf50|#8bc34a|#cddc39|#cddc39|#ffeb3b|#ffc107|#ff9800|#ff5722|#795548|#9e9e9e|#20707|#befe7ee|#9e9e9e|#9e9e5e|#9e4e9e">
</div>
<div class="right-block">
<canvas id="paint-canvas" width="640" height="400"></canvas>
</div>
<script src="https://cdn.jsdelivr.net/npm/a-color-picker#1.1.8/dist/acolorpicker.js"></script>
<script src="./paint.js"></script>
My js code
var colors="#f44336";
AColorPicker.from('.picker')
.on('change', (picker, color) => {
colors= color;
});
var canvas = document.getElementById("paint-canvas");
var context = canvas.getContext("2d");
var boundings = canvas.getBoundingClientRect();
window.onload = function () {
// Definitions
// Specifications
var mouseX = 0;
var mouseY = 0;
context.strokeStyle = 'black'; // initial brush color
context.lineWidth = 1; // initial brush width
var isDrawing = false;
loadInput.addEventListener('change', (event) => this.load(event));
// Handle Colors
colors.addEventListener('click', function(event) {
context.strokeStyle = event.target.value || 'black';
});
// Mouse Down Event
canvas.addEventListener('mousedown', function(event) {
setMouseCoordinates(event);
isDrawing = true;
// Start Drawing
context.beginPath();
context.moveTo(mouseX, mouseY);
});
// Mouse Move Event
canvas.addEventListener('mousemove', function(event) {
setMouseCoordinates(event);
if(isDrawing){
context.lineTo(mouseX, mouseY);
context.stroke();
}
});
// Mouse Up Event
canvas.addEventListener('mouseup', function(event) {
setMouseCoordinates(event);
isDrawing = false;
});
// Handle Mouse Coordinates
function setMouseCoordinates(event) {
mouseX = event.clientX - boundings.left;
mouseY = event.clientY - boundings.top;
}
};
You cannot add an event listener to a string.
var colors="#f44336";
colors.addEventListener('click', function(event) {
context.strokeStyle = event.target.value || 'black';
});
String does not have this method. Given the assumption it remains a string after the picker on change event.
The thing is that, you need to change your context.strokeColor when the event fires up on the color change when picked, So you should Create a reference of the AColorPciker element and use its event emitter when your document is loaded
Then you can easily change your strokeColor, I hope this works for you.
I am adding the edited script, which should work for you.
// Initializing the color picker reference
var colorPicker = AColorPicker.from('.picker');
var canvas = document.getElementById("paint-canvas");
var context = canvas.getContext("2d");
var boundings = canvas.getBoundingClientRect();
window.onload = function () {
// Definitions
// Specifications
var mouseX = 0;
var mouseY = 0;
context.strokeStyle = 'black'; // initial brush color
context.lineWidth = 1; // initial brush width
var isDrawing = false;
// Here I am using the refernce of AColorPicker to set the context Stroke color, when the change is emitted on the color change
colorPicker.on('change', (picker, color) => {
context.strokeStyle = color;
});
// Mouse Down Event
canvas.addEventListener('mousedown', function(event) {
setMouseCoordinates(event);
isDrawing = true;
// Start Drawing
context.beginPath();
context.moveTo(mouseX, mouseY);
});
// Mouse Move Event
canvas.addEventListener('mousemove', function(event) {
setMouseCoordinates(event);
if(isDrawing){
context.lineTo(mouseX, mouseY);
context.stroke();
}
});
// Mouse Up Event
canvas.addEventListener('mouseup', function(event) {
setMouseCoordinates(event);
isDrawing = false;
});
// Handle Mouse Coordinates
function setMouseCoordinates(event) {
mouseX = event.clientX - boundings.left;
mouseY = event.clientY - boundings.top;
}
};
There are two different functions are used to draw the free drawing and line drawing on a canvas. But when a function is called other function not working properly. If the line drawing function called first, and when we press the button to draw free it also draws the line. In the opposite case the continuous line get drawn.The two function are given below.
For free drawing
function free(){
var canvas=document.getElementById('canvas');
var radius=10;
var dragging1=false;
context.lineWidth=2*radius;
var putPoint=function(e) {
if(dragging1){
context.lineTo(e.clientX,e.clientY);
context.stroke();
context.beginPath();
context.arc(e.clientX,e.clientY,radius,0,Math.PI*2);
context.fill();
context.beginPath();
context.moveTo(e.clientX,e.clientY);
}//end of if
}
var engage = function(e) {
dragging1=true;
putPoint(e);
}
var disengage = function() {
dragging1=false;
context.beginPath();
}
canvas.addEventListener('mousedown',engage);
canvas.addEventListener('mousemove',putPoint);
canvas.addEventListener('mouseup',disengage);
}
For Line Drwawing
function line(){
var canvas,
context,
dragging = false,
dragStartLocation,
snapshot;
function getCanvasCoordinates(event) {
var x = event.clientX - canvas.getBoundingClientRect().left,
y = event.clientY - canvas.getBoundingClientRect().top;
return {x: x, y: y};
}
function takeSnapshot() {
snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}
function restoreSnapshot() {
context.putImageData(snapshot, 0, 0);
}
function drawLine(position) {
context.beginPath();
context.moveTo(dragStartLocation.x, dragStartLocation.y);
context.lineTo(position.x, position.y);
context.stroke();
}
function dragStart(event) {
dragging = true;
dragStartLocation = getCanvasCoordinates(event);
takeSnapshot();
}
function drag(event) {
var position;
if (dragging === true) {
restoreSnapshot();
position = getCanvasCoordinates(event);
drawLine(position);
}
}
function dragStop(event) {
dragging = false;
restoreSnapshot();
var position = getCanvasCoordinates(event);
drawLine(position);
}
function init() {
canvas = document.getElementById("canvas");
context = canvas.getContext('2d');
context.strokeStyle = 'purple';
context.lineWidth = 6;
context.lineCap = 'round';
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
}
init()
}
How can i solve this? Iam stuck at this point.
In this case please create two functions that removes the event listeners in the other function. That means create to function
function removeLineListeners(){
canvas.removeEventListener('mousedown', dragStart);
canvas.removeEventListener('mousemove', drag);
canvas.removeEventListener('mouseup', dragStop);
}
and
function removeFreeListeners(){
canvas.removeEventListener('mousedown',engage,false);
canvas.removeEventListener('mousemove',putPoint,false);
canvas.removeEventListener('mouseup',disengage,false);
}
So when when add removeLineListeners() to the starting of the free and
removeFreeListeners() to the strting of Line function. This worked for me
i'm creating a web page where you dynamically draw multiple rectangles. I can draw the single object, but once I tried to draw another one, the previous one is gone away. I tried to save the state using save() and restore(), and it seems that I can't put it here. Isn't it logical that save method is put in the mouseup and restore method is called in the mousedown event? Any help or advice will be appreciated.
const canvas = document.getElementById("circle"),
ctx = canvas.getContext("2d"),
circle = {},
drag = false,
circleMade = false,
mouseMoved = false;
function draw() {
ctx.beginPath();
ctx.arc(circle.X, circle.Y, circle.radius, 0, 2.0 * Math.PI);
ctx.stroke();
}
function mouseDown(e) {
ctx.restore();
circle.startX = e.pageX - this.offsetLeft;
circle.startY = e.pageY - this.offsetTop;
circle.X = circle.startX;
circle.Y = circle.startY;
if (!circleMade) {
circle.radius = 0;
}
drag = true;
}
function mouseUp() {
drag = false;
circleMade = true;
if (!mouseMoved) {
circle = {};
circleMade = false;
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
mouseMoved = false;
ctx.save();
}
function mouseMove(e) {
if (drag) {
mouseMoved = true;
circle.X = e.pageX - this.offsetLeft;
circle.Y = e.pageY - this.offsetTop;
if (!circleMade) {
circle.radius = Math.sqrt(Math.pow((circle.X - circle.startX), 2) + Math.pow((circle.Y - circle.startY), 2));
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
draw();
}
}
function init() {
canvas.addEventListener('mousedown', mouseDown, false);
canvas.addEventListener('mouseup', mouseUp, false);
canvas.addEventListener('mousemove', mouseMove, false);
}
init();
you need to save the information about what you are drawing in a separate object, every time you make a draw to the canvas you will wipe and redraw the new object.
so when you clearRect and then draw you are clearing and then drawing a fresh one but the old ones are being left behind. A good example:
var SavedCircles = [];
var circleInfo = function()
{
this.x = 0;
this.y = 0;
this.startX = 0;
this.startY = 0;
this.radius = 0;
}
circle = {};
function draw()
{
for(var x=0;x<SavedCircles.length;x++)
{
ctx.beginPath();
ctx.arc(SavedCircles[x].X, SavedCircles[x].Y, SavedCircles[x].radius, 0, 2.0 * Math.PI);
ctx.stroke();
}
}
function mouseDown()
{
circle = new circleInfo();
}
function mouseUp()
{
SavedCircles.push(circle);
}
function mouseMove()
{
draw();
}
so you can get rid of save and restore, also its much faster to clear a canvas simply by:
canvas.width = canvas.width;
this should help you keep all circles ever drawn. fill in the rest with your code.
I am trying to clear the canvas for redrawing, it gets clear and when we try to redraw, the previous thing comes back.
Here is my code:
var drawingApp = (function () {
//declaring Variables
var canvas,
canvasDiv,
context,
canvasWidth = 200,
canvasHeight = 200,
clickX = [],
clickY = [],
clickDrag = [],
paint = false;
//Initalisation Function
function init() {
canvasDiv = document.getElementById('canvasDiv');
canvas = document.createElement('canvas');
canvas.setAttribute('width', canvasWidth);
canvas.setAttribute('height', canvasHeight);
canvas.setAttribute('id', 'canvas');
canvasDiv.appendChild(canvas);
if (typeof G_vmlCanvasManager != 'undefined') {
canvas = G_vmlCanvasManager.initElement(canvas);
}
context = canvas.getContext("2d");
loadEvents(); //Load events
}
function loadEvents() {
//Mouse down Event
$('#canvas').mousedown(function (e) {
var mouseX = e.pageX - this.offsetLeft;
var mouseY = e.pageY - this.offsetTop;
paint = true;
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
redraw();
});
//Mouse Move Event
$('#canvas').mousemove(function (e) {
if (paint) {
addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
redraw();
}
});
//Mouse Up Event
$('#canvas').mouseup(function (e) {
paint = false;
});
//Mouse Leave Event
$('#canvas').mouseleave(function (e) {
paint = false;
});
}
//Add Click Function
function addClick(x, y, dragging) {
clickX.push(x);
clickY.push(y);
clickDrag.push(dragging);
}
//Redraw Function
function redraw() {
context.clearRect(0, 0, context.canvas.width, context.canvas.height); // Clears the canvas
context.strokeStyle = "#df4b26";
context.lineJoin = "round";
context.lineWidth = 5;
for (var i = 0; i < clickX.length; i++) {
context.beginPath();
if (clickDrag[i] && i) {
context.moveTo(clickX[i - 1], clickY[i - 1]);
} else {
context.moveTo(clickX[i] - 1, clickY[i]);
}
context.lineTo(clickX[i], clickY[i]);
context.closePath();
context.stroke();
}
}
// Clears the canvas.
function clearCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
return {
init: init,
erase: clearCanvas
};
})();
$(function () {
drawingApp.init();
});
Here is my fiddle
Please see where m getting wrong
When you clear your canvas using the erase function, you fail to clear the clickX, clickY and clickDrag variables. So the next time it draws it still draws the old data.
Updated JSFiddle - http://jsfiddle.net/P8acZ/6/
The code that changed
function clearCanvas() {
clickDrag = [];
clickX = [];
clickY = [];
context.clearRect(0, 0, canvas.width, canvas.height);
}