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.
Related
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;
}
I am trying to change this jQuery code slightly:
jQuery(document).ready(function(){
$('#canvas').attr('height', $('#canvas').css('height'));
$('#canvas').attr('width', $('#canvas').css('width'));
$("#special").click(function(e){
var x = e.pageX - this.offsetLeft;
var y = e.pageY - this.offsetTop;
/* var c=document.getElementById("special"); */
var ctx= this.getContext("2d"); /*c.getContext("2d");*/
ctx.beginPath();
ctx.arc(x, y, 50,0, 2*Math.PI);
ctx.stroke();
$('#status').html(x +', '+ y);
});
})
Which I use with this HTML code
<body>
<h2 id="status">0, 0</h2>
<canvas style="width: 1000px; height: 1000px; border:1px ridge green;" id="canvas">
</canvas>
</body>
</html>
and trying to draw circles with radius 5 with key press.
Instead of clicking, I want a circle to appear on canvas whenever I press a key on the keyboard. Therefore, I should keep the mouse position.
I tried mousemove:
jQuery(document).ready(function(){
$('#canvas').attr('height', $('#canvas').css('height'));
$('#canvas').attr('width', $('#canvas').css('width'));
var x = -1;
var y = -1;
$("#canvas").mousemove(function(e) {
x = e.pageX;
y = e.pageY;
});
$("#canvas").keypress(function(e){
var ctx= this.getContext("2d");
ctx.beginPath();
ctx.arc(x, y, 5,0, 2*Math.PI);
ctx.stroke();
$('#status').html(x +', '+ y);
});
})
Which did not work.
As you can guess, I am pretty new to jQuery. Therefore, I might have some syntax errors (which I believe I do not because my Chrome debugger does not show any).
My ultimate goal is to create draggable circles with keypresses. This is my first step. Can you help me?
The main problem here is that you can't focus on a canvas and without focus, it doesn't take keyboard input. Instead, setup a keypress listener on the document and check if you're over the canvas.
jQuery(document).ready(function() {
$('#canvas').attr('height', $('#canvas').css('height'));
$('#canvas').attr('width', $('#canvas').css('width'));
var x = -1;
var y = -1;
// Make sure the mouse is over the canvas
var overCanvas = false;
$('#canvas').mouseover(function() {
overCanvas = true;
});
$('#canvas').mouseleave(function() {
overCanvas = false;
});
$("#canvas").mousemove(function(e) {
// Use offset[X/Y] instead of page[X/Y]
// page[X/Y] will only be accurate if the canvas
// takes up the whole page
x = e.offsetX;
y = e.offsetY;
});
$(document).keypress(function(e) {
if (!overCanvas) {
return;
}
var canvas = $('#canvas')[0];
var ctx = canvas.getContext("2d");
ctx.strokeStyle = '#FFF'; // Stroke in white
ctx.beginPath();
ctx.arc(x, y, 5, 0, 2 * Math.PI);
ctx.stroke();
$('#status').html(x + ', ' + y);
});
})
canvas {
display: block;
background: #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="canvas" width="320" height="240"></canvas>
<span id="status"></span>
I created circles using canvas but can't delete the same on double click.`
var canvas,
context, shapes,
dragging = false, draggingtoMove = false,
dragStartLocation,dragEndLocation,
snapshot;
var numShapes;
function initiate() {
numShapes = 100;
shapes = [];
canvas = document.getElementById('canvas');
context = canvas.getContext('2d');
canvas.addEventListener('mousedown', dragStart, false);
canvas.addEventListener('mousemove', drag, false);
canvas.addEventListener('mouseup', dragStop, false);
canvas.addEventListener('dblclick', dblclickerase);
}
function dblclickerase(evt)
{
var i;
//We are going to pay attention to the layering order of the objects so that if a mouse down occurs over more than object,
//only the topmost one will be dragged.
var highestIndex = -1;
//getting mouse position correctly, being mindful of resizing that may have occured in the browser:
var bRect = canvas.getBoundingClientRect();
mouseX = (evt.clientX - bRect.left)*(canvas.width/bRect.width);
mouseY = (evt.clientY - bRect.top)*(canvas.height/bRect.height);
//find which shape was clicked
for (i=0; i < shapes.length; i++) {
if (hitTest(shapes[i], mouseX, mouseY)) {
//draggingtoMove = true;
if (i > highestIndex) {
// here i want to delete the circle on double click but not getting logic, I can get mouse location but how to select the circle and delete it
}
}
}
}
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 draw(position) {
var radius = Math.sqrt(Math.pow((dragStartLocation.x - position.x), 2) + Math.pow((dragStartLocation.y - position.y), 2));
var i=0;
var tempX;
var tempY;
var tempRad;
var tempR;
var tempG;
var tempB;
var tempColor;
tempRad = radius;
tempX = dragStartLocation.x;
tempY = dragStartLocation.y;
tempColor = getRndColor();
tempShape = {x:tempX, y:tempY, rad:tempRad, color:tempColor};
shapes.push(tempShape);
context.beginPath();
context.arc(tempX, tempY, tempRad, 0, 2*Math.PI, false);
//context.closePath();
context.fillStyle = tempColor;
context.fill();
i++;
}
function dragStart(evt) {
dragging = true;
//if (dragging == true) {
dragStartLocation = getCanvasCoordinates(evt);
takeSnapshot();
//}
}
function hitTest(shape,mx,my) {
var dx;
var dy;
dx = mx - shape.x;
dy = my - shape.y;
//a "hit" will be registered if the distance away from the center is less than the radius of the circular object
return (dx*dx + dy*dy < shape.rad*shape.rad);
}
function drag(event) {
var position;
if (dragging === true) {
restoreSnapshot();
position = getCanvasCoordinates(event);
draw(position);
}
}
function dragStop(event) {
dragging = false;
restoreSnapshot();
var position = getCanvasCoordinates(event);
dragEndLocation = getCanvasCoordinates(event);
draw(position);
}
function getRndColor() {
var r = 255 * Math.random() | 0,
g = 255 * Math.random() | 0,
b = 255 * Math.random() | 0;
return 'rgb(' + r + ',' + g + ',' + b + ')';
}
function eraseCanvas() {
context.clearRect(0, 0, canvas.width, canvas.height);
}
addEventListener("load",initiate);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<canvas id="canvas" width="1020" height="640"></canvas>
<button onclick="eraseCanvas()" style="float: right;">Reset</button>
</body>
</html>
My question is how to delete the circle when double click on same, I
added 'dblClick' eventListener but still I am only able to perform the 'clearRect'
which will only clear the rectangle from start and end location which is little odd. Another thing I can't change the color to white which will not be valid.point as if my circle overlaps another will look odd.
You can't delete what you draw on the canvas like that. Once it's drawn on the canvas, it stays there and you have no way to access it except to read the pixel data - but that won't solve your problem because you can have overlapping circles of the same color.
To solve the issue, you must keep track of drawn circles, and redraw the full canvas every time it's needed (when adding a new circle, removing an old one, etc.). That way, when you want to delete a circle, you'd simply remove it from the list of circles (a simple array would work). But the important thing is that you need to clear and redraw the full canvas.
Summary: while having your canvas constantly redrawn (either on every tick or when a user interaction happens), your click'n'drag function should only be adding the circle to the circle list (specifying data like x, y, radius, color), while double-clicking a circle would look up that circle in the list, and remove it.
I am playing around with canvas. I wrote this little snippet where I can draw something in the canvas, press run and have it count the number of pixels. Only the counting doesn't work. Specifically, every element of context.getImageData(0,0,canvas.width,canvas.height).data is 0. I saw a previous post with a similar problem, but in that case, it was because the code ran before the image was loaded. In this case I have rendered the image and can see it on screen. I would appreciate any help.
<!DOCTYPE html>
<html>
<body>
<div>
<canvas id="myCanvas" width="100" height="100"
style="border:1px solid #c3c3c3;">
Your browser does not support the HTML5 canvas tag.
</canvas>
</div>
<button id="runButton">Run</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script>
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
function drawPixel(x,y,r,g,b)
{
var id = context.createImageData(1,1);
var d = id.data;
d[0] = r;
d[1] = g;
d[2] = b;
d[3] = 255;
context.putImageData( id, x, y );
}
var clicking = false;
$(document).mouseup(function(){
clicking = false;
})
canvas.addEventListener('mousedown', function(evt) {
clicking = true;
var p = getMousePos(canvas, evt);
drawPixel(p.x,p.y,0,0,0);
}, false);
canvas.addEventListener('mousemove', function(evt) {
if(clicking == false) return;
var p = getMousePos(canvas, evt);
drawPixel(p.x,p.y,0,0,0);
}, false);
$("#runButton").click(countPixels);
function countPixels()
{
var nAlive = 0;
var p = context.getImageData(0,0,canvas.width,canvas.height).data;
for (var y = 0, i =0 ; y < canvas.height; y++)
for (var x = 0; x < canvas.width; x++, i+=4)
{
if (p[i] != 255 || p[i + 1] != 255 || p[i + 2] != 255) //Not white
{
nAlive++;
}
}
alert(nAlive);
}
</script>
</body>
</html>
The canvas is initially just black transparent pixels, and the pixel drawing is using black non-transparent pixels, so when you count every pixel that isn't white, all will be counted in this case which makes the result correct.
To fix you need to fill the whole canvas with white first. The white you see now is the background of the canvas:
context.fillStyle ="#fff";
context.fillRect(0, 0, canvas.width, canvas.height);
Fiddle
Optionally you could just count non-transparent pixels by using index 3 of the pixel, if you don't want to fill first:
if (p[i+3]) //a pixel
{
nAlive++;
}
Fiddle 2
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;
}