Your choice Your choice - 19 days ago 6
Javascript Question

HTML5 canvas paint redrawing lineJoin not rounded

Hello i make like a paint with undo function, i write all coordinates in array and then try undo just redrawing without last coordinates but problem while i redrawing my canvas parameters incorrect. i use

lineJoin = "roind"
but after redrawing i see without round..

this result with round line begin and line end while i drawing:
enter image description here

this result without round begin and line end after undo function:
enter image description here

I don't have idea where disappear my round lines while i redrawing all drawings coordinate by coordinate..



var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var points = [];
var size = 10;
var prevX = 0;
var prevY = 0;
var isCanDraw = false;

$("#canvas").on("mousedown", function(e) {
isCanDraw = true;

prevX = e.clientX;
prevY = e.clientY;
points.push({x: prevX, y: prevY, size: size, mode: "begin"});

});

$("#canvas").on("mousemove", function(e) {
if(isCanDraw) {
stroke(e.clientX, e.clientY);
points.push({x: prevX, y: prevY, size: size, mode: "draw"});
}
});

$("#canvas").on("mouseup", function(e) {
isCanDraw = false;
points.push({x: prevX, y: prevY, size: size, mode: "end"});
});

$("#canvas").on("mouseleave", function(e) {
isCanDraw = false;
});

$("#undo").on("click", function(e) {
deleteLast();
redraw();
});

function deleteLast() {
if(points.length != 0) {
var i = points.length - 1;
while(points[i].mode != "begin") {
i--;
points.pop();
}
points.pop();
}
}

function redraw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);

if(points.length != 0) {
for(var i=0; i < points.length; i++) {
var pt = points[i];

var begin=false;
if(size != pt.size) {
size = pt.size;
begin=true;
}

if(pt.mode == "begin" || begin) {
ctx.moveTo(pt.x, pt.y)
}

ctx.lineTo(pt.x, pt.y)

if( pt.mode == "end" || (i == points.length-1) ) {
ctx.lineJoin = "round";
ctx.stroke()
}
}

}
}

function stroke(x,y) {
ctx.lineWidth = size;
ctx.lineJoin = "round";

ctx.beginPath();
ctx.moveTo(prevX, prevY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
prevX = x;
prevY = y;
}

#canvas {
border: 1px solid #000;
}

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="300"></canvas>
<input type="button" id="undo" value="undo">




Answer

I think that you're looking for ctx.lineCap property.
+ I modified your redraw function to use a switchinstead of your confusing if statements :

    function redraw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.lineCap = "round";
        ctx.beginPath();

        for(var i=0; i < points.length; i++) {
            var pt = points[i];                
            switch(pt.mode){
                    case "begin" : ctx.moveTo(pt.x, pt.y); 
                    case "draw" : ctx.lineTo(pt.x, pt.y);
                    case "end" : ctx.stroke();
            }
        }
}

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var points = [];
var size = 10;
var prevX = 0;
var prevY = 0;
var isCanDraw = false;
var rect = canvas.getBoundingClientRect();

$("#canvas").on("mousedown", function(e) {
  isCanDraw = true;

  prevX = e.clientX;
  prevY = e.clientY;
  
  points.push({
    x: prevX,
    y: prevY,
    size: size,
    mode: "begin"
  });
  ctx.beginPath();
  ctx.arc(prevX, prevY, size/2, 0, Math.PI*2);
  ctx.fill();
});

$("#canvas").on("mousemove", function(e) {
  if (isCanDraw) {
    stroke(e.clientX - rect.left, e.clientY - rect.top);
    points.push({
      x: prevX,
      y: prevY,
      size: size,
      mode: "draw"
    });
  }
});

$("#canvas").on("mouseup", function(e) {
  isCanDraw = false;
  points.push({
    x: prevX,
    y: prevY,
    size: size,
    mode: "end"
  });
});

$("#canvas").on("mouseleave", function(e) {
  isCanDraw = false;
});

$("#undo").on("click", function(e) {
  deleteLast();
  redraw();
});

function deleteLast() {
  if (points.length != 0) {
    var i = points.length - 1;
    while (points[i].mode != "begin") {
      i--;
      points.pop();
    }
    points.pop();
  }
}

function redraw() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  ctx.lineCap = "round";
  ctx.beginPath();

  for (var i = 0; i < points.length; i++) {
    var pt = points[i];
    switch (pt.mode) {
      case "begin":
        ctx.moveTo(pt.x, pt.y);
      case "draw":
        ctx.lineTo(pt.x, pt.y);
      case "end":
        ctx.stroke();
    }
  }
}


function stroke(x, y) {
  ctx.lineWidth = size;
  ctx.lineJoin = "round";

  ctx.beginPath();
  ctx.moveTo(prevX, prevY);
  ctx.lineTo(x, y);
  ctx.closePath();
  ctx.stroke();
  prevX = x;
  prevY = y;
}
// debounce our rect update func
var scrolling = false;
function scrollHandler(){
  rect = canvas.getBoundingClientRect();
  scrolling = false;
  }
$(window).on('scroll resize', function(e){
  if(!scrolling){
    requestAnimationFrame(scrollHandler);
    }
 });
#canvas {
  border: 1px solid #000;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<canvas id="canvas" width="500" height="300"></canvas>
<input type="button" id="undo" value="undo">