H5 Canvas | 画布中变量作用域与setInterval方法同步执行探究
Demo - 随机绘制圆环
实现思路:
- 将一个圆环的绘制分成100份,setInterval()方法定义每隔时间n绘制一段新的,每份的开始路径都是上一次的结束路径,实现步进绘制。
- 通过Math.random(),随机生成圆的坐标半径颜色。
实现方法:
- 定义画布和联系
- 设置步进属性
- 设置随机圆属性(5个参数:x,y,半径,开始,结束,方向)
- 循环执行绘画
<<index.html>>
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <style type="text/css"> #canvas { border: 1px black solid; } </style> </head> <body> <canvas id="canvas" width="1000" height="400">您的浏览器不支持canvas</canvas> <input type="button" onclick="InitDraw()" value="draw"> <script type="text/javascript"> function InitDraw() { var canvas = document.getElementById('canvas'); var ctx = canvas.getContext('2d'); var ctx2 = canvas.getContext('2d'); var step; // var sAngle; // var eAngle; var x, y, r; var add, stepTime, counterClockwise; // 步进属性 step = 0; add = Math.PI * 2 / 100; stepTime = 20; // 随机圆属性 sAngle = 0; eAngle = sAngle + add; counterClockwise = false; x = Math.random() * 800 + 100; y = Math.random() * 200 + 100; r = Math.random() * 50 + 50; ctx.strokeStyle = "#" + (Math.random() * 0x1000000 << 0).toString(16); ctx.shadowColor = "#" + (Math.random() * 0x1000000 << 0).toString(16); console.log(ctx.strokeStyle); console.log(ctx2.strokeStyle); ctx.lineWidth = 1.0; ctx.shadowOffsetX = 0; ctx.shadowOffsetY = 0; ctx.shadowBlur = 10; // 画圆 var drawID = setInterval(Draw, stepTime); function Draw() { if (step < 100) { // 绘制路径并画 ctx.beginPath(); ctx.arc(x, y, r, sAngle, eAngle, counterClockwise); ctx.stroke(); ctx.closePath(); // 步进 sAngle = eAngle; eAngle += add; // console.log("drawID:" + drawID + ",step:" + step); // console.log(ctx.strokeStyle); step++; } else { clearInterval(drawID); } } } </script> </body> </html>
在不同的变量环境下出现了不同的情况:
-
全局变量:step, sAngle, eAngle , x, y, r;
在执行绘图过程中持续变化的参数是step,sAngle,eAngle,再次调用时回到函数InitDraw();重新定义六个全局变量以及画笔样式,则重新开始绘图。上一个step和画笔样式都停留在按下button的一刻
-
全局变量:sAngle, eAngle; 局部变量:var step, x, y, r;
在控制台输出情况可以看到,当起始位置为全局变量时相互干扰的非常厉害,但因为step是局部变量,调用的是不同的副本,最后两个圈均执行到了99。并且可以看到控制台中drawID是间隔出现的,对两次setInterval方法轮流执行,也就造成了sAngle位置是跳跃的虚点。
-
局部变量:var step ,sAngle, eAngle, x, y, r;
但要注意的是在该示例中共用同一个画布和联系(ctx),在这里画笔的颜色和样式被刷新成为新的。那么应该如何在同一画布中同时绘画不同样式?
-
全局变量:step; 局部变量:var sAngle, eAngle, x, y, r;
在第二次点击出现的圈绘到约半圈时停止
点击button重新执行InitDraw();step=0; 从打印信息可以看到两个不同的setInterval方法对step变量相互干扰,直到step有机会到达99时停止绘图。
- ...一共64种变化,谨慎定义Canvas中的变量作用域
关于Context的另一个测试:
在同一个画布中调用获取两个Context,但通过输出可以看到每个画布只有一个对应的Context
经过几个Demo的分析得到以下结论:
- 在调用同一个function时候,私有变量互不相干,会像C一样得到不同的副本各自存值
- Canvas的Context样式(strokeStyle/shadowColor/...)是针对该Canvas(画布)唯一的
- 如果同时调用setInterval方法,则轮流执行,1,2,1,2,1,2...以此类推
- 谨慎使用setInterval方法,同时运行多个会导致相互干扰
遗留问题:
- 如何同时绘画不同样式?