HTML5画布绘制重绘lineJoin不圆

时间:2015-02-02 15:57:20

标签: javascript html5 canvas

你好,我做了一个具有撤销功能的绘画,我写了数组中的所有坐标,然后尝试撤消只重绘没有最后的坐标但问题,而我重绘我的画布参数不正确。我使用lineJoin = "roind"但是在重新绘制后我看到没有圆...

这个结果是圆形线开始和线条结束,而我绘图: enter image description here

此结果在撤销功能后没有圆形开始和行结束: enter image description here

当我通过坐标重新绘制所有绘图坐标时,我不知道哪里会消失我的圆形线。



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;
    }
&#13;
#canvas {
    border: 1px solid #000;
}
&#13;
<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">
&#13;
&#13;
&#13;

2 个答案:

答案 0 :(得分:2)

我认为您正在寻找ctx.lineCap property +我修改了你的重绘函数,使用switch而不是令人困惑的if语句:

    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">

答案 1 :(得分:2)

@Kaiido正确回答应用lineCap='round'会绕过重绘行的末尾。

还有两个想法:

  1. 您应该从文档的左上角考虑画布的偏移位置。否则你的prevX&amp;如果画布不在文档的左上角,则prevy位置将稍微关闭。

  2. 如果您只允许将开始和结束的线条打包并且所有临时线路盖都要对接,那么您将拥有更清晰的线条(更少&#34;凸起&#34;)。将linejoins保留为mitered的默认值。

  3. 以下是示例代码和演示:

    &#13;
    &#13;
    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(p.x,p.y,p.size/2,0,Math.PI*2);
        ctx.closePath();
        ctx.fill();
    
        // draw "draw"
        ctx.lineWidth=p.size;
        ctx.beginPath();
        ctx.moveTo(p.x,p.y);
        i++;
        while(i<points.length && points[i].mode!='end'){
          var p=points[i];
          ctx.lineTo(p.x,p.y);
          i++;
        }
        ctx.stroke();
    
        // draw "end" as circle instead of line
        var p=points[i];
        ctx.beginPath();
        ctx.arc(p.x,p.y,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;
    }
    &#13;
    body{ background-color: ivory; padding:10px; }
    #canvas{border:1px solid red;}
    &#13;
    <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>
    &#13;
    &#13;
    &#13;