Check if canvas is drawn

Asked

Viewed 167 times

-1

Hello. I need some function to check if my canvas was designed by the user. The code is as follows::

    <canvas id="canvas">
        Este navegador não suporta esta função.
    </canvas>

    <script type="text/javascript">
    var canvas = document.getElementById('canvas');
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    var context = canvas.getContext('2d');
    var start = function(coors) {
        context.beginPath();
        context.moveTo(coors.x, coors.y);
        this.isDrawing = true;
    };
    var move = function(coors) {
        if (this.isDrawing) {
            context.strokeStyle = "#000";
            context.lineJoin = "round";
            context.lineWidth = 3;
            context.lineTo(coors.x, coors.y);
            context.stroke();
        }
    };
    var stop = function(coors) {
        if (this.isDrawing) {
            this.touchmove(coors);
            this.isDrawing = false;
        }
    };
    var drawer = {
        isDrawing: false,
        mousedown: start,
        mousemove: move,
        mouseup: stop,
        touchstart: start,
        touchmove: move,
        touchend: stop
    };
    var draw = function(e) {
        var coors = {
            x: e.clientX || e.targetTouches[0].pageX,
            y: e.clientY || e.targetTouches[0].pageY
        };
        drawer[e.type](coors);
    }
    canvas.addEventListener('mousedown', draw, false);
    canvas.addEventListener('mousemove', draw, false);
    canvas.addEventListener('mouseup', draw, false);
    canvas.addEventListener('touchstart', draw, false);
    canvas.addEventListener('touchmove', draw, false);
    canvas.addEventListener('touchend', draw, false);

    var go = function(e) {
            draw(e);
        }
    };

    document.getElementById('divCanvas').addEventListener('mousedown', go, false);
    document.getElementById('divCanvas').addEventListener('touchstart', go, false);

    // prevent elastic scrolling
    document.body.addEventListener('touchmove', function(e) {
        e.preventDefault();
    }, false);
    // end body:touchmove
    window.onresize = function(e) {
        canvas.width = document.body.clientWidth;
        canvas.height = document.body.clientHeight;
    };



    $('.aviso2').click(function(){
        context.clearRect(0, 0, canvas.width, canvas.height);
    });

    </script>

The user presses the mouse or touch and draws following his command. I need some function to check if the user really drew on the canvas. I need to see if the canvas is not blank.

I’ve tried using a slight gambit for that. When the user clicks the mouse or touch, I increment a variable with the time it is holding the click/mouse. So at the end, I do an if to see if this time was less than 5 seconds for example. If it is, it’s because he didn’t draw or draw incorrectly (just scribbled something fast).

There’s like?

  • What have you tried to do? Could you add to the question?

  • Sure, I’ll add

2 answers

2


Determining whether it is empty is "complicated" by the simple fact that one can draw something in "white", or draw something that is outside the visible area, yet yes I found this answer in Soen: https://stackoverflow.com/a/17386803/1518921

The first suggestion is from @Austinbrunkhorst using getImageData to search for the pixels "not colored", getting something like:

function isCanvasBlank(canvas) {
  return !canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height).data.some(function (channel) {
      return channel !== 0;
   });
}

Another suggestion from @Kaiido which states that it may be quicker to enumerate under the Uint32Array than go through each color channel in each pixel:

function isCanvasBlank(canvas) {
  const context = canvas.getContext('2d');

  const pixelBuffer = new Uint32Array(
    context.getImageData(0, 0, canvas.width, canvas.height).data.buffer
  );

  return !pixelBuffer.some(function (color) {  return color !== 0 });
}

I do not know if it really improves, because it would be to pass on the buffer, but perhaps if in fact the image is too big you may feel some advantage


Slow form:

function isCanvasBlank(canvas) {
  const blank = document.createElement('canvas');

  blank.width = canvas.width;
  blank.height = canvas.height;

  return canvas.toDataURL() === blank.toDataURL();
}

I do not believe that this form is only slow, I believe that it is inefficient, even the toDataURL returning similar results for something empty still can occur variations, even more if you have something that "polui" injected with putImageData() or drawimage() but it’s "invisible"


On the specific question

You quoted it as

If it is, it’s because he didn’t draw or draw incorrectly (just scribbled something fast).

But it’s complicated to state what a doodle is, an idea I had would be to use the getImageData() and calculate how many pixels are different from 0 determining a maximum limit of "100" (is an example) that may be different, this is a hypothetical code I did not get to test:

function CanvasAlmostEmpty(canvas)
{
      const pixelBuffer = new Uint32Array(
        context.getImageData(0, 0, canvas.width, canvas.height).data.buffer
      );

      const limite = 100;

      return pixelBuffer.filter(function (color) {
           return color !== 0;
      }).length <= 100;
}

In the example of the code was like this, it filters with .filter how many colors are different from "empty" and then with .length we will know how many pixels we have colored in the area, with .length <= limite check if you have crossed the limit, adjust this line to determine the limit:

 const limite = 100;

0

One way is to check through the events mousedown and mousemove (touchstart and touchmove for touch devices).

Imagine this: when the user clicks on the canvas area, it will trigger the event mousedown, If it drops the click, it will trigger the event mouseup, Okay? At the event mouseup will call the function stop. However, the user can simply click on the canvas and drop the mouse click without drawing anything. What determines that something was drawn is whether it clicked on the canvas and without calling the stop (event mouseup), it move the mouse (with the mouse button clicked).

The way I found it was by doing this check with 3 variaces:

var existe,     // se algo foi desenhado
    mouseDown,  // se clicou no canvas
    mouseMove;  // se moveu o mouse no canvas

When something has been designed, the variable existe will be changed to true, and the same thing for variables mouseDown and mouseMove.

For the last two variables, I used two if's within the function draw:

if(e.type == "mousedown" || e.type == "touchstart") mouseDown = true;
if( (e.type == "mousemove" || e.type == "touchmove") && mouseDown) mouseMove = true;

The first if detects one of the two events, mousedown and touchstart, and changes the variable mouseDown for true. If the events are immediately triggered mousemove or touchmove, and the variable mouseDown is true i change the variable mouseMove also to true.

In function stop I have another if which checks whether the variable mouseMove is false. If it is false, means those two if's in function draw were not satisfied, so I leave the variable mouseDown as false:

if(!mouseMove) mouseDown = false;

In the same role stop, I got a second if verifying whether the two variables, mouseDown and mouseMove, are true, meaning something was drawn on the canvas, and changes the variable existe for true:

if(mouseDown && mouseMove) existe = true;

So far so good, but there is an error in your code when used on touch devices (at least on the iPhone tested here): no event touchend, the property e.targetTouches is empty, generating an exception in e.targetTouches[0].pageX and e.targetTouches[0].pageY.

So I put a if to especially treat this event, keeping the last coordinates in two variables X and Y and passing these values to the object coors.

See the code below as it stood and test it on both desktop and touch device:

var existe, mouseDown, mouseMove;

function verifica(){
   if(existe){
      alert("Algo foi desenhado");
   }else{
      alert("Nada!");
   }
}

var canvas = document.getElementById('canvas');
    canvas.width = document.body.clientWidth;
    canvas.height = document.body.clientHeight;
    var context = canvas.getContext('2d');
    var start = function(coors) {
        context.beginPath();
        context.moveTo(coors.x, coors.y);
        this.isDrawing = true;
    };
    var move = function(coors) {
        if (this.isDrawing) {
            context.strokeStyle = "#000";
            context.lineJoin = "round";
            context.lineWidth = 3;
            context.lineTo(coors.x, coors.y);
            context.stroke();
        }
    };
    var stop = function(coors) {
        if (this.isDrawing) {
            this.touchmove(coors);
            this.isDrawing = false;
            if(!mouseMove) mouseDown = false;
            if(mouseDown && mouseMove) existe = true;
        }
    };
    var drawer = {
        isDrawing: false,
        mousedown: start,
        mousemove: move,
        mouseup: stop,
        touchstart: start,
        touchmove: move,
        touchend: stop
    };
    var draw = function(e) {
       if(e.type != "touchend"){
        var coors = {
            x: e.clientX || e.targetTouches[0].pageX.toString(),
            y: e.clientY || e.targetTouches[0].pageY.toString()
        };
        
        var lastX = coors.x;
        var lastY = coors.y;
       }else if(e.type == "touchend"){
        var coors = {
            x: lastX,
            y: lastY
        };
       }
        drawer[e.type](coors);
         if(e.type == "mousedown" || e.type == "touchstart") mouseDown = true;
         if( (e.type == "mousemove" || e.type == "touchmove") && mouseDown) mouseMove = true;
    }
    canvas.addEventListener('mousedown', draw, false);
    canvas.addEventListener('mousemove', draw, false);
    canvas.addEventListener('mouseup', draw, false);
    canvas.addEventListener('touchstart', draw, false);
    canvas.addEventListener('touchmove', draw, false);
    canvas.addEventListener('touchend', draw, false);

    var go = function(e) {
            draw(e);
        }
//    };

//    document.getElementById('divCanvas').addEventListener('mousedown', go, false);
//    document.getElementById('divCanvas').addEventListener('touchstart', go, false);

    // prevent elastic scrolling
    document.body.addEventListener('touchmove', function(e) {
        e.preventDefault();
    }, false);
    // end body:touchmove
    window.onresize = function(e) {
        canvas.width = document.body.clientWidth;
        canvas.height = document.body.clientHeight;
    };



    $('.aviso2').click(function(){
        context.clearRect(0, 0, canvas.width, canvas.height);
    });
body{
margin: 0;
}

#canvas{
   height: 100px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="canvas">
   Este navegador não suporta esta função.
</canvas>
<br>
Desenhe na área acima<br>
<button onclick="verifica()">Verifica se há desennho</button>

Browser other questions tagged

You are not signed in. Login or sign up in order to post.