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)
Related
I am using HTML5 Canvas with JavaScript. In the HTML layout, the canvas has a dynamic table above it. The table size is not static and changes at run-time depending on the parameter given. The problem I have is that when the table becomes long, it pushes the canvas down and the drawn image no longer shows. I know the drawn image is there because when I apply the following style code:
canvas {
position: absolute;
top: 0px;
left: 0px
}
the canvas moves to the top and the drawn image appears. Also, when the table is short, the canvas works fine.
I have tried using absolute and relative positioning on the table and canvas elements but that is not helping. I have tried getting the height of the table and applying a margin top to the canvas at run time but that didn't work. I have tried offsets, but they are not working either. I don't know what to do in order to keep the drawn image with the canvas element.
//declare variables
var canvas, context, flag = false;
var offsetX, offsetY;
var prevX; //initial position of mouse along x-axis
var currX; //new position of mouse along x-axis, initially set to 0
var prevY; //initial position of mouse along y axis
var currY; //new position of mouse along y axis, initially set to 0
var dot_draw = false;
var font_color = "black";
function startSignaturePad() {
canvas = document.getElementById('signaturepad'); //get the canvas element
if (canvas) {
context = canvas.getContext("2d"); //get the 2d drawing context
canvas.width = 400;
canvas.height = 150;
width = canvas.width;
height = canvas.height;
}
function reOffset() {
var BB = canvas.getBoundingClientRect();
offsetX = BB.left;
offsetY = BB.top;
}
reOffset();
window.onscroll = function(e) {
reOffset();
}
window.onresize = function(e) {
reOffset();
}
//bind the event listeners to the canvas
canvas.addEventListener("mousemove", function onMouseMove(e) {
getPositionXY('move', e)
}, false);
canvas.addEventListener("mousedown", function onMouseDown(e) {
getPositionXY('down', e)
}, false);
canvas.addEventListener("mouseup", function onMouseUp(e) {
getPositionXY('up', e)
}, false);
canvas.addEventListener("mouseout", function onMouseOut(e) {
getPositionXY('out', e)
}, false);
}
function draw() { //function to draw a dot at a specific position - grabs and then draws the position of x and y
context.beginPath();
context.moveTo(prevX, prevY);
context.lineTo(currX, currY);
context.strokeStyle = font_color;
context.lineWidth = font_size;
context.stroke();
context.closePath();
}
function erase() { //erase what is on the canvas
var erase = confirm("Are you sure you want to erase?");
if (erase) {
context.clearRect(0, 0, width, height);
}
}
function getPositionXY(mouse, e) {
if (mouse == 'down') {
prevX = currX; //reset previous position of x and y
prevY = currY;
currX = (e.clientX - canvas.offsetLeft) < (e.clientX - canvas.offsetX) ? e.clientX - canvas.offsetX : e.clientX - canvas.offsetLeft; //set new position of x and y
currY = (e.clientY - canvas.offsetTop) < (e.clientY - canvas.offsetY) ? e.clientY - canvas.offsetY : e.clientY - canvas.offsetTop;
flag = true;
dot_draw = true;
if (dot_draw) { //draw path while mouse is pressed down
context.textBaseline = "hanging";
context.beginPath();
context.fillStyle = font_color;
context.arc(currX, currY, 2, 0, 2 * Math.PI);
context.closePath();
dot_draw = false;
}
}
if (mouse == 'up' || mouse == "out") {
flag = false; //when mouse is released do nothing
}
if (mouse == 'move') {
if (flag) {
prevX = currX;
prevY = currY;
currX = (e.clientX - canvas.offsetLeft) < (e.clientX - canvas.offsetX) ? e.clientX - canvas.offsetX : e.clientX - canvas.offsetLeft;
currY = (e.clientY - canvas.offsetTop) < (e.clientY - canvas.offsetY) ? e.clientY - canvas.offsetY : e.clientY - canvas.offsetTop;
draw();
}
}
}
canvas {
position: absolute;
top: 0px;
left: 0px
}
<div>
<table>
<!-- some code -->
</table>
</div>
<div id="sigCanvas">
<canvas id="signaturepad" style="border:1px solid;"></canvas>
</div>
Since your canvas can move around, you want the latest position, so get it at the last possible instant.
Since your code works when the canvas is at (0,0), just adding
a call to reOffset() and the very beginning of getPositionXY() might do the trick.
If not, here is how I locate a mouse click relative to the canvas:
function locateMouse(evnt)
{
var x = evnt.pageX;
var y = evnt.pageY;
var c = canvas.getBoundingClientRect();
x = Math.floor(x) - c.left;
y = Math.floor(y) - c.top;
/// then use x and y however you want
}
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);
})();
});
I have an image gallery. When a image from gallery is clicked, it is rendered on a canvas. The objective is to allow users to draw rectangles on regions of interest and capture the rectangle coordinates. The drawn rectangles vanishes when I move to the next image.
The following is the code and I have tried to comment as much as I can:
//get clicked image name and store in a variable
function clickedImage(clicked_id) {
var clickedImg = document.getElementById(clicked_id).src;
var clickedImg = clickedImg.replace(/^.*[\\\/]/, '');
localStorage.setItem("clickedImg", clickedImg);
//initiate canvas to load image
var canvas = document.getElementById("iriscanvas");
var ctx = canvas.getContext("2d");
var thumbNails = document.getElementById("loaded_img_panel");
var pic = new Image();
pic.onload = function() {
ctx.drawImage(pic, 0,0)
}
//load the image from the thumbnail on to the canvas
thumbNails.addEventListener('click', function(event) {
pic.src = event.target.src;
});
//thickness of rectangle and count of rectangles
var strokeWidth = 3;
drawCount = 1;
//initiate mouse events
canvas.addEventListener("mousemove", function(e) {
drawRectangleOnCanvas.handleMouseMove(e);
}, false);
canvas.addEventListener("mousedown", function(e) {
drawRectangleOnCanvas.handleMouseDown(e);
}, false);
canvas.addEventListener("mouseup", function(e) {
drawRectangleOnCanvas.handleMouseUp(e);
}, false);
canvas.addEventListener("mouseout", function(e) {
drawRectangleOnCanvas.handleMouseOut(e);
}, false);
function reOffset() {
var BB = canvas.getBoundingClientRect();
recOffsetX = BB.left;
recOffsetY = BB.top;
}
var recOffsetX, recOffsetY;
reOffset();
window.onscroll = function(e) {
reOffset();
}
window.onresize = function(e) {
reOffset();
}
var isRecDown = false;
var startX, startY;
var rects = [];
var newRect;
var drawRectangleOnCanvas = {
handleMouseDown: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX = parseInt(e.clientX - recOffsetX);
startY = parseInt(e.clientY - recOffsetY);
// Put your mousedown stuff here
isRecDown = true;
},
handleMouseUp: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
// Put your mouseup stuff here
isRecDown = false;
//if(!willOverlap(newRect)){
rects.push(newRect);
//}
drawRectangleOnCanvas.drawAll();
var brand = localStorage.getItem("brandNode");
var clickImg = localStorage.getItem("clickedImg");
//get x,y,w,h coordinates depending on how the rectangle is drawn.
if((mouseX-startX) < 0) {
stX = startX + (mouseX-startX)
} else {
stX = startX
}
if((mouseY-startY) < 0) {
stY = startY + (mouseY-startY)
} else {
stY = startY
}
if((mouseX-startX) < 0) {
stW = startX - stX
} else {
stW = mouseX - startX
}
if((mouseY-startY) < 0) {
stH = startY - stY
} else {
stH = mouseY - startY
}
//log the coordinates of the rectangles
var dat = {image : clickImg, brand: brand, x : stX, y : stY, w: stW, h: stH};
var dat = JSON.stringify(dat);
console.log(dat);
},
drawAll: function() {
ctx.drawImage(pic, 0, 0);
ctx.lineWidth = strokeWidth;
var brand = localStorage.getItem("brandNode");
for (var i = 0; i < rects.length; i++) {
var r = rects[i];
ctx.strokeStyle = r.color;
ctx.globalAlpha = 1;
ctx.strokeRect(r.left, r.top, r.right - r.left, r.bottom - r.top);
ctx.beginPath();
//ctx.arc(r.left, r.top, 15, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = r.color;
ctx.fill();
var text = brand;
ctx.fillStyle = "#fff";
var font = "bold " + 12 + "px serif";
ctx.font = font;
var width = ctx.measureText(text).width;
var height = ctx.measureText("h").height; // this is a GUESS of height
ctx.fillText(text, r.left-1, r.top - 10)
}
},
handleMouseOut: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
// Put your mouseOut stuff here
isRecDown = false;
},
handleMouseMove: function(e) {
if (!isRecDown) {
return;
}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
newRect = {
left: Math.min(startX, mouseX),
right: Math.max(startX, mouseX),
top: Math.min(startY, mouseY),
bottom: Math.max(startY, mouseY),
color: "#9afe2e"
}
drawRectangleOnCanvas.drawAll();
ctx.strokeStyle = "#9afe2e";
ctx.lineWidth = strokeWidth;
ctx.globalAlpha = 1;
ctx.strokeRect(startX, startY, mouseX - startX, mouseY - startY);
}
}
}
When I move to the next image the rectangles created on the previous image is removed. I don't know if I have to use canvas.toDataURL to retain the rectangles, because I have thousands of images in the gallery and not sure if I will have space in the browser, though not all the images are going to the used for drawing rectangles.
Moreover, after drawing the rectangles when I click on the same image, it clears all the rectangles.
How can I retain the drawn rectangles within a session at least?
Layer 2 canvases over each other. Render the image into the bottom canvas, and draw on the top one. That way, changing the image won't affect the drawn lines.
A <canvas> works just like a real-life painter's canvas. There is no concept of layers or "objects" on a canvas. It's all just paint on a single surface.
When you draw a different image on a canvas, you're overriding everything that was on the canvas already.
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>
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