William Jones
William Jones

Reputation: 1159

Why is this JavaScript canvas drawing app lagging?

I am making an HTML drawing app with JavaScript, following a tutorial from this page. I've got up to the point at the end of the 'Demo Colours' section, just before the 'Add Sizes' section.

I have made the app for myself but after a reasonable amount of drawing, the app begins to lag. The pen begins to delay behind the mouse, but most of all, when the colour is changed, it takes a considerable amount of time for the pen's colour to actually change.

I'm calling console.log when the button is pressed, telling me which button is pressed. These appear immediately when the button is pressed, but the colour still takes a while to change.

Here's the code:

<html>
  <head></head>
<body>
  <canvas id="lessonCanvas" width="800" height="500" style="border:1px solid black;"></canvas>
  <button id="colorPurple">Purple</button>
  <button id="colorGreen">Green</button>
  <button id="colorYellow">Yellow</button>
  <button id="colorBrown">Brown</button>

  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
  <script>
    //canvas drawing
    context = document.getElementById('lessonCanvas').getContext("2d");
    $('#lessonCanvas').mousedown(function(e){
      var mouseX = e.pageX - this.offsetLeft;
      var mouseY = e.pageY - this.offsetTop;

      paint = true;
      addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
      redraw();
    });
    $('#lessonCanvas').mousemove(function(e){
      if(paint){
        addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
        redraw();
      }
    });
    $('#lessonCanvas').mouseup(function(e){
      paint = false;
    });
    $('#lessonCanvas').mouseleave(function(e){
      paint = false;
    });

    var clickX = new Array();
    var clickY = new Array();
    var clickDrag = new Array();
    var clickSize = new Array();
    var curSize = "normal";
    var clickTool = new Array();
    var curTool = "crayon";
    var paint;

    function addClick(x, y, dragging) {
      clickX.push(x);
      clickY.push(y);
      clickDrag.push(dragging);
      if(curTool == "eraser"){
        clickColor.push("white");
      }else{
        clickColor.push(curColor);
      }
      clickColor.push(curColor);
      clickSize.push(curSize);
    }

    function redraw() {
      context.lineJoin = "round";
      /* context.lineWidth = 5; */
      for(var i=0; i < clickX.length; i++) {        
        context.beginPath();
        if(clickDrag[i] && i) {
          context.moveTo(clickX[i-1], clickY[i-1]);
        } else {
          context.moveTo(clickX[i]-1, clickY[i]);
        }
        context.lineTo(clickX[i], clickY[i]);
        context.closePath();
        context.strokeStyle = clickColor[i];
        context.lineWidth = curSize;
        context.stroke();
      }
    }

    var colorPurple = "#cb3594";
    var colorGreen = "#659b41";
    var colorYellow = "#ffcf33";
    var colorBrown = "#986928";

    var curColor = colorPurple;
    var clickColor = new Array();

    document.getElementById("colorPurple").onclick = function() {
      curColor = colorPurple;
      console.log("Color changed to purple.");
    }
    document.getElementById("colorGreen").onclick = function() {
      curColor = colorGreen;
      console.log("Color changed to green.");
    }
    document.getElementById("colorYellow").onclick = function() {
      curColor = colorYellow;
      console.log("Color changed to yellow.");
    }
    document.getElementById("colorBrown").onclick = function() {
      curColor = colorBrown;
      console.log("Color changed to brown.");
    }
  </script>
</body>
</html>

There's a demo at this page, which uses the exact same code but for some reason doesn't lag. Is this because my canvas is bigger, or is there some other problem I haven't noticed? Any help will be appreciated!

Upvotes: 1

Views: 1138

Answers (2)

JJJJ
JJJJ

Reputation: 1358

I also encountered this lag. I follow the tutorial here. After searching for solution I found this tutorial. After comparing, the reason why it is lagging it's because of this loop.

function redraw() {
  context.lineJoin = "round";
  /* context.lineWidth = 5; */
  for(var i=0; i < clickX.length; i++) {        
    context.beginPath();
    if(clickDrag[i] && i) {
      context.moveTo(clickX[i-1], clickY[i-1]);
    } else {
      context.moveTo(clickX[i]-1, clickY[i]);
    }
    context.lineTo(clickX[i], clickY[i]);
    context.closePath();
    context.strokeStyle = clickColor[i];
    context.lineWidth = curSize;
    context.stroke();
  }
}

The value saved in arrays does not reset and always looping every time the mouse move event occur. To solve this problem, Remove the addClick(), don't save it in array and just save the last x, y and color. YOu should also save the last x and y on mouse down event. Here's an example.

saveX;
saveY;
function redraw(x, y){
    ctx.beginPath();
    ctx.moveTo(saveX, saveY);
    ctx.lineTo(x, y);
    ctx.closePath();
    ctx.strokeStyle = selectedColor;
    ctx.lineJoin = 'round';
    ctx.lineWidth = curSize;
    ctx.stroke();
    saveX = x;
    saveY = y;
}

Upvotes: 0

Alen.Toma
Alen.Toma

Reputation: 4870

It dose not lag. You have done a mistake.

Have a look below at addClick There you are adding the same color twice and thats why you are getting this behavior.

I made smal change, read the comment at addClick

   
    var colorPurple = "#cb3594";
    var colorGreen = "#659b41";
    var colorYellow = "#ffcf33";
    var colorBrown = "#986928";

    var curColor = colorPurple;
    var clickColor = new Array();
   
   //canvas drawing
    context = document.getElementById('lessonCanvas').getContext("2d");
$('#lessonCanvas').mousedown(function(e){
      var mouseX = e.pageX - this.offsetLeft;
      var mouseY = e.pageY - this.offsetTop;

      paint = true;
      addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
      redraw();
    });
    $('#lessonCanvas').mousemove(function(e){
      if(paint){
        addClick(e.pageX - this.offsetLeft, e.pageY - this.offsetTop, true);
        redraw();
      }
    });
    $('#lessonCanvas').mouseup(function(e){
      paint = false;
    });
    $('#lessonCanvas').mouseleave(function(e){
      paint = false;
    });

    var clickX = new Array();
    var clickY = new Array();
    var clickDrag = new Array();
    var clickSize = new Array();
    var curSize = "normal";
    var clickTool = new Array();
    var curTool = "crayon";
    var paint;

    function addClick(x, y, dragging) {
      clickX.push(x);
      clickY.push(y);
      clickDrag.push(dragging);
      if(curTool == "eraser"){
        clickColor.push("white");
      }else{
         clickColor.push(curColor); 
      }
      // clickColor.push(curColor);//This should be removed
      clickSize.push(curSize);
    }

    function redraw() {
      context.lineJoin = "round";
      /* context.lineWidth = 5; */
      for(var i=0; i < clickX.length; i++) {        
        context.beginPath();
        if(clickDrag[i] && i) {
          context.moveTo(clickX[i-1], clickY[i-1]);
        } else {
          context.moveTo(clickX[i]-1, clickY[i]);
        }
        context.lineTo(clickX[i], clickY[i]);
        context.closePath();
        context.strokeStyle = clickColor[i];
        context.lineWidth = curSize;
        context.stroke();
      }
    }


    document.getElementById("colorPurple").onclick = function() {
      curColor = colorPurple;
      console.log("Color changed to purple.");
    }
    document.getElementById("colorGreen").onclick = function() {
      curColor = colorGreen;
      console.log("Color changed to green.");
    }
    document.getElementById("colorYellow").onclick = function() {
      curColor = colorYellow;
      console.log("Color changed to yellow.");
    }
    document.getElementById("colorBrown").onclick = function() {
      curColor = colorBrown;
      console.log("Color changed to brown.");
    }
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<canvas id="lessonCanvas" width="200" height="200" style="border:1px solid black;"></canvas>
  <button id="colorPurple">Purple</button>
  <button id="colorGreen">Green</button>
  <button id="colorYellow">Yellow</button>
  <button id="colorBrown">Brown</button>

Upvotes: 2

Related Questions