canvas with a cursor follower [duplicate] - javascript

This question already has answers here:
Is there any way to accelerate the mousemove event?
(2 answers)
Closed 4 years ago.
$(function(){
var mouseX = 0;
var mouseY = 0;
$('body,html').mousemove(function(e){
var gap = parseInt($('#stalker').css("width")) / 2;
mouseX = e.pageX - gap;
mouseY = e.pageY - gap;
$('#stalker').css('left', mouseX);
$('#stalker').css('top', mouseY);
});
var canvas = document.getElementById('mycanvas');
if(!canvas || !canvas.getContext) return false;
var ctx = canvas.getContext('2d');
ctx.lineWidth = 2;
ctx.lineJoin = ctx.lineCap = 'round';
var startX,
startY,
x,
y,
borderWidth = 5,
isDrawing = false;
$('#mycanvas,#stalker').mousedown(function(e){
startX = e.pageX - $('#mycanvas').offset().left - borderWidth;
startY = e.pageY - $('#mycanvas').offset().top - borderWidth;
})
.mouseup(function(e){
if(!isDrawing) return;
x = e.pageX - $('#mycanvas').offset().left - borderWidth;
y = e.pageY - $('#mycanvas').offset().top - borderWidth;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(x,y);
ctx.stroke();
})
$('#mycanvas').mouseenter(function(e){
startX = e.pageX - $('#mycanvas').offset().left - borderWidth;
startY = e.pageY - $('#mycanvas').offset().top - borderWidth;
});
$('body,html').mousedown(function(e){
isDrawing = true;
})
.mouseup(function(e){
isDrawing = false;
});
$('#mycanvas,#stalker').mousemove(function(e){
if(!isDrawing) return;
x = e.pageX - $('#mycanvas').offset().left - borderWidth;
y = e.pageY - $('#mycanvas').offset().top - borderWidth;
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(x,y);
ctx.stroke();
startX = x;
startY = y;
});
});
#mycanvas{
border:5px solid #999;
}
#stalker{
position:absolute;
width:80px;
height:80px;
border:solid 1px gray;
border-radius:50%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<div id="stalker"></div>
<canvas width="550px" height="500px" id="mycanvas">
</canvas>
I'm trying to make a drawing app with canvas,
and I needed a circle that keeps following the cursor while drawing.
so I wrote the above code,
but it's not really working: if I draw a line slowly it looks fine, but if I move the cursor faster, the line doesn't connect.
The line would be like two or three separate lines even though I'm not releasing the mouse click.
I thought this could be because #stalker is not catching up the speed of the cursor, so I put "mousedown" and "mousemove" on #mycanvas too, but still it doesn't work.
Does anyone know why?

you can save mouse positions in an array, and then draw it
a quick example:
$(function(){
var mouseX = 0;
var mouseY = 0;
$('body,html').mousemove(function(e){
var gap = parseInt($('#stalker').css("width")) / 2;
mouseX = e.pageX - gap;
mouseY = e.pageY - gap;
$('#stalker').css('left', mouseX);
$('#stalker').css('top', mouseY);
});
var canvas = document.getElementById('mycanvas');
if(!canvas || !canvas.getContext) return false;
var ctx = canvas.getContext('2d');
ctx.lineWidth = 2;
ctx.lineJoin = ctx.lineCap = 'round';
var startX,
startY,
x,
y,
borderWidth = 5,
isDrawing = false,
lines = [];
$('body,html').mousedown(function(e){
isDrawing = true;
lines.push([]);
})
.mouseup(function(e){
isDrawing = false;
});
$('#mycanvas,#stalker').mousemove(function(e){
if(!isDrawing) return;
x = e.pageX - $('#mycanvas').offset().left - borderWidth;
y = e.pageY - $('#mycanvas').offset().top - borderWidth;
lines[lines.length-1].push([x, y]);
});
function render() {
ctx.clearRect(0, 0, 550, 500);
for (const line of lines) {
ctx.beginPath();
for (const [i, pos] of Object.entries(line)) {
if (!+i) {
ctx.moveTo(pos[0], pos[1]);
} else {
ctx.lineTo(pos[0], pos[1]);
}
}
ctx.stroke();
}
}
(function loop() {
render();
requestAnimationFrame(loop);
})();
});

Related

Canvas Arrowhead

Please look at the code for Canvas arrowhead why the arrowhead disappears every time you draw a new line. And how can I fix it? sorry for my english thank you
I want this section to be used to draw matching lines. But I have a problem with arrowheads. I hope someone can help me with a problem I'm not good at and can't find a solution.
https://jsfiddle.net/liptonkingza/4vn3uyb9/1/
Code
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var storedLines = [];
var startX = 0;
var startY = 0;
var isDown;
ctx.strokeStyle = "orange";
ctx.lineWidth = 3;
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#clear").click(function() {
storedLines.length = 0;
redrawStoredLines();
});
function handleMouseDown(e) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
isDown = true;
startX = mouseX;
startY = mouseY;
}
function arrow (p1, p2, size) {
var angle = Math.atan2((p2.y - p1.y) , (p2.x - p1.x));
var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
ctx.save();
ctx.translate(p1.x, p1.y);
ctx.rotate(angle);
// line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(hyp - size, 0);
ctx.stroke();
// triangle
ctx.fillStyle = 'orange';
ctx.beginPath();
ctx.lineTo(hyp - size, size);
ctx.lineTo(hyp, 0);
ctx.lineTo(hyp - size, -size);
ctx.fill();
ctx.restore();
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
redrawStoredLines();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
// draw the current line
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
ctx.stroke();
}
function handleMouseUp(e) {
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
}
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
ctx.beginPath();
ctx.moveTo(storedLines[i].x1, storedLines[i].y1);
ctx.lineTo(storedLines[i].x2, storedLines[i].y2);
ctx.stroke();
}
}
body {
background-color: ivory;
padding: 10px;
}
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Drag to draw lines</p>
<canvas id="canvas" width=300 height=300></canvas>
<br/>
<button id="clear">Clear Canvas</button>
Your redrawStoredLines function is only drawing lines and not including the arrow.
Replace this:
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
ctx.beginPath();
ctx.moveTo(storedLines[i].x1, storedLines[i].y1);
ctx.lineTo(storedLines[i].x2, storedLines[i].y2);
ctx.stroke();
}
}
With:
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
arrow({x: storedLines[i].x1, y: storedLines[i].y1}, {x: storedLines[i].x2, y: storedLines[i].y2}, 10);
}
}
See it in action...
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var storedLines = [];
var startX = 0;
var startY = 0;
var isDown;
ctx.strokeStyle = "orange";
ctx.lineWidth = 3;
$("#canvas").mousedown(function(e) {
handleMouseDown(e);
});
$("#canvas").mousemove(function(e) {
handleMouseMove(e);
});
$("#canvas").mouseup(function(e) {
handleMouseUp(e);
});
$("#clear").click(function() {
storedLines.length = 0;
redrawStoredLines();
});
function handleMouseDown(e) {
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
isDown = true;
startX = mouseX;
startY = mouseY;
}
function arrow (p1, p2, size) {
var angle = Math.atan2((p2.y - p1.y) , (p2.x - p1.x));
var hyp = Math.sqrt((p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y));
ctx.save();
ctx.translate(p1.x, p1.y);
ctx.rotate(angle);
// line
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(hyp - size, 0);
ctx.stroke();
// triangle
ctx.fillStyle = 'orange';
ctx.beginPath();
ctx.lineTo(hyp - size, size);
ctx.lineTo(hyp, 0);
ctx.lineTo(hyp - size, -size);
ctx.fill();
ctx.restore();
}
function handleMouseMove(e) {
if (!isDown) {
return;
}
redrawStoredLines();
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
// draw the current line
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(mouseX, mouseY);
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
ctx.stroke();
}
function handleMouseUp(e) {
isDown = false;
var mouseX = parseInt(e.clientX - offsetX);
var mouseY = parseInt(e.clientY - offsetY);
storedLines.push({
x1: startX,
y1: startY,
x2: mouseX,
y2: mouseY
});
redrawStoredLines();
arrow({x: startX, y: startY}, {x: mouseX, y: mouseY}, 10);
}
function redrawStoredLines() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
if (storedLines.length == 0) {
return;
}
// redraw each stored line
for (var i = 0; i < storedLines.length; i++) {
arrow({x: storedLines[i].x1, y: storedLines[i].y1}, {x: storedLines[i].x2, y: storedLines[i].y2}, 10);
}
}
body {
background-color: ivory;
padding: 10px;
}
canvas {
border: 1px solid red;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Drag to draw lines</p>
<canvas id="canvas" width=300 height=300></canvas>
<br/>
<button id="clear">Clear Canvas</button>

detect close path in canvas

Hi I'm searching to find a way to close path with javascript.
I can draw a series of straight lines by clicking on the canvas but I want that when the line are closed the object create takes a grey background.
Like in this example when you close the wall the room appears
var needFirstPoint = true;
function drawNextLine(ctx, x, y) {
if (needFirstPoint) {
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(x, y);
needFirstPoint = false;
}
else {
ctx.lineTo(x, y);
ctx.stroke();
}
}
$(document).ready(function(){
var canvas = $('#myCanvas').get(0);
if (!canvas.getContext) { return; }
var ctx = canvas.getContext('2d');
$('#myCanvas').on('click', function(e){
var offset = $(this).offset();
var x = e.pageX - offset.left;
var y = e.pageY - offset.top;
drawNextLine(ctx, x, y);
});
});
canvas {
border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="600" height="600"></canvas>
I don't know how to detect a close path that could form an object
EDIT: There is a simpler solution. Remember the position of the first click and check if any of the subsequent clicks are nearby.
https://codepen.io/anon/pen/pQLwGK
var startX = -1, startY = -1;
function dist(x0,y0,x1,y1)
{
return Math.sqrt( Math.pow(x1-x0,2) + Math.pow(y1-y0,2));
}
$(document).ready(function()
{
var canvas = $('#myCanvas').get(0);
if (!canvas.getContext) { return; }
var ctx = canvas.getContext('2d');
ctx.fillStyle = '#f00';
ctx.beginPath();
$('#myCanvas').on('click', function(e)
{
console.log('click');
var offset = $(this).offset();
var x = e.pageX - offset.left;
var y = e.pageY - offset.top;
if (startX === -1)
{
console.log('start position is set to ',x ,y);
startX = x;
startY = y;
ctx.moveTo(x,y);
}
else
{
// checking if a click is within 20px of the starting point
if (dist(startX, startY,x,y ) < 20)
{
// assume that polygon is closed
ctx.lineTo(startX,startY);
ctx.fill();
console.log('fill');
}
else
{
ctx.lineTo(x,y);
}
ctx.stroke();
}
});
});

Show rectangle on canvas when mouse move

I want to draw rectangle on canvas. Below code is working fine except when i draw rectangle it does't show path when mouse is moving. When i left the mouse then rectangle is visible on canvas.
Please help,
Thanks
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50); //Load Image on canvas
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
canvas.addEventListener("mousedown",function (e) {
mouseDown(e);
}, false);
canvas.addEventListener("mousemove",function (e){
mouseXY(e);
}, false);
canvas.addEventListener("mouseup", function (e){
mouseUp(e);
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
//drawSquare();
}
}
function drawSquare() {
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.colortool div {
width: 15px;
height: 15px;
float: left;
margin-left: 2px;
}
.clear {
clear: both;
}
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
Here is you new JavaScript
var canvas, cnvHid, cnvRender, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2;
function init() {
canvas = document.getElementById('can');
cnvHid = document.getElementById( "canHid" );
cnvRender = document.getElementById( "canRend" );
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
ctx.drawImage(imageObj, 69, 50); //Load Image on canvas
renderAllCanvas();
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
cnvRender.addEventListener("mousedown",function (e) {
mouseDown(e);
renderAllCanvas();
}, false);
cnvRender.addEventListener("mousemove",function (e){
mouseXY(e);
renderAllCanvas();
}, false);
cnvRender.addEventListener("mouseup", function (e){
mouseUp(e);
renderAllCanvas();
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare( canvas ); //update on mouse-up
cnvHid.getContext( "2d" ).clearRect( 0, 0, cnvHid.width, cnvHid.height );
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare( canvas ); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare( cnvHid, true );
}
}
function drawSquare( cnv, clear ) {
var ctx = cnv.getContext( "2d" );
if( clear && clear === true ){
ctx.clearRect( 0, 0, cnv.width, cnv.height );
}
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
ctx.closePath();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
function renderAllCanvas(){
var cnxRender = cnvRender.getContext( "2d" );
cnxRender.drawImage(
canvas
,0,0
,cnvRender.width,cnvRender.height
);
cnxRender.drawImage(
cnvHid
,0,0
,cnvRender.width,cnvRender.height
);
}
And here is you new HTML
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="display: none;"></canvas>
<canvas id="canHid" width="400" height="400" style="display: none;"></canvas>
<canvas id="canRend" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>
In some way, you would need to keep track on the changes you make to a shape you draw on the canvas. In your case, you would start by creating a very small rectangle and then scale it according to your mouse position during your dragmove.
Currently, you only have a function which draws an entirely new rectangle but does not take any previous "state" into consideration.
I found this blogpost which could be helpful. It doesn't explain scaling in particular but it could help with the basic concepts behind so I think this would be a good way for you to find a suitable solution.
Since we are finding the canvas tag in the DOM using it’s id and then setting the drawing context of the canvas to 2D. Two things is importent here is store the information as we draw the recatangle and a bolean to check user is drawing the rectangleor not.
You can reffer these links:Drawing a rectangle using click, mouse move, and click
Draw on HTML5 Canvas using a mouse
Check the js fiddle in the given link.
Hope this will help you..
Your current code has the redraw commented out on the mouse move, which would be required to update the canvas. However your code is also destroying the image the way the rectangle is being drawn. If you retain the image as shown below and redraw it on each frame before drawing the rectangle, it might have the desired effect.
var canvas, ctx, flag = false,
prevX = 0,
currX = 0,
prevY = 0,
currY = 0,
currShape = 'rectangle',
mouseIsDown = 0,
startX, endX, startY, endY,
dot_flag = false;
var x = "white",
y = 2,
image = null;
function init() {
canvas = document.getElementById('can');
ctx = canvas.getContext("2d");
var imageObj = new Image(); //Canvas image Obj
imageObj.onload = function() {
image = imageObj;
ctx.drawImage(image, 69, 50); //Load Image on canvas
};
imageObj.src = 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg'; //Load Image
w = canvas.width; // Canvas Width
h = canvas.height; // Canvas Height
//Check Shape to be draw
eventListener();
}
function eventListener(){
if(currShape=='rectangle'){
canvas.addEventListener("mousedown",function (e) {
mouseDown(e);
}, false);
canvas.addEventListener("mousemove",function (e){
mouseXY(e);
}, false);
canvas.addEventListener("mouseup", function (e){
mouseUp(e);
}, false);
}
}
function mouseUp(eve) {
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
}
function mouseDown(eve) {
mouseIsDown = 1;
var pos = getMousePos(canvas, eve);
startX = endX = pos.x;
startY = endY = pos.y;
if(currShape=='rectangle')
{
drawSquare(); //update on mouse-up
}
}
function mouseXY(eve) {
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, eve);
endX = pos.x;
endY = pos.y;
drawSquare();
}
}
function drawSquare() {
// draw background image
if(image) {
ctx.drawImage(image, 69, 50);
}
// creating a square
var w = endX - startX;
var h = endY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
ctx.beginPath();
ctx.globalAlpha=0.7;
ctx.rect(startX + offsetX, startY + offsetY, width, height);
ctx.fillStyle = x;
ctx.fill();
ctx.lineWidth = y;
ctx.strokeStyle = x;
ctx.stroke();
}
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
.colortool div {
width: 15px;
height: 15px;
float: left;
margin-left: 2px;
}
.clear {
clear: both;
}
<!DOCTYPE HTML>
<html>
<body onload="init()">
<div class="canvasbody">
<canvas id="can" width="400" height="400" style="border:1px dotted #eee;"></canvas>
</div>
</body>
</html>

How to clear trails when drawing rectangles on an HMTL5 canvas

I am currently working on an application where I draw a rectangle on a canvas. I can draw the rectangle perfectly but then when I try to change the movement of the mouse to make the rectangle smaller there are trails that are left behind. How do I clear these trails when I make the rectangle's size smaller? below is my JavaScript code that I used. Thanks in advance.
function drawSquare() {
// creating a square
var w = lastX - startX;
var h = lastY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
context.beginPath();
context.rect(startX + offsetX, startY + offsetY, width, height);
context.fillStyle = "gold";
context.fill();
context.lineWidth = 1;
context.strokeStyle = 'red';
context.stroke();
canvas.style.cursor = "default";
}
function getMousePos(canvas, e) {
var rect = canvas.getBoundingClientRect();
return {
x: e.pageX - canvas.offsetLeft,
y: e.pageY - canvas.offsetTop,
};
}
function handleMouseDown(e) {
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
isDown = true;
if (isChecBoxClicked == true) {
mouseIsDown = 1;
startX = lastX;
startY = lastY;
var pos = getMousePos(canvas, e);
startX = lastX = pos.x;
startY = lastY = pos.y;
drawSquare();
}
else {
canvas.style.cursor = "default";
}
}
function handleMouseUp(e) {
// clear the dragging flag
isDown = false;
canvas.style.cursor = "default";
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
if (isChecBoxClicked == true)
{
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
function handleMouseMove(e) {
// if we're not dragging, exit
if (!isDown) {
return;
}
//if (defaultval == 1) {
// return;
//}
if (isChecBoxClicked == true) {
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
A canvas doesn't clear itself. At least not a 2D context, like you are using. If you keep drawing on it, the new graphics is placed on top of the old. You need to explicitly clear it:
context.clearRect(0, 0, canvas.width, canvas.height);
You will probably have to clear your canvas. If you are only drawing a square you will have to do that in the drawSquare function. If you are drawing multiple things you will have to do it in a higher function that redraws multiple things.
For clearing the whole canvas, you can use the following code:
context.clearRect ( 0 , 0 , canvas.width, canvas.height );
There are also a lot of canvas libraries that will manage this for you and optimize the areas redrawn (they might only clear a part of the canvas, so there are less pixels redrawn)

How do I show what the user's rectangle will look like?

I'm trying to draw a rectangle on canvas with a click, a mouse movement, and another click. How should I go about following the user's cursor after the first click and displaying a preview of a filled rectangle on canvas of what the shape would look like at any given coordinate.
So far, I can successfully create the rectangle without showing what the rectangle will look like at any coordinate.
Here is the code so far:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var drawingShape = false;
//function getMousePos(canvas, ev) {
//var rect = canvas.getBoundingClientRect();
//}
//canvas.addEventListener('mousemove', function (ev) {
//var mousePos = getMousePos(canvas, ev);
//}
function setMousePosition(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
$("#downlog").html("Down: " + mouseX + " / " + mouseY);
if (drawingShape) {
drawingShape = false;
ctx.beginPath();
ctx.fillStyle = "#FF0000";
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.fill();
} else {
drawingShape = true;
startX = mouseX;
startY = mouseY;
}
}
$("#canvas").mousedown(function (e) {
setMousePosition(e);
});
I attempted to use an event listener to mouse movement, as I saw in this HTML5 tutorial (http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/), but I'm unsure how to connect it with the existing code.
You can store the image whenever you start drawing and reload it everytime you want to edit it.
Here's my quick implementation based on your code, it needs some optimization (perhaps only capture the area you're planning to draw):
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var drawingShape = false;
var oldImage;
canvas.addEventListener('mousemove', function(e){
if(drawingShape){
ctx.putImageData(oldImage,0,0);
mouseX = parseInt(e.clientX - offsetX, 10);
mouseY = parseInt(e.clientY - offsetY, 10);
ctx.beginPath();
ctx.fillStyle = "#FF0000";
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.fill();
}
});
function setMousePosition(e) {
mouseX = parseInt(e.clientX - offsetX, 10);
mouseY = parseInt(e.clientY - offsetY, 10);
$("#downlog").html("Down: " + mouseX + " / " + mouseY);
if (drawingShape) {
drawingShape = false;
ctx.beginPath();
ctx.fillStyle = "#FF0000";
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.fill();
} else {
drawingShape = true;
startX = mouseX;
startY = mouseY;
oldImage = ctx.getImageData(0,0,canvas.width,canvas.height);
}
}
$("#canvas").mousedown(function (e) {
setMousePosition(e);
});
Notice how we store the image data in the mouse down event and retrieve it on each mouse move

Categories