HTML5Join Canvas Paint Repainting Not Rounded

Hi, I do as paint with the undo function, I write all the coordinates in the array, and then try to cancel only the redraw without the last coordinates, but there is a problem while I redraw my canvas settings incorrectly. I use lineJoin = "roind" , but after redrawing I see without a round.

this result with the start of the round and the end of the line while I draw: enter image description here

this result without rounding and end of line after undo function: enter image description here

I have no idea where my round lines disappear, and I redraw all the drawings in the coordinates.

 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"> 
+2
javascript html5 canvas
source share
2 answers

I think you are looking for ctx. lineCap property .
+ I changed your redraw function to use switch instead 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"> 
+2
source share

@Kaiido correctly answers that applying lineCap='round' will round off the ends of your redrawn line.

Two further thoughts:

  • You must consider the position of the canvas offset in the upper left corner of the document. Otherwise, the positions of prevX and prevY will be slightly disabled if the canvas is not in the upper left corner of the document.

  • You will have a clearer line (less "voluminous") if you allow rounding off of the rounding of only the start and end lines, and all time strips should be clogged. Leave the jojo string as the default.

Here is a sample code and demo:

 var canvas=document.getElementById("canvas"); var ctx=canvas.getContext("2d"); var cw=canvas.width; var ch=canvas.height; var $canvas=$("#canvas"); var canvasOffset=$canvas.offset(); var offsetX=canvasOffset.left; var offsetY=canvasOffset.top; var points = []; var size = 10; var prevX = 0; var prevY = 0; var isCanDraw = false; $("#canvas").on("mousedown", function(e) { isCanDraw = true; prevX = e.clientX-offsetX; prevY = e.clientY-offsetY; points.push({x: prevX, y: prevY, size: size, mode: "begin"}); }); $("#canvas").on("mousemove", function(e) { if(isCanDraw) { stroke(e.clientX-offsetX, e.clientY-offsetY); 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); var savedFillStyle=ctx.fillStyle; ctx.fillStyle=ctx.strokeStyle; var i=0; while(i<points.length){ var p=points[i]; // draw "begin" as circle instead of line ctx.beginPath(); ctx.arc(px,py,p.size/2,0,Math.PI*2); ctx.closePath(); ctx.fill(); // draw "draw" ctx.lineWidth=p.size; ctx.beginPath(); ctx.moveTo(px,py); i++; while(i<points.length && points[i].mode!='end'){ var p=points[i]; ctx.lineTo(px,py); i++; } ctx.stroke(); // draw "end" as circle instead of line var p=points[i]; ctx.beginPath(); ctx.arc(px,py,p.size/2,0,Math.PI*2); ctx.closePath(); ctx.fill(); i++; } ctx.fillStyle=savedFillStyle; } 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; } 
 body{ background-color: ivory; padding:10px; } #canvas{border:1px solid red;} 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <canvas id="canvas" width="500" height="300"></canvas> <input type="button" id="undo" value="undo"> </body> 
+2
source share

All Articles