【问题标题】:HTML5 canvas paint redrawing lineJoin not roundedHTML5画布重绘线加入未圆角
【发布时间】:2016-11-17 17:43:12
【问题描述】:

您好,我用撤消功能制作了一个绘画,我将所有坐标写入数组中,然后尝试撤消只是重绘没有最后一个坐标,但是当我重绘我的画布参数不正确时出现问题。我使用lineJoin = "roind",但重绘后我看到没有圆形..

这个结果在我绘制时以圆线开始和线结束:

撤消函数后没有圆开始和行结束的结果:

当我按坐标重绘所有绘图时,我不知道我的圆线在哪里消失了..

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

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    我认为您正在寻找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">

    【讨论】:

      【解决方案2】:

      @Kaiido 正确回答应用 lineCap='round' 将使重绘线的末端变圆。

      另外两个想法:

      1. 您应该考虑画布从文档左上角的偏移位置。否则,如果画布不在文档的左上角,您的 prevX 和 prevY 位置会稍微偏离。

      2. 如果您只允许开始和结束线帽圆整并且所有中间线帽对接,您将拥有更清晰的线(更少“凸出”)。将 linejoins 保留为 mitred 的默认值。

      这是示例代码和演示:

      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;
      }
      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>

      【讨论】:

        猜你喜欢
        • 2013-02-07
        • 2017-12-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-17
        • 1970-01-01
        相关资源
        最近更新 更多