JavaScript - Canvas Drawing - Script Doesn't Work - javascript

I wrote a very simple JavaScript that uses the HTML5 canvas. When the user clicks their mouse on the canvas the script gets their mouse coordinates, then when they move their mouse while holding it down it draws a line, this repeats until they let up on the mouse. But it does not work and I have no idea why? Thanks in advance for your help.
<body>
<canvas id="myCanvas" width="500" height="500" style="border:1px solid #000000;">
</canvas>
<script>
// Canvas link
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
// Variables
var x1;
var y2;
var isPressed = false;
// Event listeners
context.addEventListener('mousedown', functionMouseDown, false);
context.addEventListener('mousemove', functionMouseMove, false);
context.addEventListener('mouseup', functionMouseUp, false);
function functionMouseDown() {
// Get coordinates
x1 = mousePos.x;
y1 = mousePos.y;
isPressed = true;
}
function functionMouseMove() {
// If mouse is down and moved start drawing line
if (isPressed == true) {
drawLine();
}
}
function functionMouseUp() {
// Stop drawing line
isPressed = false;
}
function drawLine() {
// Draw line
context.moveTo(x1,y1);
context.lineTo(x,y);
context.stroke();
// Set start coordinates to current coordinates
x1 = x;
y1 = y;
}
</script>
</body>
</html>

There are several problems here. You need to get the mouse position, which is not simply stored in mousePos.x/y. You get through the mouse move event, passed as the first param to the function which is added as the listener for mousemove, mousedown, mouseup. Here is how I fixed it
function functionMouseDown(e) {
// Get coordinates
x1 = e.clientX
y1 = e.clientY;
isPressed = true;
}
function functionMouseMove(e) {
// If mouse is down and moved start drawing line
if (isPressed == true) {
drawLine(e);
}
}
function functionMouseUp() {
// Stop drawing line
isPressed = false;
}
function drawLine(e) {
// Draw line
var x = e.clientX;
var y = e.clientY;
context.moveTo(x1,y1);
context.lineTo(x,y);
context.stroke();
// Set start coordinates to current coordinates
x1 = x;
y1 = y;
}

Related

How do i get update to stop running when I click?

Here is a code segment where i am trying to make update stop running so that I can put a dot on the canvas. When I try to get putPoint to return clicked = true, it makes clicked equal true regardless if I click or not. I just want to return true if and only if I click.
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");
//canvas.width = window.innerWidth;
//canvas.height = window.innerHeight;
var radius = 2;
var dragging = false; // wether or not the mouse button is held down
ctx.lineWidth = radius * 2;
var canvasPos = getPosition(canvas);
var mouseX = 0;
var mouseY = 0;
var clicked = false;
// here is where I declare clicked = true globally
function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.beginPath();
ctx.arc(mouseX, mouseY, radius, 0, 2 * Math.PI, true);
ctx.fill();
requestAnimationFrame(update);
}
canvas.addEventListener("mousemove", setMousePosition, false);
function setMousePosition(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
//console.log("before update " + clicked);
if (clicked != true) {
update();
//console.log("inside update " +clicked);
}
// here is the code I want to stop when I click
//console.log("after update " + clicked);
function putPoint() {
//e.clientX and e.clientY get the mouse position
ctx.beginPath();
//e.clientX and e.clientY get the mouse position
ctx.arc(mouseX - 10, mouseY - 10, radius, 0, Math.PI * 2);
//ctx.arc(e.offsetX, e.offsetY, radius, 0, Math.PI * 2);
ctx.fill();
//console.log("inside putPoint " + clicked);
}
//putPoint puts a dot on the canvas at the mouse position. But it wont fire unless
//I stop update, which tracks my dot.
//console.log("after putPoint " + clicked);
canvas.addEventListener("mousedown", putPoint);
//console.log(putPoint());
//console.log(clicked);
function getPosition(el) {
var xPosition = 0;
var yPosition = 0;
while (el) {
xPosition += (el.offsetLeft - el.scrollLeft + el.clientLeft);
yPosition += (el.offsetTop - el.scrollTop + el.clientTop);
el = el.offsetParent;
}
return {
x: xPosition,
y: yPosition
};
}
<canvas id=myCanvas>
</canvas>
below is a smaller reproduction of the problem. basically I am trying to update my variable to true when i click on the element. But when I return true or even set clicked to to true within the test function, it still reads true wether I click or not. It doesnt dynamically change. Maybe Im using the wrong event ? im not sure.
var clicked = false;
console.log(clicked);
function test () {
return true;
}
clicked = test();
console.log(clicked);
document.getElementsByTagName("h1")[0].addEventListener("mousedown", test);
I'm inferring a bit based on clues from both the used and unused (e.g. dragging variable) parts of your first snippet, but it seems to me like you are trying to draw a point that tracks with your mouse, and then once a click event has occurred you want to start drawing points dragging after the mouse until that click is released.
First, your issue with your 'clicked' tracking
I think you are misunderstanding when different statements are executed. In your second snippet all of the statements outside of the 'test' event handler function are only executed once. The 'test' function will be called with each mouse click, but simply returns true and does not change the value of 'clicked'. So, the statement:
var clicked = false;
...and the statement:
clicked = test();
...each only execute once. Here is a quick example to show you how you could track the toggling of that value. Try a simple click and also holding the click for a second before releasing to get the idea.
var clicked = false;
var clickableArea = document.getElementById("clickable");
clickableArea.addEventListener('mousedown', function() {
clicked = true;
console.log('Clicked, value of clicked var: ' + clicked);
});
clickableArea.addEventListener('mouseup', function() {
clicked = false;
console.log('Released, value of clicked var: ' + clicked);
});
<div id="clickable">Click Me</div>
What I think you are going for with your canvas rendering:
Move the mouse around and then click and drag the mouse.
var canvas, ctx;
var radius = 2;
var mouseX = 0;
var mouseY = 0;
var clicked = false;
var dragging = false;
// manages the drawing cycle
function putPoint() {
// clear the canvas if not dragging, or just before the first draw of a dragging cycle
if(!dragging) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
}
dragging = clicked;
// draw
var offset = dragging ? 10 : 0;
ctx.beginPath();
ctx.arc(mouseX-offset, mouseY-offset, radius, 0, 2 * Math.PI, true);
ctx.fill();
// kick off another cycle
requestAnimationFrame(putPoint);
}
// event handlers
function trackMouse(e) {
mouseX = e.clientX;
mouseY = e.clientY;
}
function startedDragging() {
clicked = true;
}
function quitDragging() {
clicked = false;
dragging = false;
}
// only runs once when called below, sets things up, starts the drawing cycle
function start() {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
ctx.lineWidth = radius * 2;
// attach events to handlers
canvas.addEventListener("mousemove", trackMouse, false);
canvas.addEventListener("mousedown", startedDragging);
canvas.addEventListener("mouseup", quitDragging);
requestAnimationFrame(putPoint);
}
start(); // calling start to kick things off
<canvas id="myCanvas">
</canvas>

Dynamically drawing in canvas

I'm trying to create a simple, purely JS program for drawing in a canvas. I have an acceptable solution right now, but if I draw very quickly, my drawing pen isn't continuous and I get scattered circles, probably because the computer can't keep up with the pace.
var draw = false;
function yesDraw() {
draw = true;
}
function mouseCoordinates(e) {
if (draw) {
var x = e.offsetX;
var y = e.offsetY;
drawing(x, y);
}
}
function noDraw() {
draw = false;
}
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
function drawing(x, y) {
ctx.beginPath();
ctx.arc(x, y, 10, 0, 2 * Math.PI);
ctx.fillStyle = "black";
ctx.fill();
}
<canvas id="myCanvas" height="400" ; width="1000" onmousedown="yesDraw()" onmousemove="mouseCoordinates(event)" onmouseup="noDraw()" onmouseout="noDraw()" style="border: solid 1px black;">Your browser does not support canvas.</canvas>
Is there any way to get a continuous flow of drawing and still keep it 100% JS?
Line segments from previous mouse position.
Rather than draw arcs draw line segments from the previous mouse position to the new one. As you don't want the line to be drawn from the end of the previous draw, you also need to indicate when a new line starts and set the previous mouse position to the current mouse.
To do this I added 3 variables lineStart, lastX,and lastY
lineStart is set to true when the mouse down event fires. In the draw function if line start is true then the lastX and lastY are set to the x,y and lineStart is set to false.
lastX, lastY hold the previous mouse position. They are set to x,y at the end of every draw call.
The line segments need to have the 2D context properties ctx.lineWidth set to the line width. To ensure the line is continuous the ctx.lineCap property is set to "round". This adds a semi circle to the start and end of the line.
Drawing past the edge
Having the pen turn off when the mouse moves out is annoying, you do this because if you don't you lose the mouse up events and the mouse keeps drawing with the mouse button up.
If you add the mouse to the document rather than the canvas, you don't have to worry about the mouse going outside the frame. You will still get the mouse up events even if the mouse is completely of the tab and browser.
Though you will have to use a slightly different way of getting the mouse coordinates, as you will want to still draw while off the canvas by at least half the draw line width. See code on how to get the mouse coordinates.
const c = document.getElementById("myCanvas");
const ctx = c.getContext("2d");
const r = 10; // draw radius
ctx.lineWidth = r * 2;
ctx.lineCap = "round";
ctx.fillStyle = "black";
var draw = false;
var lineStart = true;
var lastX, lastY;
function yesDraw() { draw = true; lineStart = true }
function mouseMove(e) {
const bounds = c.getBoundingClientRect();
const x = e.pageX - bounds.left - scrollX;
const y = e.pageY - bounds.top - scrollY;
if(draw && x > -r && x < c.width + r && y > -r && y < c.height + r){
drawing(x,y);
}
}
function noDraw() { draw = false }
document.addEventListener("mousemove",mouseMove);
document.addEventListener("mousedown",yesDraw);
document.addEventListener("mouseup",noDraw);
function drawing(x, y) {
if(lineStart){
lastX = x;
lastY = y;
lineStart = false;
}
ctx.beginPath();
ctx.lineTo(lastX, lastY);
ctx.lineTo(x, y);
ctx.stroke();
lastX = x;
lastY = y;
}
<canvas id="myCanvas" height="400" ; width="1000" style="border: solid 1px black;">Your browser does not support canvas.</canvas>
Use lineTo and end each line in an arc to make continuous smooth lines.
//Create Canvas
//(You can do this in HTML)
var c = document.body.appendChild(document.createElement("canvas"));
c.height = 400;
c.width = 1000;
var ctx = c.getContext("2d");
ctx.lineWidth = 20;
//Control drawing variable
var drawing = false;
c.onmousedown = c.onmouseout = c.onmouseup = function(evt) {
drawing = (evt.type === "mousedown");
};
//Keep track of last position
var oldX = null;
var oldY = null;
/**
* Draw the latest line
*
* #param {number} x
* #param {number} y
*/
function draw(x, y) {
if (drawing) {
if (oldX !== null) {
//If drawing, move to old coordinates for continual line
ctx.beginPath();
ctx.moveTo(oldX, oldY);
} else {
//Else simply move to current coordinates
ctx.moveTo(x, y);
ctx.beginPath();
}
//Draw a line
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
//Add an arc to the end of the line to make it smooth
ctx.beginPath();
ctx.arc(x, y, 0, 0, Math.PI * 2);
ctx.closePath();
ctx.stroke();
//Save new coordinates as old for next draw cycle
oldX = x;
oldY = y;
} else {
//If not drawing, cut line byt setting "old" to null
oldX = null;
oldY = null;
}
}
//Bind drawing
c.onmousemove = function(evt) {
draw(evt.offsetX, evt.offsetY);
};
canvas {
border: solid 1px black;
background-color: #eee;
}

Context.Arc not drawing on specified coordinates

I'm trying to draw a circle when ever the user clicks and moves the mouse inside the canvas. If I use random coordinates on the .arc() draws but if I use the mouse's coordinates it doesn't draw
If I try this:
JS:
<script>
var clicked = false;
var x = 0;
var y = 0;
var ye = true;
function load(event) {
debugger; var x2 = event.pageX;
var y2 = event.pageY;
if (x2 > 10) {
var num;
}
document.getElementById("<% = values.ClientID%>").innerText = "X= " + x2 + " Y= " + y2;
if (clicked) {
//debugger; document.getElementById("<% = values.ClientID%>").innerText += " Moving!";
debugger; var canvas = document.getElementById("<% = canvasSignature.ClientID%>");
var ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.arc(x, y, 3, 0, 2 * Math.PI);
ctx.stroke();
x = x + 1;
y = y + 1;
}
}
function down() {
debugger; clicked = true;
}
function up() {
debugger;
clicked = false;
}
</script>
ASP:
<body onmouseup ="up()">
<div >
<asp:Label ID ="lblSignature" runat ="server">Sign here</asp:Label>
</div>
<canvas id ="canvasSignature" runat ="server" width="200" height="100" style="border:1px solid #000000;" onmousemove ="load(event);" onmousedown ="down();"></canvas>
<asp:Label ID ="values" runat ="server"></asp:Label>
</body>
This works but if I replace x and y with x2 and y2 ctx.arc(x2, y2, 3, 0, 2 * Math.PI);, doesn't draw. I'm not getting any errors either.
Thanks
The mouse position must be adjusted as they are here relative to page, though, pageX and pageY are not part of the official standard and may not work in some browsers.
[pageX / pageY] This feature is non-standard and is not on a standards
track. Do not use it on production sites facing the Web: it will not
work for every user. There may also be large incompatibilities between
implementations and the behavior may change in the future.
Source
You can use the following code to adjust the mouse position. It uses clientX/Y which is relative to the client window. Then use the absolute position of the clicked element, here the canvas, to find the difference so the mouse position becomes relative to canvas instead:
var ctx = canvas.getContext("2d"); // set this once in global/parent
function load(event) {
var rect = this.getBoundingClientRect(), // get abs. region for clicked element
x = event.clientX - rect.left,
y = event.clientY - rect.top;
// plot arc
ctx.beginPath();
ctx.arc(x, y, 3, 0, 2 * Math.PI);
ctx.stroke();
}
The only drawback is that you have to consider border and padding if you apply that to canvas. Usually avoid applying such styles to canvas, rather wrap it in a container div and apply those styles to the div instead.
I managed to figure it out! Instead of drawing circles I drew lines. On mousedown, call moveTo(clientX,clientY) and on mouseMove call lineTo(clientX,clientY) moveTo(clientX,clientY) That way when the user clicks I have the initial position for the line, when he moves, assign the final position and update the initial position.
JS:
<script>
var clicked = false;
var ctx = null;
var canvas = null;
function move(event)
{
document.getElementById("<% = values.ClientID%>").innerText = "X= " + currentX + " Y= " + currentY;
if (clicked)
{
ctx.lineTo(event.offsetX, event.offsetY);
ctx.moveTo(event.offsetX, event.offsetY);
ctx.stroke();
x = x + 1;
y = y + 1;
}
}
function down(event)
{
clicked = true;
var canvas = document.getElementById("<% = canvasSignature.ClientID%>");
ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.moveTo(event.offsetX, event.offsetY);
}
function up()
{
clicked = false;
ctx.closePath();
}
</script>
ASPX:
<div onmouseup="up();">
<div>
<asp:Label ID="lblSignature" runat="server">Sign here</asp:Label>
</div>
<canvas id="canvasSignature" runat="server" width="300" height="300" style="border: 1px solid #000000;" onmousemove="move(event);" onmousedown="down(event);"></canvas>
<asp:Label ID="values" runat="server"></asp:Label>
</div>
Works on Chrome and IE9.

Html5-canvas- How to remove space between the point I click and the draw point

please see the image below for better understanding what I mean :
http://8pic.ir/images/c6kzf0n0eu1v81sv3lit.jpg
as you can see, I scrolled down and when I click on canvas to point a position , it gives space between the point I click and the point it draw the line .
this is my code:
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var cw,ch;
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var nameimageis =1;
// set some canvas styles
ctx.strokeStyle='black';
// an array to hold user's click-points that define the clipping area
var points=[];
// load the image
var img=new Image();
img.crossOrigin='anonymous';
img.onload=start;
img.src="http://localhost/image/D0D70A02A7_166.18K_{}_6458.JPG";
function start(){
// resize canvas to fit the img
cw=canvas.width=img.width;
ch=canvas.height=img.height;
// draw the image at 25% opacity
drawImage(1);
// listen for mousedown and button clicks
$('#canvas').mousedown(function(e){handleMouseDown(e);});
$('#reset').click(function(){ points.length=0; drawImage(1); });
}
rightclick = function(e) {
e.preventDefault();
if(!e.offsetX) {
e.offsetX = (e.pageX - $(e.target).offset().left);
e.offsetY = (e.pageY - $(e.target).offset().top);
}
var x = e.offsetX, y = e.offsetY;
for (var i = 0; i < points.length; i+=2) {
dis = Math.sqrt(Math.pow(x - points[i], 2) + Math.pow(y - points[i+1], 2));
if ( dis < 6 ) {
points.splice(i, 2);
draw();
record();
return false;
}
}
return false;
};
function handleMouseDown(e){
// tell the browser that we're handling this event
e.preventDefault();
e.stopPropagation();
// calculate mouseX & mouseY
mx=parseInt(e.clientX-offsetX);
my=parseInt(e.clientY-offsetY);
// push the clicked point to the points[] array
points.push({x:mx,y:my});
// show the user an outline of their current clipping path
outlineIt();
// if the user clicked back in the original circle
// then complete the clip
/*if(points.length>1){
var dx=mx-points[0].x;
var dy=my-points[0].y;
if(dx*dx+dy*dy<10*10){
clipIt();
}
}*/
}
// redraw the image at the specified opacity
function drawImage(alpha){
ctx.clearRect(0,0,cw,ch);
ctx.globalAlpha=alpha;
ctx.drawImage(img,0,0);
ctx.globalAlpha=1.00;
}
// show the current potential clipping path
function outlineIt(){
drawImage(1);
ctx.beginPath();
ctx.moveTo(points[0].x,points[0].y);
for(var i=0;i<points.length;i++){
ctx.lineTo(points[i].x,points[i].y);
}
ctx.closePath();
ctx.stroke();
ctx.beginPath();
ctx.arc(points[0].x,points[0].y,10,0,Math.PI*2);
ctx.closePath();
ctx.stroke();
}
How can I remove this space and point the right position every where I clicked?
It's because you are using e.clientY in function handleMouseDown. clientX/Y is relative to the viewport, not the document. Try use e.pageX/Y, which are relative to the document content.
More details in this question.

myContext.clearRect(0, 0, 500, 700); Not Clearing Canvas Correctly

I have an HTML5 Canvas that can be drawn on with the mouse. I would like to be able to clear the canvas so the user can make a new drawing. I do this with:
myContext.clearRect(0, 0, 500, 700);
The canvas appears clear but as soon as the user begins a new drawing the old drawing reappears. My JavaScript for the mouse drawing part is:
// Variables
var x1;
var y1;
var isPressed = false;
var myCanvas;
var myContext;
function startCanvas() {
// Canvas stuff
myCanvas = document.getElementById("can1");
myContext = myCanvas.getContext("2d");
// Specify a black background, and white lines that are 3 pixels thick.
myContext.fillStyle = '#000000';
myContext.strokeStyle = '#000000';
myContext.fillRect(0, 0, 500, 700);
myContext.lineWidth = 3;
myContext.fill();
}
function functionMouseDown(e) {
// Get coordinates
x1 = e.clientX - myCanvas.offsetLeft;
y1 = e.clientY - myCanvas.offsetTop;
isPressed = true;
}
function functionMouseMove(e) {
// If mouse is down and moved start drawing line
if (isPressed == true) {
drawLine(e);
}
}
function functionMouseUp() {
// Stop drawing line
isPressed = false;
}
function drawLine(e) {
// Draw line
var x = e.clientX - myCanvas.offsetLeft;
var y = e.clientY - myCanvas.offsetTop;
myContext.strokeStyle = '#ffffff';
myContext.lineWidth = 1;
myContext.moveTo(x1, y1);
myContext.lineTo(x, y);
myContext.stroke();
// Set start coordinates to current coordinates
x1 = x;
y1 = y;
}
startCanvas();
The HTML is:
<canvas id="can1" width="500" height="700"></canvas>
myContext.strokeStyle = '#000000';
myContext.beginPath();//<---- add this and read about this.
myContext.fillRect(0, 0, 500, 700);
myContext.lineWidth = 3; //why?
myContext.fill();

Categories