使用 canvas 绘制时钟。查询关于 save()

Using canvas to draw a clock. Query about the save()

我知道 save() 和 restore() 的功能,它们保存和恢复当前 canvas 状态。但对这些还没有深刻的认识。当程序调用绘制时钟的函数时,在重新绘制之前已经清除了所有的canvas。为什么还应在此处添加 save() 。谁能解释一下?谢谢。

window.onload=function(){

   var oCan=document.getElementById('clock');
   var oCanPen=oCan.getContext('2d');
   drawClock();
   setInterval(function(){
    drawClock();
   },1000);
   function drawClock(){
    // oCanPen.save();
    oCanPen.clearRect(0,0,oCan.width,oCan.height);
    var time=new Date();
    var second=time.getSeconds();
    var minute=time.getMinutes();
    var hour=time.getHours()+minute/60;

   oCanPen.save();

   oCanPen.beginPath();
   oCanPen.arc(200,200,100,0,360*Math.PI/180,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   for (var i = 0; i < 60; i++) {
    oCanPen.moveTo(200,200);
    oCanPen.arc(200,200,100,i*6*Math.PI/180,i*6*Math.PI/180,false);
    }
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   oCanPen.fillStyle='#fff';
   oCanPen.arc(200,200,90,0,360*Math.PI/180,false);
   oCanPen.closePath();
   oCanPen.fill();

   oCanPen.beginPath();
    for (var i = 0; i < 12; i++) {
    oCanPen.moveTo(200,200);
    oCanPen.arc(200,200,100,i*30*Math.PI/180,i*30*Math.PI/180,false);
    }
   oCanPen.closePath();
   oCanPen.stroke();


   oCanPen.beginPath();
   oCanPen.fillStyle='#fff';
   oCanPen.arc(200,200,80,0,360*Math.PI/180,false);
   oCanPen.closePath();
   oCanPen.fill();
   

   oCanPen.beginPath();
   oCanPen.strokeStyle='red';
   var iSecond=(-90+second*6)*Math.PI/180;
   oCanPen.moveTo(200,200);
   oCanPen.arc(200,200,85,iSecond,iSecond,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   oCanPen.lineWidth=4;
   oCanPen.strokeStyle='blue';
   var iMinute=(-90+minute*6)*Math.PI/180;
   oCanPen.moveTo(200,200);
   oCanPen.arc(200,200,60,iMinute,iMinute,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   oCanPen.lineWidth=6;
   var iHour=(-90+hour*30)*Math.PI/180;
   oCanPen.strokeStyle='black';
   oCanPen.moveTo(200,200);
   oCanPen.arc(200,200,40,iHour,iHour,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.restore();
  }

  };
 body{
  background: #333;
 }
 canvas{
  background: #f2f2f2;
 }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
 <title></title>

</head>
<body>

<canvas id="clock" width="400" height="400"></canvas>

</body>
</html>

保存和恢复不受位图内容的影响 - 它们只是按照您所说的那样处理状态,或者"settings"例如颜色样式、线宽、当前字体等

当您清除 canvas 时,状态保持不变。反之亦然,恢复状态时不会影响 canvas.

上的任何现有内容

典型用法是,如果您有自己喜欢的状态,但需要临时更改转换、样式等内容。绘制,然后恢复,这样您就可以恢复到原来的状态,而无需重置这些值。

在您的情况下,您可以更改 lineWidth 和 strokeStyles,而不必担心这些。

另一方面,如果您能够跟踪所有更改的状态值,则可以避免 save/restore。这在很多情况下比 save/restore 快,因为后者保存完整状态,而不仅仅是样式和线宽。

在你的情况下,你可以简单地删除 save/restore 并使用这行新代码来避免它:

..
var hour=time.getHours()+minute/60;

oCanPen.lineWidth = 1;

oCanPen.beginPath();
..              

window.onload=function(){

   var oCan=document.getElementById('clock');
   var oCanPen=oCan.getContext('2d');
   drawClock();
   setInterval(function(){
    drawClock();
   },1000);
   function drawClock(){
    // oCanPen.save();
    oCanPen.clearRect(0,0,oCan.width,oCan.height);
    var time=new Date();
    var second=time.getSeconds();
    var minute=time.getMinutes();
    var hour=time.getHours()+minute/60;

            oCanPen.lineWidth = 1;
              
   oCanPen.beginPath();
   oCanPen.arc(200,200,100,0,360*Math.PI/180,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   for (var i = 0; i < 60; i++) {
    oCanPen.moveTo(200,200);
    oCanPen.arc(200,200,100,i*6*Math.PI/180,i*6*Math.PI/180,false);
    }
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   oCanPen.fillStyle='#fff';
   oCanPen.arc(200,200,90,0,360*Math.PI/180,false);
   oCanPen.closePath();
   oCanPen.fill();

   oCanPen.beginPath();
    for (var i = 0; i < 12; i++) {
    oCanPen.moveTo(200,200);
    oCanPen.arc(200,200,100,i*30*Math.PI/180,i*30*Math.PI/180,false);
    }
   oCanPen.closePath();
   oCanPen.stroke();


   oCanPen.beginPath();
   oCanPen.fillStyle='#fff';
   oCanPen.arc(200,200,80,0,360*Math.PI/180,false);
   oCanPen.closePath();
   oCanPen.fill();
   

   oCanPen.beginPath();
   oCanPen.strokeStyle='red';
   var iSecond=(-90+second*6)*Math.PI/180;
   oCanPen.moveTo(200,200);
   oCanPen.arc(200,200,85,iSecond,iSecond,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   oCanPen.lineWidth=4;
   oCanPen.strokeStyle='blue';
   var iMinute=(-90+minute*6)*Math.PI/180;
   oCanPen.moveTo(200,200);
   oCanPen.arc(200,200,60,iMinute,iMinute,false);
   oCanPen.closePath();
   oCanPen.stroke();

   oCanPen.beginPath();
   oCanPen.lineWidth=6;
   var iHour=(-90+hour*30)*Math.PI/180;
   oCanPen.strokeStyle='black';
   oCanPen.moveTo(200,200);
   oCanPen.arc(200,200,40,iHour,iHour,false);
   oCanPen.closePath();
   oCanPen.stroke();

  }

  };
body{
  background: #333;
 }
 canvas{
  background: #f2f2f2;
 }
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
 <title></title>

</head>
<body>

<canvas id="clock" width="400" height="400"></canvas>

</body>
</html>