Just for fun and learning, I am trying to create a web based forms editor in the manner of Visual Studio. First requirement is the ability to draw a rectangle so that the outline follows the mouse movement while drawing. So with every mouse displacement, the previously drawn rectangle should be wiped. To achieve this, before drawing a new rectangle, I restore a snapshot of the canvas that was taken when the mouse button was pressed down.
This works well enough, the flickering is understandable but not too disturbing as long as I keep some continuous movement in the mouse. But what I fail to understand, and what is really annoying, is that the rectangle disappears as soon as I stop the mouse movement for more than a split second. I put a minimal test set in this Codepen [https://codepen.io/cbreemer/pen/mdgOQdQ] so the issue will be clear even is maybe my explanation wasn't.
I am hoping somebody can tell me what I am missing here.
I thought that maybe moving the rectangle-drawing code inside the image load handler (in the mouse move handler) might fix it. But sadly, then I don't see anything until the mouse button is released. I can't think of anything else to try.
var ctx;
var startX, startY, endX, endY, lastX, lastY;
var rect;
var lastCanvas;
var isMouseDown = false;
function init()
{
rect = myCanvas.getBoundingClientRect();
ctx = myCanvas.getContext("2d");
ctx.lineWidth = 1;
ctx.strokeStyle = "black";
ctx.fillStyle = "wheat";
ctx.fillRect(0, 0, rect.width, rect.height);
myCanvas.addEventListener("mousemove",(e)=>
{
if ( isMouseDown )
{
var canvasPic = new Image();
canvasPic.src = lastCanvas;
canvasPic.addEventListener("load", (e)=> { ctx.drawImage(canvasPic, 0, 0); });
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
ctx.strokeRect(startX, startY, x-startX, y-startY);
lastX = x;
lastY = y;
}
});
myCanvas.addEventListener("mousedown",(e)=>
{
lastCanvas = myCanvas.toDataURL();
startX = e.clientX - rect.left;
startY = e.clientY - rect.top;
lastX = startX;
lastY = startY;
isMouseDown = true;
});
myCanvas.addEventListener("mouseup",(e)=>
{
isMouseDown = false;
endX = e.clientX - rect.left;
endY = e.clientY - rect.top;
ctx.strokeRect(startX, startY, endX-startX, endY-startY);
});
}
<!DOCTYPE html>
<html>
<body onLoad="init();">
<canvas id="myCanvas" width="600" height="400" style="border:1px solid black"></canvas>
</body>
</html>
Taken from another answer of mine, Here's the basic idea of redrawing the canvas every tick of the
requestAnimationFrame. It also demonstrated how to better redraw image (taken usinggetImageData.