Guest User

Let It Snow V2 Full Code

a guest
Nov 26th, 2017
355
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.37 KB | None | 0 0
  1. (function() {
  2.  
  3. /**
  4. * A timer class used to measure differences in two times or count down to completion.
  5. * @author Rock
  6. */
  7. class Timer {
  8. /**
  9. * @param {number} duration The duration of the timer. Not really needed if using as a stopwatch
  10. * @param {boolean} auto_start
  11. */
  12. constructor(duration, auto_start = true) {
  13. /**
  14. * Technically this is the "start time" but it's really just used for the offset to get `time_running` and `time_remaining` because pausing will cause this to change
  15. */
  16. this._start_time = Date.now();
  17. this._paused = true;
  18. this._paused_at = Date.now();
  19.  
  20. this.duration = duration;
  21.  
  22. if(auto_start) this.start();
  23. }
  24.  
  25. /** Returns the current elapsed time of the timer */
  26. get elapsed_time() {
  27. if(!this.paused) return Date.now() - this._start_time;
  28. return this._paused_at - this._start_time;
  29. }
  30.  
  31. /** Returns the time remaining */
  32. get remaining_time() {
  33. return Math.max(0, this.duration - this.elapsed_time);
  34. }
  35.  
  36. /** Retruns whether the timer is paused or not */
  37. get paused() {
  38. return this._paused;
  39. }
  40.  
  41. /** Returns whether the timer has completed (reached 0ms) */
  42. get is_complete() {
  43. return this.elapsed_time >= this.duration;
  44. }
  45.  
  46. /** Starts or resumes the timer. */
  47. start() {
  48. this._start_time = Date.now() - this.elapsed_time;
  49. this._paused = false;
  50. return this;
  51. }
  52.  
  53. /** Resets the timer without pausing */
  54. reset() {
  55. this._paused_at = this._start_time = Date.now();
  56. return this;
  57. }
  58.  
  59. /** Pauses the timer without resetting it */
  60. pause() {
  61. this._paused = true;
  62. this._paused_at = Date.now();
  63. return this;
  64. }
  65.  
  66. /** Stops and resets the timer */
  67. stop() {
  68. this._paused = true;
  69. return this;
  70. }
  71. }
  72. /** @type {HTMLCanvasElement} */
  73. const canvas = document.createElement("canvas");
  74. canvas.style.position = "fixed";
  75. canvas.style.left = 0;
  76. canvas.style.top = 0;
  77. canvas.style.width = "100vw";
  78. canvas.style.height = "100vh";
  79. canvas.style.zIndex = "100000";
  80. canvas.style.pointerEvents = "none";
  81. document.body.insertBefore(canvas, document.body.children[0]);
  82.  
  83. const ctx = canvas.getContext("2d");
  84.  
  85. const num_flakes = 300,
  86. wind_change_speed = 0.0005,
  87. fall_speed_coefficient = 50,
  88. wind_speed = 15
  89. scale_coefficient_1 = 3;
  90. scale_min = 0.8
  91. scale_coefficient = 1,
  92. screen_max_overlap = 20,
  93. min_fall_speed = 65;
  94. let screen_width = canvas.width = window.innerWidth,
  95. screen_height = canvas.height = window.innerHeight;
  96. v_overlap_threshhold = screen_height + screen_max_overlap;
  97. h_overlap_threshhold = screen_width + screen_max_overlap;
  98.  
  99. // Creating one snowflake image and re-using it is MUCH faster to render
  100. // This is the raidus a snowlfake can have
  101. const max_snowflake_size = (scale_coefficient_1 + scale_min) * scale_coefficient;
  102. /** Misleading variable name. This is the max diameter of the snowflakes *when drawn to the screen* it's actually double this in the background canvas */
  103. const snowflake_diameter = max_snowflake_size * 2;
  104. const snowflake_canvas_dimensions = snowflake_diameter * 2;
  105. const snowflake_canvas = flake_canvas = document.createElement("canvas")
  106. const sCtx = snowflake_canvas.getContext("2d");
  107. const flakeGradient = sCtx.createRadialGradient(snowflake_diameter, snowflake_diameter, 0, snowflake_diameter, snowflake_diameter, snowflake_diameter);
  108. flakeGradient.addColorStop(0, 'hsla(255,255%,255%,1)');
  109. flakeGradient.addColorStop(1, 'hsla(255,255%,255%,0)');
  110. sCtx.fillStyle = flakeGradient;
  111. sCtx.fillRect(0, 0, snowflake_canvas_dimensions, snowflake_canvas_dimensions);
  112.  
  113.  
  114. let dtTimer = new Timer(0, true);
  115. var snowflakes = [];
  116.  
  117. let wind_timer = new Timer(0, true);
  118. for (var i = 0; i < num_flakes; ++i) {
  119. const flake = new Flake();
  120. flake.y = Math.random() * (screen_height + screen_max_overlap);
  121. flake.x = Math.random() * screen_width;
  122. flake.sz = (Math.random() * scale_coefficient_1 + scale_min) * scale_coefficient;
  123. flake.dy = (Math.pow(flake.sz, 2.5) * .1) * fall_speed_coefficient * (Math.random() * 2 + 1);
  124. flake.dy = flake.dy < min_fall_speed ? min_fall_speed : flake.dy;
  125.  
  126. flake.final_scale_coefficient = flake.sz / snowflake_diameter;
  127.  
  128. flake.dy_squared = flake.dy * flake.dy;
  129.  
  130. flake.wind_offset = Math.random() * Math.PI / 1.3;
  131.  
  132. flake.dx_coefficient = flake.sz * wind_speed;
  133.  
  134. flake.dx = 0;
  135. flake.speed = 0;
  136.  
  137. snowflakes.push(flake);
  138. }
  139. function frame() {
  140. ctx.clearRect(0, 0, screen_width, screen_height);
  141. //ctx.fillStyle = 'hsla(242, 95%, 3%, 1)';
  142. //ctx.fillRect(0, 0, screen_width, screen_height);
  143. ctx.fill();
  144. window.requestAnimationFrame(frame);
  145. const dt = dtTimer.elapsed_time * (1 / 1000);
  146. dtTimer.reset();
  147. const wind_state = wind_timer.elapsed_time * wind_change_speed;
  148. for (var i = 0; i < snowflakes.length; ++i) {
  149. const flake = snowflakes[i];
  150. flake.dx = Math.sin(wind_state + flake.wind_offset) * flake.dx_coefficient;
  151. flake.speed = Math.sqrt(flake.dx * flake.dx + flake.dy_squared);
  152. flake.y += flake.dy * dt;
  153. flake.x += flake.dx * dt;
  154. if (flake.y > v_overlap_threshhold) flake.y = -screen_max_overlap;
  155. if (flake.x > h_overlap_threshhold) flake.x = -screen_max_overlap;
  156. if (flake.x < -screen_max_overlap) flake.x = h_overlap_threshhold;
  157. flake.draw();
  158. }
  159. }
  160. function Flake() {
  161. this.draw = function () {
  162. const angle = Math.atan(this.dx / this.dy);
  163.  
  164. ctx.save();
  165. ctx.translate(this.x, this.y);
  166. ctx.rotate(-angle);
  167. ctx.scale(this.final_scale_coefficient, this.final_scale_coefficient * Math.max(1, Math.pow(this.speed, 0.7) / 15))
  168. ctx.drawImage(snowflake_canvas, -snowflake_canvas_dimensions / 2, -snowflake_canvas_dimensions / 2)
  169. ctx.restore();
  170. }
  171. }
  172.  
  173. function scrambleFlakes() {
  174. for (var i = 0; i < num_flakes; ++i) {
  175. snowflakes[i].y = Math.random() * (screen_height + screen_max_overlap);
  176. snowflakes[i].x = Math.random() * screen_width;
  177. }
  178. }
  179.  
  180. scrambleFlakes();
  181.  
  182. function onResizeOrVisibilityChange() {
  183. canvas.width = screen_width = window.innerWidth;
  184. canvas.height = screen_height = window.innerHeight;
  185. v_overlap_threshhold = screen_height + screen_max_overlap;
  186. h_overlap_threshhold = screen_width + screen_max_overlap;
  187.  
  188. scrambleFlakes();
  189. }
  190.  
  191. document.addEventListener("visibilitychange", () => setTimeout(onResizeOrVisibilityChange, 100), false);
  192. window.addEventListener('resize', onResizeOrVisibilityChange, false);
  193.  
  194. frame();
  195. })();
Advertisement
Add Comment
Please, Sign In to add comment