How can i draw on a canvas in mobile device? - javascript

i have some canvases in my code. All of these are like a blackboard, this canvases let me draw on an image, but when i try to draw in a device nothing happens. This is all of my code:
let configureCanvas = canvas => {
let ctx = canvas.getContext("2d");
let painting = canvas.parentNode;
let paintStyle = getComputedStyle(painting);
if(canvas == document.getElementById("pizarra-musculos")) {
var x = window.matchMedia("(max-width: 700px)")
myFunction(x) // Call listener function at run time
x.addListener(myFunction) // Attach listener function on state changes
function myFunction(x) {
if (x.matches) { // If media query matches
canvas.width = "350";
canvas.height = "350";
} else {
canvas.width = "500";
canvas.height = "500";
}
}
}else{
canvas.width = "350";
canvas.height = "350";
}
let mouse = {
x: 0,
y: 0
};
canvas.ontouchstart = function(e){
var touches = e.touches || [];
var touch = touches[0] || {};
}
canvas.addEventListener('mousemove', function(e) {
mouse.x = e.pageX - this.offsetLeft;
mouse.y = e.pageY - this.offsetTop
}, false);
if(canvas == document.getElementById("pizarra-musculos")) {
//Rojo Claro
ctx.lineWidth = 12;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(255, 8, 53, 0.02)';
document.getElementById("btnRojoClaro").addEventListener("click", ()=>{
//Rojo Claro
ctx.lineWidth = 12;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = 'rgba(255, 8, 53, 0.02)';
});
document.getElementById("btnVerde").addEventListener("click", ()=>{
//Rojo Claro
ctx.lineWidth = 4;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#249120';
});
document.getElementById("btnRojo").addEventListener("click", ()=>{
//Rojo Claro
ctx.lineWidth = 4;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#ff0000';
});
document.getElementById("btnNegro").addEventListener("click", ()=>{
//Negro
ctx.lineWidth = 4;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#000000';
});
document.getElementById("btnAzul").addEventListener("click", ()=>{
//Azul
ctx.lineWidth = 4;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#1e5085';
});
}else{
ctx.lineWidth = 3;
ctx.lineJoin = 'round';
ctx.lineCap = 'round';
ctx.strokeStyle = '#e34f54';
};
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.nextElementSibling.addEventListener('click', function() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
});
}
PD: i learned about the touchscreens on mozila developers but i can't do functionally this canvas on device... Thanks for learning my question.

In javascript, you can add listenner! That means that something will be listenned and a code will be executed when the listenner will be activated !
For instance, if you declare in html <button id="mybutton"></button> in js, you can retrieve this button with document.getElementById("mybutton"), thus, you can manipulate the element itself, value, return, action, etc...,
Let's store this element var button = document.getElementById("mybutton")
now console.log(button) will sort of display this element, cool right ?
On this button you can add listenner, onClick for example that will execute a function when the button is clicked
button.addEvenListenner("onClick", my_function)
So now when you will click on your button you will execute my_function (you need to create my_function of course)
But in your case your want to get the eventListenner of a mouse mouve or when someone use finger on their phone!
You already made it, with 'mousemove' for example ! or 'mouseup' etc...
The thing desktop is a phone and vice versa!
You don't have a mouse on your phone you have your finger, so need to have a listenner when someone touch de screen!
That's where 'touchstart' event listenner is here for, when you touch the screen, you can call a function to do whatever you want with this !
Those four listenner will be enough for your project, why you may ask ?
'touchstart' tells when you touch the screen
'touchend' tells when you remove your finger from the screen
'touchmove' tells when you drag your finger on the screen (touchstart and touchmove are not the same thing !)
'touchcancel' tells when you cancel (Honestly I don't know, you don't need it I guess)
now you need to add your listenner to your canvas
var canvas = document.getElementById("pizarra-musculos")
then you add your listenner
canvas.addEventListener("touchstart", handleStart);
canvas.addEventListener("touchend", handleEnd);
canvas.addEventListener("touchmove", handleMove);
Now when one of those 3 listenner will be used, the function next to them will be called !
Thus, you can execute whatever you want in those function
function handleMove(e) {
// Cache the client X/Y coordinates
var clientX = e.touches[0].clientX;
var clientY = e.touches[0].clientY;
}
With this bit of code you are able to keep track of the x and y of your finger of your screen, try every listenner to know when they are called etc.. put some console.log to print out value, you will do it it's not hard hope it helped you

Related

Update HTML canvas height on scroll

I want to add a drawing canvas on top of a website that stretches for the whole height of a website.
I specified
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
and it seems to work for the viewport, but when I scroll, I cannot draw bellow it.
I assume I need to update the canvas.height every time I scroll down, but I cannot seem to find a solution.
Here is the code:
window.addEventListener ("load", () => {
const canvas = document.querySelector ("#canvas");
const ctx = canvas.getContext ("2d");
//Resizing
canvas.height = window.innerHeight;
canvas.width = window.innerWidth;
//Variables
let painting = false;
function startPosition (e){
painting = true;
draw (e);
}
function finishedPosition (){
painting = false;
ctx.beginPath();
}
function draw (e){
if (!painting) return;
ctx.lineWidth = 1;
ctx.lineCap = "round";
ctx.lineTo(e.clientX, e.clientY);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(e.clientX, e.clientY);
}
//Event listeners
canvas.addEventListener ("mousedown", startPosition);
canvas.addEventListener ("mouseup", finishedPosition);
canvas.addEventListener ("mousemove", draw);
});
I would appreciate any help on this!
This appears to be due to the use of window.innerHeight. Try using document.querySelector('body').clientHeight as that should give you the height of the entire body of the page.
Also, use MouseEvent.pageX and .pageY because .clientY will not update when the user scrolls the page.

Erasing only paticular element of canvas in JS

I want to create something like scratch card.
I created a canvas and added text to it.I than added a box over the text to hide it.Finally write down the code to erase(scratch) that box.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
ctx.font = "30px Arial";
ctx.fillText("Hello World",10,50);
ctx.globalCompositeOperation = 'source-over';
ctx.fillStyle='red';
ctx.fillRect(0,0,500,500);
function myFunction(event) {
var x = event.touches[0].clientX;
var y = event.touches[0].clientY;
document.getElementById("demo").innerHTML = x + ", " + y;
ctx.globalCompositeOperation = 'destination-out';
ctx.arc(x,y,30,0,2*Math.PI);
ctx.fill();
}
But the problem is it delete the text also.
How could I only delete that box not the text?
Canvas context keeps only one drawing state, which is the one rendered. If you modify a pixel, it won't remember how it was before, and since it has no built-in concept of layers, when you clear a pixel, it's just a transparent pixel.
So to achieve what you want, the easiest is to build this layering logic yourself, e.g by creating two "off-screen" canvases, as in "not appended in the DOM", one for the scratchable area, and one for the background that should be revealed.
Then on a third canvas, you'll draw both canvases every time. It is this third canvas that will be presented to your user:
var canvas = document.getElementById("myCanvas");
// the context that will be presented to the user
var main = canvas.getContext("2d");
// an offscreen one that will hold the background
var background = canvas.cloneNode().getContext("2d");
// and the one we will scratch
var scratch = canvas.cloneNode().getContext("2d");
generateBackground();
generateScratch();
drawAll();
// the events handlers
var down = false;
canvas.onmousemove = handlemousemove;
canvas.onmousedown = handlemousedown;
canvas.onmouseup = handlemouseup;
function drawAll() {
main.clearRect(0,0,canvas.width,canvas.height);
main.drawImage(background.canvas, 0,0);
main.drawImage(scratch.canvas, 0,0);
}
function generateBackground(){
background.font = "30px Arial";
background.fillText("Hello World",10,50);
}
function generateScratch() {
scratch.fillStyle='red';
scratch.fillRect(0,0,500,500);
scratch.globalCompositeOperation = 'destination-out';
}
function handlemousedown(evt) {
down = true;
handlemousemove(evt);
}
function handlemouseup(evt) {
down = false;
}
function handlemousemove(evt) {
if(!down) return;
var x = evt.clientX - canvas.offsetLeft;
var y = evt.clientY - canvas.offsetTop;
scratch.beginPath();
scratch.arc(x, y, 30, 0, 2*Math.PI);
scratch.fill();
drawAll();
}
<canvas id="myCanvas"></canvas>
Now, it could all have been done on the same canvas, but performance wise, it's probably not the best, since it implies generating an overly complex sub-path that should get re-rendered at every draw, also, it is not much easier to implement:
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext('2d');
ctx.font = '30px Arial';
drawAll();
// the events handlers
var down = false;
canvas.onmousemove = handlemousemove;
canvas.onmousedown = handlemousedown;
canvas.onmouseup = handlemouseup;
function drawAll() {
ctx.globalCompositeOperation = 'source-over';
// first draw the scratch pad, intact
ctx.fillStyle = 'red';
ctx.fillRect(0,0,500,500);
// then erase with the currently being defined path
// see 'handlemousemove's note
ctx.globalCompositeOperation = 'destination-out';
ctx.fill();
// finally draw the text behind
ctx.globalCompositeOperation = 'destination-over';
ctx.fillStyle = 'black';
ctx.fillText("Hello World",10,50);
}
function handlemousedown(evt) {
down = true;
handlemousemove(evt);
}
function handlemouseup(evt) {
down = false;
}
function handlemousemove(evt) {
if(!down) return;
var x = evt.clientX - canvas.offsetLeft;
var y = evt.clientY - canvas.offsetTop;
// note how here we don't create a new Path,
// meaning that all the arcs are being added to the single one being rendered
ctx.moveTo(x, y);
ctx.arc(x, y, 30, 0, 2*Math.PI);
drawAll();
}
<canvas id="myCanvas"></canvas>
How could I only delete that box not the text?
You can't, you'll have to redraw the text. Once you've drawn the box over the text, you've obliterated it, it doesn't exist anymore. Canvas is pixel-based, not shape-based like SVG.

JavaScript Canvas touch future with multiple eventListeners

I need to add a touch feature to the canvas app that I'm working on (multiple users white board), and I already read about the event listeners and the event.preventDefault(), but I can't understand how can I use two event listeners with 'DOMContentLoaded' and 'touchmove'. At this point I don't know if using multiple event listeners is the solution I need.
This is the code I'm using:
document.addEventListener("DOMContentLoaded", function() {
var mouse = {
click: false,
move: false,
pos: {x:0, y:0},
pos_prev: false
};
var canvas = document.getElementById('drawing');
var context = canvas.getContext('2d');
var width = 1280;
var height = 960;
var socket = io.connect();
var lineWidth = 1;
var shadowBlur = 1;
var shadowColor = "black";
var strokeStyle = "black";
canvas.width = width;
canvas.height = height;
canvas.onmousedown = function(e){ mouse.click = true; };
canvas.onmouseup = function(e){ mouse.click = false; };
canvas.onmousemove = function(e) {
mouse.pos.x = e.clientX / width;
mouse.pos.y = e.clientY / height;
mouse.move = true;
};
socket.on('draw_line', function (data) {
var line = data.line;
context.beginPath();
context.lineWidth = lineWidth;
context.shadowBlur = shadowBlur;
context.strokeStyle = strokeStyle;
context.lineJoin="round";
context.lineCap = "round";
context.moveTo(line[0].x * width, line[0].y * height);
context.lineTo(line[1].x * width, line[1].y * height);
context.stroke();
});
function mainLoop() {
if (mouse.click && mouse.move && mouse.pos_prev) {
socket.emit('draw_line', { line: [ mouse.pos, mouse.pos_prev ] });
mouse.move = false;
}
mouse.pos_prev = {x: mouse.pos.x, y: mouse.pos.y};
setTimeout(mainLoop, 50);
}
mainLoop();
});
I would really appreciate any help.
Thanks.
Are you encountering some sort of bug? Right now it appears that your code operates by listening for the mouse being clicked and the mouse being moved. If the mouse is pressed down, the mouse is being moved and the loop has run at least once (mouse.click && mouse.move && mouse.pos_prev) then it draws a line on the canvas element.

I want to draw pattern on an image with canvas on click

i want to draw pattern on a image with canvas on click you can understand more with the provided images
here is what end result i want
http://i.imgur.com/wnH2Vxu.png
But i am having this blurred line
http://i.imgur.com/HXF1rTv.png
i am using following code
(
function() {
var canvas = document.querySelector('#canvas');
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);
var texture = document.getElementById("texture");
pFill = ctx.createPattern(texture, "repeat");
ctx.strokeStyle = pFill;
/* Drawing on Paint App */
ctx.lineWidth = 12;
ctx.lineJoin = 'square';
ctx.lineCap = 'square';
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();
};
}()
);
$( document ).ready(function() {
var c = document.getElementById("canvas");
var ctx = c.getContext("2d");
var img = document.getElementById("scream");
ctx.drawImage(img,10,10);
});
Method with stroke pattern will not work here. Because this pattern position is fixed. So when your line is not exactly horizontal or vertical you will have a distorted image instead of a chain of accurate balls.
Well I think the whole approach should be reconsidered.
User should create a path like in photoshop, which is visible as a temporary line. At first it can easily be a polyline, where vertices are pointed by clicks. And when the path is confirmed (by double click for example) you should remove the temporary line and put the balls along the path with a given step. In this case you can handle all turns and regularity distortions.
This is quite a bunch of work, but the task is in reality much more complex than it seems to be.
As a quick workaround you can try a simple approach. Drop a ball each time distance from the previous drop is more than double radius (for example) of the ball..
var lastBall = {x: null, y : null};
function drawBall(center){
ctx.beginPath();
ctx.arc(center.x, center.y, 10, 0, 2 * Math.PI, false);
ctx.fillStyle = 'orange';
ctx.fill();
}
function distance(a, b){
return Math.sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
var onPaint = function() {
if(!lastBall.x || distance(lastBall, mouse) > 25 ){
drawBall(mouse);
lastBall.x = mouse.x;
lastBall.y = mouse.y;
}
The code is rough you should define proper variables for color and radius, or perhaps replace it with your pattern, but you can get the idea
Fiddle

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