7-4 canvas飘雪(下)
本节编程练习不计算学习进度,请电脑登录imooc.com操作

canvas飘雪(下)

右边的代码snowflake.js是完成的雪花代码,初学者可能会有点难度,尝试着慢慢理解下。在canvas飘雪(中)的基础上增加了运动的一个算法,然后把整个结构给规整了下。

入口是Snowflake函数,流程如下:

  1. 获取canvas节点,并设置容器尺寸
  2. initSnow方法创建雪球对象,保存在snowArrObjs容器中
  3. 创建render与update方法,主要是用来创建雪花并更新雪花的坐标
  4. 引入requestAnimationFrame方法,刷新雪花

雪球的变化会有一系列的参数设置,这里会用initSnow函数完成这个默认的参数选择,并增加了速率等参数设置。

雪球的坐标变化update方法:

Y轴:

this.y += this.speedY;
if (this.y > this.snowSettings.maxY) {
    this.y -= this.snowSettings.maxY;
}

this.speedY是一个增量,每次都叠加赋予,如果溢出后就会还原

X轴:

this.angle += this.speedX;
if (this.angle > Math.PI * 2) {
    this.angle -= Math.PI * 2;
}
this.x = this.initialX + this.moveX * Math.sin(this.angle);

X轴的变化是有个左右移动的,所以这里回用正玄值来计算左右的位移

移动:

在renderAndUpdate方法中,通过不断的调用requestAnimationFrame达到不断刷新雪球的坐标,感觉上雪球是不断在飘落

var renderAndUpdate = function() {
    render();
    update();
    requestAnimationFrame(renderAndUpdate);
}

任务

在snowflake.js文件141行处填入任务代码

计算出雪飘在x轴坐标中移动的距离

  1. <!DOCTYPE html>
  2. <html>
  3.  
  4. <head>
  5. <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
  6. <title>圣诞主题</title>
  7. <link rel='stylesheet' href='common.css' />
  8. <link rel="stylesheet" type="text/css" href="pageC.css">
  9. </head>
  10.  
  11. <body>
  12. <section class="container">
  13. <!-- 第一幅画面 -->
  14. <section class="page-a bg-adaptive">
  15. </section>
  16. <!-- 第二幅画面 -->
  17. <section class="page-b bg-adaptive">
  18. </section>
  19. <!-- 第三幅画面 -->
  20. <section class="page-c bg-adaptive">
  21. <!-- 窗户关闭 -->
  22. <div class="window wood">
  23. <div class="window-content" data-attr="red">
  24. <div class="window-scene-bg"></div>
  25. <div class="window-close-bg"></div>
  26. <div class="window-left hover"></div>
  27. <div class="window-right hover"></div>
  28. </div>
  29. </div>
  30. </section>
  31. <!-- 雪花 -->
  32. <canvas id="snowflake"></canvas>
  33. </section>
  34. <script type="text/javascript">
  35. var config = {};
  36. //rem设置
  37. (function(doc, win) {
  38. var docEl = doc.documentElement,
  39. resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize',
  40. recalc = function() {
  41. var clientWidth = docEl.clientWidth;
  42. if (!clientWidth) return;
  43. docEl.style.fontSize = 20 * (clientWidth / 320) + 'px';
  44. //宽与高度
  45. document.body.style.height = clientWidth * (900 / 1440) + "px"
  46. config.clientWidth = clientWidth;
  47. config.clientHeight = clientWidth * (900 / 1440)
  48. };
  49. win.addEventListener(resizeEvt, recalc, false);
  50. doc.addEventListener('DOMContentLoaded', recalc, false);
  51. })(document, window);
  52. </script>
  53. <script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script>
  54. <script type="text/javascript" src="snowflake.js"></script>
  55. </body>
  56.  
  57. </html>
  58.  
  1. /**
  2.  * 雪花
  3.  * canvas版
  4.  */
  5. $(function() {
  6.  
  7. /**
  8.   * 雪球
  9.   * @param {[type]} elementName [description]
  10.   */
  11. function Snowflake(elementName) {
  12.  
  13. var snowElement = document.getElementById(elementName)
  14. var canvasContext = snowElement.getContext("2d");
  15. var width = config.clientWidth;
  16. var height = config.clientHeight;
  17.  
  18. //canvas尺寸修正
  19. snowElement.width = width;
  20. snowElement.height = height;
  21.  
  22. //构建雪球的数量
  23. var snowNumber = 50;
  24.  
  25. //构建雪球对象
  26. var snowArrObjs = initSnow(snowNumber, width, height);
  27. var snowArrNum = snowArrObjs.length;
  28. /**
  29.   * 绘制页面
  30.   * @return {[type]} [description]
  31.   */
  32. var render = function() {
  33. //清理之前的矩形数据
  34. canvasContext.clearRect(0, 0, width, height);
  35. for (var i = 0; i < snowArrNum; ++i) {
  36. snowArrObjs[i].render(canvasContext);
  37. }
  38. }
  39.  
  40. /**
  41.   * 更新雪花
  42.   * @return {[type]} [description]
  43.   */
  44. var update = function() {
  45. for (var i = 0; i < snowArrNum; ++i) {
  46. snowArrObjs[i].update();
  47. }
  48. }
  49.  
  50. /**
  51.   * 绘制与更新
  52.   * @return {[type]} [description]
  53.   */
  54. var renderAndUpdate = function() {
  55. render();
  56. update();
  57. requestAnimationFrame(renderAndUpdate);
  58. }
  59.  
  60. renderAndUpdate();
  61. }
  62.  
  63. function initSnow(snowNumber, width, height) {
  64. //雪球参数
  65. var options = {
  66. //雪球的半球距离
  67. minRadius: 3,
  68. maxRadius: 10,
  69. // 运动的范围区域
  70. maxX: width,
  71. maxY: height,
  72. //速率
  73. minSpeedY: 0.05,
  74. maxSpeedY: 2,
  75. speedX: 0.05,
  76. //滤镜
  77. minAlpha: 0.5,
  78. maxAlpha: 1.0,
  79. minMoveX: 4,
  80. maxMoveX: 18
  81. }
  82. var snowArr = [];
  83. for (var i = 0; i < snowNumber; ++i) {
  84. snowArr[i] = new Snow(options);
  85. }
  86. return snowArr;
  87. }
  88.  
  89. /**
  90.   * 雪球类
  91.   */
  92. function Snow(snowSettings) {
  93. this.snowSettings = snowSettings;
  94. this.radius = randomInRange(snowSettings.minRadius, snowSettings.maxRadius);
  95. //初始的x位置
  96. this.initialX = Math.random() * snowSettings.maxX;
  97. this.y = -(Math.random() * 500);
  98. //运行的速率
  99. this.speedY = randomInRange(snowSettings.minSpeedY, snowSettings.maxSpeedY);
  100. this.speedX = snowSettings.speedX;
  101. //滤镜
  102. this.alpha = randomInRange(snowSettings.minAlpha, snowSettings.maxAlpha);
  103. //角度.默认是360
  104. this.angle = Math.random(Math.PI * 2);
  105. //运行的距离
  106. this.x = this.initialX + Math.sin(this.angle);
  107. //x移动距离
  108. this.moveX = randomInRange(snowSettings.minMoveX, snowSettings.maxMoveX);
  109. }
  110.  
  111. /**
  112.   * 绘制雪球
  113.   * @param {[type]} canvasContext [description]
  114.   * @return {[type]} [description]
  115.   */
  116. Snow.prototype.render = function(canvasContext) {
  117. //清除路径
  118. //开始一个画布中的一条新路径(或者子路径的一个集合)
  119. canvasContext.beginPath();
  120. //用来填充路径的当前的颜色,白色的雪球
  121. canvasContext.fillStyle = "rgba(255, 255, 255, " + this.alpha + ")";
  122. //一个中心点和半径,为一个画布的当前子路径添加一条弧线
  123. //坐标,圆,沿着圆指定弧的开始点和结束点的一个角度
  124. //弧沿着圆周的逆时针方向(TRUE)还是顺时针方向(FALSE)遍历
  125. canvasContext.arc(this.x, this.y, this.radius, 0, Math.PI * 2, true);
  126. //关闭子路径
  127. canvasContext.closePath();
  128. //fill() 方法使用 fillStyle 属性所指定的颜色、渐变和模式来填充当前路径
  129. canvasContext.fill();
  130. }
  131.  
  132. Snow.prototype.update = function() {
  133. this.y += this.speedY;
  134. if (this.y > this.snowSettings.maxY) {
  135. this.y -= this.snowSettings.maxY;
  136. }
  137. this.angle += this.speedX;
  138. if (this.angle > Math.PI * 2) {
  139. this.angle -= Math.PI * 2;
  140. }
  141. //?
  142. }
  143.  
  144.  
  145. /**
  146.   * 随机处理
  147.   * @param {[type]} min [description]
  148.   * @param {[type]} max [description]
  149.   * @return {[type]} [description]
  150.   */
  151. function randomInRange(min, max) {
  152. var random = Math.random() * (max - min) + min;
  153. return random;
  154. }
  155.  
  156.  
  157. Snowflake("snowflake")
  158. })
  159.  
  1. *{
  2. margin: 0;
  3. padding: 0;
  4. }
  5.  
  6.  
  7. .container {
  8. width: 100%;
  9. height: 100%;
  10. position: relative;
  11. overflow: hidden;
  12. }
  13.  
  14. .bg-adaptive {
  15. background-size: 100% 100%;
  16. }
  17.  
  1. .page-c {
  2. width : 100%;
  3. height : 100%;
  4. background-image: url("http://img1.sycdn.imooc.com//565d0b280001788014410901.png");
  5. position: absolute;
  6. z-index: 30;
  7. }
  8.  
  9.  
  10. #snowflake{
  11. position:absolute;
  12. left:0;
  13. top:0;
  14. z-index: 999999;
  15. }
  16.  
下一节