第一步:画一个米字格,先画一个矩形,再画中间的米字。

<script>
window.onload = function(){
  var canvas = document.getElementById('canvas');
  var context = canvas.getContext('2d');

  canvas.width = 600;
  canvas.height = canvas.width;
  var color ="black";
  //画出田字格
  drawGrid();


  //田字格
  function drawGrid(){
    context.save();
    context.strokeStyle = "rgb(230,11,9)";
    context.beginPath();
    context.moveTo(3,3);
    context.lineTo(canvas.width - 3,3);
    context.lineTo(canvas.width - 3,canvas.height -3);
    context.lineTo(3,canvas.height -3);
    context.closePath();

    context.lineWidth = 6;
    context.stroke();

    context.beginPath();
    context.moveTo(0,0);
    context.lineTo(canvas.width,canvas.height);

    context.moveTo(canvas.width,0);
    context.lineTo(0,canvas.height);

    context.moveTo(canvas.width/2,0);
    context.lineTo(canvas.width/2,canvas.height);

    context.moveTo(0,canvas.width/2);
    context.lineTo(canvas.width,canvas.height/2);
    context.lineWidth=1;
    context.stroke();
    context.restore();

  }
}
</script>

canvas学写一个字

第二步.鼠标的四种状态:onmousedown、onmouseup、onmouseout、onmousemove。

根据分析写字的主要操作操作在onmousemove事件下进行的。鼠标onmouseup、onmouseout的时候应该停止写字。鼠标onmousedown触发写字。

所以需先判断鼠标是否按下,如果按下则onmousemove开始执行写字操作。否则不执行。

var isMouseDown = false; //初始化鼠标是否按下

canvas.onmousedown=function(e){//鼠标按下
      e.preventDefault();
      isMouseDown = true;
      console.log("...onmousedown");
}
canvas.onmouseup=function(e){//鼠标起来
      e.preventDefault();
      isMouseDown = false;
      console.log("...onmouseup");
}
canvas.onmouseout=function(e){//鼠标离开
      e.preventDefault();
      isMouseDown = false;
      console.log("...onmouseout");
}
canvas.onmousemove=function(e){//鼠标移动
     e.preventDefault();
         if(isMouseDown){
             console.log("...onmousemove");
         }    
}

canvas学写一个字

第三步:在canvas中写字,相当于鼠标移动的时候不停地画直线。那么问题来了,画直线就需要获得起始坐标。e.clientX,e.clientY只能获得当前屏幕的坐标,而我们需要的是canvas里面的坐标。

接下来我们需要想办法得到canvas的坐标了。在canvas中有一个方法getBoundingClientRect()可以获得canvas距离屏幕的距离。

我们可以通过获得光标屏幕坐标 - canvas距离屏幕的距离来得到光标在canvas中的坐标。

但是怎么确认哪个是起始位置,哪个是结束位置呢?所以一开始会初始化一个一开始的位置,lastLoc = {x:0,y:0};当鼠标落下,记录光标位置赋值给lastLoc。鼠标移动的时候获得当前坐标curLoc作为结束位置。

绘制结束后,将curLoc的值赋给lastLoc。所以每一次鼠标移动画直线的起始坐标为上一次的结束坐标,结束坐标为当前鼠标坐标。

  var isMouseDown = false; //鼠标是否按下
  var lastLoc = {x:0,y:0};//初始化鼠标上一次所在位置

  canvas.onmousedown=function(e){
      e.preventDefault();
      isMouseDown = true;
      lastLoc = windowToCanvas(e.clientX,e.clientY);//上一次的坐标
  }

 canvas.onmousemove=function(e){
         e.preventDefault();
         if(isMouseDown){
                //draw
                var curLoc = windowToCanvas(e.clientX,e.clientY);//获得当前坐标
                
                var lineWidth = 5;
                context.lineWidth=lineWidth;

                context.beginPath();
                context.moveTo(lastLoc.x,lastLoc.y);//起始位置为鼠标落下的位置
                context.lineTo(curLoc.x,curLoc.y);//结束位置为当前位置

                context.strokeStyle=color;
                context.stroke();
            
                lastLoc = curLoc;//将当前坐标赋值给上一次坐标
                lastLineWidth = lineWidth;
          }
            
     }


     //获得canvas坐标
     function windowToCanvas(x,y){
            var bbox = canvas.getBoundingClientRect();
            return {x:Math.round(x-bbox.left),y:Math.round(y-bbox.top)};
     }

canvas学写一个字canvas学写一个字

 

 现在写字功能已经完成了,但是我们需要对他进行优化。

优化一:当把context.lineWidth改大一些的时候,我们会发现,写字功能变得很不光滑了。

              canvas学写一个字

    这是什么原因呢,我们可以尝试画两条宽度很大的直线看一下,两条直线之间确实是有缺口存在的,并且跟线的宽度有关。所以学写一个字会出现毛糙现象。

            canvas学写一个字

    解决方法:设定线段端点的形状(线帽)

canvas.onmousemove=function(e){
            e.preventDefault();
            if(isMouseDown){
                //draw
                var curLoc = windowToCanvas(e.clientX,e.clientY);//获得当前坐标
                
                var lineWidth = 30;
                context.lineWidth=lineWidth;

                context.beginPath();
                context.moveTo(lastLoc.x,lastLoc.y);
                context.lineTo(curLoc.x,curLoc.y);

                context.strokeStyle=color;
                context.lineCap = "round"
                context.lineJoin = "round"
                context.stroke();
            
                lastLoc = curLoc;
                lastTimestamp = curTimestamp;
                lastLineWidth = lineWidth;
            }
            
        }
View Code

相关文章: