Advertisement
Guest User

Untitled

a guest
Oct 20th, 2016
77
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 14.82 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>ES6 Improved Canvas Animation Demo</title>
  6. <style id="jsbin-css">
  7. body{
  8. margin:16px;
  9. font:14pt Roboto, "San Francisco", "Helvetica Neue", Helvetica, Arial, sans-serif;
  10. font-weight:300;
  11. }
  12. h1{
  13. display:block;
  14. margin:-16px -16px 16px;
  15. padding:32px;
  16. background:#616161;
  17. box-sizing:border-box;
  18. color:#fff;
  19. font-size:32pt;
  20. font-weight:300;
  21. }
  22. canvas{
  23. box-shadow:0 0 8px #666;
  24. }
  25. </style>
  26. </head>
  27. <body>
  28. <h1>ES6 Improved Canvas Animation Demo</h1>
  29. <canvas id="canvas" width="600" height="400">Please update your browser.</canvas>
  30.  
  31. <button id="addRect">Add Rectangle</button>
  32. <script id="jsbin-javascript">
  33. console.clear();
  34.  
  35. class Drawable{
  36.  
  37. // Lots of constructor parameters with sensible defaults = more useful
  38. constructor(context, x = 0, y = 0, fillStyle = "#000", strokeStyle = "transparent", lineWidth = 0){
  39. this.context = context;
  40. if(!(this.context instanceof CanvasRenderingContext2D)){
  41. throw new Error("You must provide a valid canvas context to Drawables.");
  42. }
  43.  
  44. this.x = x;
  45. this.y = y;
  46. this.fillStyle = fillStyle;
  47. this.strokeStyle = strokeStyle;
  48. this.lineWidth = lineWidth;
  49.  
  50. // NEW: Deltas Map
  51. // Note I have decided not to allow this to be passed as a parameter, but you could add this if you prefer.
  52. // Remember to add it to all of the classes which inherit from Drawable too if you like.
  53. this.deltas = new Map();
  54. }
  55.  
  56. // The method to call when drawing
  57. draw(){
  58. // SAVE context
  59. this.context.save();
  60.  
  61. // TRANSLATE to where we want to start drawing
  62. this.context.translate(this.x, this.y);
  63.  
  64. // CONFIGURE the context with colours and widths
  65. this.context.fillStyle = this.fillStyle;
  66. this.context.strokeStyle = this.strokeStyle;
  67. this.context.lineWidth = this.lineWidth;
  68.  
  69. // This is where the drawing would happen.
  70. // And will in subclasses!
  71. }
  72.  
  73.  
  74. // This method should be called when a shape has finished drawing
  75. // It will restore the context back to where it was before drawing started
  76. afterDraw(){
  77.  
  78. // RESTORE the context (undo translate, colours, width changes)
  79. this.context.restore();
  80. }
  81.  
  82. // NEW: Method to tell a Drawable to apply any applicable animations, based on how much time has passed
  83. applyAnimation(secondsElapsed){
  84. // Loop over all deltas
  85. for(const [propertyName, valueChangePerSecond] of this.deltas){
  86. // Calculate how much to change the amount by (change amount = change per second * seconds passed)
  87. const changeAmount = secondsElapsed * valueChangePerSecond;
  88.  
  89. // Apply the change
  90. // e.g. this["x"] += 0.5;
  91. this[propertyName] += changeAmount;
  92.  
  93. // Enable for a verbose rundown of changes being made
  94. // Warning, this will spam your console!
  95. //console.log(`Changing the ${propertyName} property by ${changeAmount} because ${secondsElapsed} seconds have passed.`)
  96. }
  97. }
  98. }
  99.  
  100. class Rectangle extends Drawable{
  101.  
  102. // Compared to drawable, also accepts width and height
  103. constructor(context, x = 0, y = 0, fillStyle = "#000", strokeStyle = "transparent", lineWidth = 0, deltas = new Map(), width = 100, height = 100){
  104.  
  105. // Call through to super - with the parameters it expects
  106. super(context, x, y, fillStyle, strokeStyle, lineWidth);
  107.  
  108. // Save the additional properties
  109. this.width = width;
  110. this.height = height;
  111. }
  112.  
  113. // Override draw to provide actual rectangle drawing
  114. draw(){
  115.  
  116. // Call super's draw method to do all of the set-up
  117. super.draw();
  118.  
  119. // Now do the rectangle drawing
  120. // We can draw *around* point 0,0 because we have already translated to the desired x,y coordinate
  121. this.context.fillRect( this.width / -2, this.height / -2, this.width, this.height);
  122. this.context.strokeRect( this.width / -2, this.height / -2, this.width, this.height);
  123.  
  124. // Remember, subclasses must call afterDraw to do cleanup (restore the translates done)
  125. super.afterDraw();
  126. }
  127. }
  128.  
  129. const canvas = document.getElementById("canvas");
  130. const context = canvas.getContext("2d");
  131.  
  132. // NEW: A set to hold all canvas objects
  133. const canvasObjects = new Set();
  134.  
  135. // Create some rectangles
  136. const rect1 = new Rectangle(context, 100, 100, "orange");
  137. const rect2 = new Rectangle(context, 100, 300, "rgba(200, 100, 100, 0.8)");
  138. const rect3 = new Rectangle(context, 400, 150, "#f00");
  139. const rect4 = new Rectangle(context, 500, 300, "hsla(200, 50%, 50%, 1)");
  140.  
  141. // NEW: Set some delta on the rects
  142. rect1.deltas.set("width", 5); // Change width property by 5 per second
  143. rect2.deltas.set("x", 20); // Change x property by 250 per second
  144. rect2.deltas.set("height", -10); // Change height property by -10 per second
  145. rect3.deltas.set("height", 5); // Change height property by -10 per second
  146. rect3.deltas.set("width", 5); // Change height property by -10 per second
  147. rect4.deltas.set("y", -15); // Change height property by -10 per second
  148.  
  149.  
  150. let lastTime = Date.now();
  151.  
  152. // NEW: Add objects to the canvasObjects set
  153. canvasObjects.add(rect1);
  154. canvasObjects.add(rect2);
  155. canvasObjects.add(rect3);
  156. canvasObjects.add(rect4);
  157.  
  158.  
  159. // Called very rapidly to carry out animations
  160. function animationLoop(){
  161. // 0. Schedule the next run of this function
  162. requestAnimationFrame(animationLoop);
  163.  
  164. // 1. Clear the Canvas
  165. context.clearRect(0, 0, canvas.width, canvas.height);
  166.  
  167. // 2. Calculate Changes
  168. // Calculate the difference, in seconds, between when the
  169. // loop last ran and now.
  170. const diffSeconds = (Date.now() - lastTime) / 1000;
  171.  
  172. // Store the current time as lastTime, so that next time the loop
  173. // is called we have a reference point to calculate diffSeconds from
  174. lastTime = Date.now();
  175.  
  176. // Only if some time has passsed...
  177. if(diffSeconds > 0){
  178. // NEW: 3. Loop to apply animations and redraw
  179. for(const canvasObject of canvasObjects){
  180. canvasObject.applyAnimation(diffSeconds);
  181. canvasObject.draw();
  182. }
  183. }
  184.  
  185. }
  186.  
  187. // Call animate for the first time
  188. animationLoop();
  189.  
  190.  
  191.  
  192. // NEW: Handle clicks on the button
  193. document.getElementById("addRect").addEventListener("click", (e) => {
  194. e.preventDefault();
  195.  
  196. // Create the rectangle, using some random properties
  197. const rect = new Rectangle(context, // context
  198. randomBetween(0, canvas.width), // x
  199. randomBetween(0, canvas.height), // y
  200. randomNiceColourString(), // fillStyle
  201. randomNiceColourString(), // strokeStyle
  202. randomBetween(0, 5), // lineWidth
  203. randomBetween(20, 120), // width
  204. randomBetween(20, 120)); // height
  205.  
  206. // Add the rectangle to the canvasObjects array
  207. // It will get drawn (and optionally begin animation)
  208. canvasObjects.add(rect);
  209. });
  210.  
  211.  
  212. // NEW: Helper function for a random whole number between two values (inclusive)
  213. function randomBetween(minimum, maximum){
  214. var range = maximum - minimum;
  215.  
  216. var random = Math.random();
  217. random = random * (range + 1);
  218. random = Math.floor(random);
  219.  
  220. random = random + minimum;
  221.  
  222. return random;
  223. }
  224.  
  225. // NEW: Helper function for a random hsl colour string - high saturation and mid lightness for vivid colours
  226. function randomNiceColourString(){
  227. var h = randomBetween(0, 360),
  228. s = randomBetween(90, 100),
  229. l = randomBetween(45, 55);
  230.  
  231. // e.g. hsl(320,95%,50%)
  232. var colour = "hsl(" + h + "," + s + "%," + l + "%)";
  233.  
  234. return colour;
  235. }
  236. </script>
  237.  
  238.  
  239. <script id="jsbin-source-css" type="text/css">body{
  240. margin:16px;
  241. font:14pt Roboto, "San Francisco", "Helvetica Neue", Helvetica, Arial, sans-serif;
  242. font-weight:300;
  243. }
  244. h1{
  245. display:block;
  246. margin:-16px -16px 16px;
  247. padding:32px;
  248. background:#616161;
  249. box-sizing:border-box;
  250. color:#fff;
  251. font-size:32pt;
  252. font-weight:300;
  253. }
  254. canvas{
  255. box-shadow:0 0 8px #666;
  256. }</script>
  257.  
  258. <script id="jsbin-source-javascript" type="text/javascript">console.clear();
  259.  
  260. class Drawable{
  261.  
  262. // Lots of constructor parameters with sensible defaults = more useful
  263. constructor(context, x = 0, y = 0, fillStyle = "#000", strokeStyle = "transparent", lineWidth = 0){
  264. this.context = context;
  265. if(!(this.context instanceof CanvasRenderingContext2D)){
  266. throw new Error("You must provide a valid canvas context to Drawables.");
  267. }
  268.  
  269. this.x = x;
  270. this.y = y;
  271. this.fillStyle = fillStyle;
  272. this.strokeStyle = strokeStyle;
  273. this.lineWidth = lineWidth;
  274.  
  275. // NEW: Deltas Map
  276. // Note I have decided not to allow this to be passed as a parameter, but you could add this if you prefer.
  277. // Remember to add it to all of the classes which inherit from Drawable too if you like.
  278. this.deltas = new Map();
  279. }
  280.  
  281. // The method to call when drawing
  282. draw(){
  283. // SAVE context
  284. this.context.save();
  285.  
  286. // TRANSLATE to where we want to start drawing
  287. this.context.translate(this.x, this.y);
  288.  
  289. // CONFIGURE the context with colours and widths
  290. this.context.fillStyle = this.fillStyle;
  291. this.context.strokeStyle = this.strokeStyle;
  292. this.context.lineWidth = this.lineWidth;
  293.  
  294. // This is where the drawing would happen.
  295. // And will in subclasses!
  296. }
  297.  
  298.  
  299. // This method should be called when a shape has finished drawing
  300. // It will restore the context back to where it was before drawing started
  301. afterDraw(){
  302.  
  303. // RESTORE the context (undo translate, colours, width changes)
  304. this.context.restore();
  305. }
  306.  
  307. // NEW: Method to tell a Drawable to apply any applicable animations, based on how much time has passed
  308. applyAnimation(secondsElapsed){
  309. // Loop over all deltas
  310. for(const [propertyName, valueChangePerSecond] of this.deltas){
  311. // Calculate how much to change the amount by (change amount = change per second * seconds passed)
  312. const changeAmount = secondsElapsed * valueChangePerSecond;
  313.  
  314. // Apply the change
  315. // e.g. this["x"] += 0.5;
  316. this[propertyName] += changeAmount;
  317.  
  318. // Enable for a verbose rundown of changes being made
  319. // Warning, this will spam your console!
  320. //console.log(`Changing the ${propertyName} property by ${changeAmount} because ${secondsElapsed} seconds have passed.`)
  321. }
  322. }
  323. }
  324.  
  325. class Rectangle extends Drawable{
  326.  
  327. // Compared to drawable, also accepts width and height
  328. constructor(context, x = 0, y = 0, fillStyle = "#000", strokeStyle = "transparent", lineWidth = 0, deltas = new Map(), width = 100, height = 100){
  329.  
  330. // Call through to super - with the parameters it expects
  331. super(context, x, y, fillStyle, strokeStyle, lineWidth);
  332.  
  333. // Save the additional properties
  334. this.width = width;
  335. this.height = height;
  336. }
  337.  
  338. // Override draw to provide actual rectangle drawing
  339. draw(){
  340.  
  341. // Call super's draw method to do all of the set-up
  342. super.draw();
  343.  
  344. // Now do the rectangle drawing
  345. // We can draw *around* point 0,0 because we have already translated to the desired x,y coordinate
  346. this.context.fillRect( this.width / -2, this.height / -2, this.width, this.height);
  347. this.context.strokeRect( this.width / -2, this.height / -2, this.width, this.height);
  348.  
  349. // Remember, subclasses must call afterDraw to do cleanup (restore the translates done)
  350. super.afterDraw();
  351. }
  352. }
  353.  
  354. const canvas = document.getElementById("canvas");
  355. const context = canvas.getContext("2d");
  356.  
  357. // NEW: A set to hold all canvas objects
  358. const canvasObjects = new Set();
  359.  
  360. // Create some rectangles
  361. const rect1 = new Rectangle(context, 100, 100, "orange");
  362. const rect2 = new Rectangle(context, 100, 300, "rgba(200, 100, 100, 0.8)");
  363. const rect3 = new Rectangle(context, 400, 150, "#f00");
  364. const rect4 = new Rectangle(context, 500, 300, "hsla(200, 50%, 50%, 1)");
  365.  
  366. // NEW: Set some delta on the rects
  367. rect1.deltas.set("width", 5); // Change width property by 5 per second
  368. rect2.deltas.set("x", 20); // Change x property by 250 per second
  369. rect2.deltas.set("height", -10); // Change height property by -10 per second
  370. rect3.deltas.set("height", 5); // Change height property by -10 per second
  371. rect3.deltas.set("width", 5); // Change height property by -10 per second
  372. rect4.deltas.set("y", -15); // Change height property by -10 per second
  373.  
  374.  
  375. let lastTime = Date.now();
  376.  
  377. // NEW: Add objects to the canvasObjects set
  378. canvasObjects.add(rect1);
  379. canvasObjects.add(rect2);
  380. canvasObjects.add(rect3);
  381. canvasObjects.add(rect4);
  382.  
  383.  
  384. // Called very rapidly to carry out animations
  385. function animationLoop(){
  386. // 0. Schedule the next run of this function
  387. requestAnimationFrame(animationLoop);
  388.  
  389. // 1. Clear the Canvas
  390. context.clearRect(0, 0, canvas.width, canvas.height);
  391.  
  392. // 2. Calculate Changes
  393. // Calculate the difference, in seconds, between when the
  394. // loop last ran and now.
  395. const diffSeconds = (Date.now() - lastTime) / 1000;
  396.  
  397. // Store the current time as lastTime, so that next time the loop
  398. // is called we have a reference point to calculate diffSeconds from
  399. lastTime = Date.now();
  400.  
  401. // Only if some time has passsed...
  402. if(diffSeconds > 0){
  403. // NEW: 3. Loop to apply animations and redraw
  404. for(const canvasObject of canvasObjects){
  405. canvasObject.applyAnimation(diffSeconds);
  406. canvasObject.draw();
  407. }
  408. }
  409.  
  410. }
  411.  
  412. // Call animate for the first time
  413. animationLoop();
  414.  
  415.  
  416.  
  417. // NEW: Handle clicks on the button
  418. document.getElementById("addRect").addEventListener("click", (e) => {
  419. e.preventDefault();
  420.  
  421. // Create the rectangle, using some random properties
  422. const rect = new Rectangle(context, // context
  423. randomBetween(0, canvas.width), // x
  424. randomBetween(0, canvas.height), // y
  425. randomNiceColourString(), // fillStyle
  426. randomNiceColourString(), // strokeStyle
  427. randomBetween(0, 5), // lineWidth
  428. randomBetween(20, 120), // width
  429. randomBetween(20, 120)); // height
  430.  
  431. // Add the rectangle to the canvasObjects array
  432. // It will get drawn (and optionally begin animation)
  433. canvasObjects.add(rect);
  434. });
  435.  
  436.  
  437. // NEW: Helper function for a random whole number between two values (inclusive)
  438. function randomBetween(minimum, maximum){
  439. var range = maximum - minimum;
  440.  
  441. var random = Math.random();
  442. random = random * (range + 1);
  443. random = Math.floor(random);
  444.  
  445. random = random + minimum;
  446.  
  447. return random;
  448. }
  449.  
  450. // NEW: Helper function for a random hsl colour string - high saturation and mid lightness for vivid colours
  451. function randomNiceColourString(){
  452. var h = randomBetween(0, 360),
  453. s = randomBetween(90, 100),
  454. l = randomBetween(45, 55);
  455.  
  456. // e.g. hsl(320,95%,50%)
  457. var colour = "hsl(" + h + "," + s + "%," + l + "%)";
  458.  
  459. return colour;
  460. }</script></body>
  461. </html>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement