javascriptcanvaskeycode

Canvas draw rectangle only when keyboard is pressed


I am drawing rectangles on a canvas using mouse. However, I want to activate the mouse action to draw the rectangles only when key d is pressed on the key board.

If I use

if (event.ctrlKey) {
 //draw rectangles
} 

I am able to draw by holding the ctrlKey on the keyboard. However, if I use

if (e.which == 88) {
 //draw rectangles
}

it doesn't work. I am not able to bind the keyboard keypress events to mouse events on a canvas. I understand canvas element does not have onKeyPress event and as suggested in some of the blogs, I tried the following code, which doesn't work. How can I get started?

I have many events for which I have to bind the keyboard press event on the canvas.

<!doctype html>
<html>

<head>
    <meta charset="utf-8">
    <title>parallelogram</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>

<body>
    <canvas id="canvas" width="800" height="600" style="border:solid 1px;margin:0;padding:0;;z-index:1"></canvas>
</body>

</html>

<script type="text/javascript">
var canvas, context;
var dragging = false;
var startLocation;
var dragStartLocation;
var dragStopLocation;
var dragThirdLocation;
var snapshot;
var coords = [];
var pointsNum = 0;
var d = {
    x: 0,
    y: 0
};

//Get mouse click coordinates
function getCanvasCoordinates(event)
{
    var x = event.clientX - canvas.getBoundingClientRect().left;
    var y = event.clientY - canvas.getBoundingClientRect().top;
    return {
        x: x,
        y: y
    };
}

//save the canvas original state
function takeSnapShot()
{
    snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
}

//restore the canvas original state
function restoreSnapShot()
{
    context.putImageData(snapshot, 0, 0);
}

//draw a point on mouse click
function drawPoint(position)
{
    context.beginPath();
    context.arc(position.x, position.y, 5.5, 0, Math.PI * 2, false);
    context.stroke();
}

//draw a line on mouse move
function drawLine(start, end)
{
    context.beginPath();
    context.moveTo(start.x, start.y);
    context.lineTo(end.x, end.y);
    context.stroke();
}

//start the event with first mouse click
function dragStart(event)
{
    dragging = true;
    dragStartLocation = getCanvasCoordinates(event);
    coords['imageClicked'] = localStorage.getItem('clickedImage');
    console.log(coords);
    var brandNode = localStorage.getItem('brandNode');
    var locationNode = localStorage.getItem('locationNode');
    drawPoint(dragStartLocation);
    pointsNum++;
    takeSnapShot();
    if (pointsNum == 1) startLocation = dragStartLocation;
}

//draw a line along with the mouse move from the first click
function drag(event)
{
    var position;
    if (snapshot && pointsNum && pointsNum < 3)
    {
        restoreSnapShot();
        position = getCanvasCoordinates(event);
        drawLine(dragStartLocation, position);
        drawPoint(position);
        if (pointsNum == 2) drawFourthCoord(position)

    }
}

//stop the mouse movement and drawing line.
function dragStop(event)
{
    dragging = false;
    restoreSnapShot();
    var position = getCanvasCoordinates(event);
    dragStopLocation = position;
    drawPoint(dragStopLocation);
    pointsNum++;
    drawLine(dragStartLocation, dragStopLocation);
    takeSnapShot();
    d = {
        x: dragStartLocation.x - dragStopLocation.x,
        y: dragStartLocation.y - dragStopLocation.y
    };

    dragStartLocation = position;
    console.log(dragStartLocation);
    if (pointsNum > 3) pointsNum = 0;
}

//draw the fourth coordinate
function drawFourthCoord(position)
{
    var p = {
        x: position.x + d.x,
        y: position.y + d.y
    };
    drawLine(position, p);
    drawPoint(p);
    drawLine(startLocation, p);
}

/*
  This code works...but does not have binding to keyCode x
  function init() {
  canvas = document.getElementById('canvas');
  context = canvas.getContext('2d');
  context.lineCap = "round";
  context.lineWidth = 3;
  context.strokeStyle = '#f4d03f';
  canvas.addEventListener('mousedown', dragStart, false);
  canvas.addEventListener('mousemove', drag, false);
  canvas.addEventListener('mouseup', dragStop, false);  

}

window.addEventListener('load', init, false);
*/

var canvaskey = document.getElementById('canvas');
canvaskey.addEventListener('keydown', doKeyDown, true);

function doKeyDown(e)
{
    if (e.which == 88)
    {
        canvas = document.getElementById('canvas');
        context = canvas.getContext('2d');
        context.lineCap = "round";
        context.lineWidth = 3;
        context.strokeStyle = '#f4d03f';
        canvas.addEventListener('mousedown', dragStart, false);
        canvas.addEventListener('mousemove', drag, false);
        canvas.addEventListener('mouseup', dragStop, false);
    }
}
</script>


Solution

  • Simply hold a semaphor variable in the scope your drawing functions have access to.

    On keydown of required key, set it to true, on keyup to false.
    In the draw function, check the semaphor is set to true, otherwise, return promptly.

    // our keydown semaphor
    var d_down = false;
    
    function doKeyDown(e)
    {
        if (e.key == "d")
        {
          d_down = true;
        }
    }
    function doKeyUp(e)
    {
        if (e.key == "d")
        {
          d_down = false;
        }
    }
    
    
    var canvas, context;
    var dragging = false;
    var startLocation;
    var dragStartLocation;
    var dragStopLocation;
    var dragThirdLocation;
    var snapshot;
    var coords = [];
    var pointsNum = 0;
    var d = {
        x: 0,
        y: 0
    };
    
    //Get mouse click coordinates
    function getCanvasCoordinates(event)
    {
        var x = event.clientX - canvas.getBoundingClientRect().left;
        var y = event.clientY - canvas.getBoundingClientRect().top;
        return {
            x: x,
            y: y
        };
    }
    
    //save the canvas original state
    function takeSnapShot()
    {
        snapshot = context.getImageData(0, 0, canvas.width, canvas.height);
    }
    
    //restore the canvas original state
    function restoreSnapShot()
    {
        context.putImageData(snapshot, 0, 0);
    }
    
    //draw a point on mouse click
    function drawPoint(position)
    {
        context.beginPath();
        context.arc(position.x, position.y, 5.5, 0, Math.PI * 2, false);
        context.stroke();
    }
    
    //draw a line on mouse move
    function drawLine(start, end)
    {
        context.beginPath();
        context.moveTo(start.x, start.y);
        context.lineTo(end.x, end.y);
        context.stroke();
    }
    
    //start the event with first mouse click
    function dragStart(event)
    {
      // check our semaphor
      if(!d_down)
        return; // we're not allowed to go farther
        
        dragging = true;
        dragStartLocation = getCanvasCoordinates(event);
    /*    coords['imageClicked'] = localStorage.getItem('clickedImage');
        console.log(coords);
        var brandNode = localStorage.getItem('brandNode');
        var locationNode = localStorage.getItem('locationNode');*/
        drawPoint(dragStartLocation);
        pointsNum++;
        takeSnapShot();
        if (pointsNum == 1) startLocation = dragStartLocation;
    }
    
    //draw a line along with the mouse move from the first click
    function drag(event)
    {
      // check our semaphor
      if(!d_down)
        return; // we're not allowed to go farther
        var position;
        if (snapshot && pointsNum && pointsNum < 3)
        {
            restoreSnapShot();
            position = getCanvasCoordinates(event);
            drawLine(dragStartLocation, position);
            drawPoint(position);
            if (pointsNum == 2) drawFourthCoord(position)
    
        }
    }
    
    //stop the mouse movement and drawing line.
    function dragStop(event)
    {
        dragging = false;
      // check our semaphor
      if(!d_down)
        return; // we're not allowed to go farther
        restoreSnapShot();
        var position = getCanvasCoordinates(event);
        dragStopLocation = position;
        drawPoint(dragStopLocation);
        pointsNum++;
        drawLine(dragStartLocation, dragStopLocation);
        takeSnapShot();
        d = {
            x: dragStartLocation.x - dragStopLocation.x,
            y: dragStartLocation.y - dragStopLocation.y
        };
    
        dragStartLocation = position;
    //    console.log(dragStartLocation);
        if (pointsNum > 3) pointsNum = 0;
    }
    
    //draw the fourth coordinate
    function drawFourthCoord(position)
    {
        var p = {
            x: position.x + d.x,
            y: position.y + d.y
        };
        drawLine(position, p);
        drawPoint(p);
        drawLine(startLocation, p);
    }
    
      function init() {
      canvas = document.getElementById('canvas');
      context = canvas.getContext('2d');
      context.lineCap = "round";
      context.lineWidth = 3;
      context.strokeStyle = '#f4d03f';
      canvas.addEventListener('mousedown', dragStart, false);
      canvas.addEventListener('mousemove', drag, false);
      canvas.addEventListener('mouseup', dragStop, false); 
      snapshot = context.createImageData(1,1)
    
    }
    
    window.addEventListener('load', init, false);
    
    var canvaskey = document.getElementById('canvas');
    canvaskey.addEventListener('keydown', doKeyDown);
    canvaskey.addEventListener('keyup', doKeyUp);
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
    <canvas id="canvas" width="800" height="600" style="border:solid 1px;margin:0;padding:0;;z-index:1" tabindex="1"></canvas>