PageRenderTime 36ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/engine/js/sprite.js

https://github.com/Breton/HTML5-Storybook
JavaScript | 308 lines | 204 code | 62 blank | 42 comment | 63 complexity | 2d50918924ecd25c6e33ed73951b7666 MD5 | raw file
  1. // ------------------------------------------------------------------
  2. // sprite.js
  3. //
  4. // Copyright 2012 PBS KIDS Interactive. All Rights Reserved.
  5. PBS.KIDS.storybook.sprite = function (GLOBAL, PBS, options) {
  6. "use strict";
  7. var that,
  8. element,
  9. resource = (options && options.resource !== undefined) ? options.resource : undefined,
  10. ctx,
  11. destroyed = false,
  12. initialized = false,
  13. spec = {},
  14. previousFrame = 0,
  15. curFrame = 0,
  16. updateIndex = 0,
  17. frameWidth,
  18. frameHeight,
  19. frameDelay = options.frameDelay || 1,
  20. loop = options.loop,
  21. parentElement = options && options.parentElement,
  22. paused = false,
  23. parentWidthRatio = 1,
  24. parentHeightRatio = 1,
  25. backgroundColor = options.color,
  26. numFrames = options.numFrames,
  27. init = function () {
  28. if (!initialized) {
  29. initialized = true;
  30. that.initView();
  31. // If the sprite has an image
  32. if (resource && resource.image) {
  33. that.width = resource.image.width;
  34. that.height = resource.image.height;
  35. } else {
  36. that.width = 100;
  37. that.height = 100;
  38. }
  39. // Determine the dimensions of the frame. It may be different from the image dimensions if more than one frame
  40. frameWidth = numFrames ? (that.width / numFrames) : that.width;
  41. frameHeight = that.height;
  42. // Set the dimensions of the element
  43. element.width = frameWidth;
  44. element.height = frameHeight;
  45. // If the width was specified
  46. if (options.width) {
  47. // If px is in the width (e.g. 100px)
  48. if (options.width.toString().indexOf("px") !== -1) {
  49. element.style.width = options.width;
  50. } else {
  51. element.style.width = options.width + "%";
  52. }
  53. // Scale sprite if the parent is scaled
  54. } else if (that.parentWidth) {
  55. parentWidthRatio = (element.width / that.parentWidth);
  56. element.style.width = (parentWidthRatio * 100) + "%";
  57. }
  58. // If the height was specified
  59. if (options.height) {
  60. // If px is in the height (e.g. 100px)
  61. if (options.height.toString().indexOf("px") !== -1) {
  62. element.style.height = options.height;
  63. } else {
  64. element.style.height = options.height + "%";
  65. }
  66. // Scale sprite if the parent is scaled
  67. } else if (that.parentHeight) {
  68. parentHeightRatio = (element.height / that.parentHeight);
  69. element.style.height = (parentHeightRatio * 100) + "%";
  70. }
  71. // Listen to when the sprite is touched or clicked
  72. that.addEventListener("PRESS", that.press);
  73. // If auto start is turned off (it is on by default)
  74. if (that.autoStart === false) {
  75. paused = true;
  76. }
  77. that.dirty = true;
  78. }
  79. },
  80. // Call when all resources for the sprite are loaded
  81. resourcesReady = function () {
  82. init();
  83. },
  84. // Returns the animation frame to be displayed
  85. applyEasing = function (curTick, totalTicks, totalNumFrames) {
  86. var currentFrame;
  87. // If no easeIn option then go slow at the beginning of an animation
  88. if (options.easing && options.easing.toUpperCase() === "EASEIN") {
  89. currentFrame = totalNumFrames * (1 - GLOBAL.Math.cos(curTick / totalTicks * GLOBAL.Math.PI / 2));
  90. // If no easeOut option then go slow at the end of an animation
  91. } else if (options.easing && options.easing.toUpperCase() === "EASEOUT") {
  92. currentFrame = totalNumFrames * (GLOBAL.Math.sin(curTick / totalTicks * GLOBAL.Math.PI / 2));
  93. // If no easing then the animation frames advance linearly
  94. } else {
  95. currentFrame = totalNumFrames * curTick / totalTicks;
  96. //console.log(totalNumFrames + " * " + curTick + "/" + totalTicks + " = " + currentFrame);
  97. }
  98. return GLOBAL.Math.floor(currentFrame);
  99. };
  100. // Create the sprite's canvas
  101. spec.width = 99 + "px";
  102. spec.height = 99 + "px";
  103. spec.className = "pbsCanvas pbsSprite";
  104. if (options && options.className) {
  105. spec.className += " " + options.className
  106. }
  107. ctx = PBS.KIDS.storybook.createCanvas(parentElement, spec);
  108. // Inherit the view
  109. that = PBS.KIDS.storybook.view(PBS, ctx.canvas);
  110. element = that.getElement();
  111. // Public properties
  112. that.x = options && (options.x !== undefined) ? options.x : 0;
  113. that.y = options && (options.y !== undefined) ? options.y : 0;
  114. that.width = options && (options.width !== undefined) ? options.width : 0;
  115. that.height = options && (options.height !== undefined) ? options.height : 0;
  116. that.parentWidth = options.parentWidth;
  117. that.parentHeight = options.parentHeight;
  118. that.horizontalAlign = (options && options.horizontalAlign !== undefined) ? options.horizontalAlign.toUpperCase() : "LEFT",
  119. that.verticalAlign = (options && options.verticalAlign !== undefined) ? options.verticalAlign.toUpperCase() : "TOP",
  120. that.visible = true;
  121. that.alpha;
  122. that.destroyed = false;
  123. that.url = options && options.url;
  124. that.autoStart = options && (options.autoStart !== undefined) ? options.autoStart : true;
  125. that.autoReset = options && (options.autoReset !== undefined) ? options.autoReset : false;
  126. that.update = function () {
  127. // If the sprite is a non-paused animation
  128. if (numFrames && !paused) {
  129. // If the last frame
  130. if (updateIndex + 1 >= numFrames * frameDelay) {
  131. // If the animation is set to loop
  132. if (loop) {
  133. curFrame = 0;
  134. updateIndex = 0;
  135. // If the animation is set to automatically reset
  136. } else if (that.autoReset) {
  137. curFrame = 0;
  138. updateIndex = 0;
  139. that.stop();
  140. } // Else the animation is complete so stay on the final frame
  141. // If the animation is not complete
  142. } else {
  143. updateIndex += 1;
  144. curFrame = applyEasing(updateIndex, numFrames * frameDelay, numFrames);
  145. }
  146. // If the current and previous frame is different then redraw
  147. if (previousFrame !== curFrame) {
  148. that.dirty = true;
  149. // Save the frame that was just drawn
  150. previousFrame = curFrame;
  151. }
  152. }
  153. };
  154. that.render = function () {
  155. var curAlpha, frameXPos;
  156. if (initialized) {
  157. if (that.dirty) {
  158. // If the sprite is visible
  159. if (that.visible) {
  160. curAlpha = ctx.globalAlpha;
  161. ctx.globalAlpha = that.alpha;
  162. // If background color
  163. if (backgroundColor) {
  164. // Draw the background color
  165. ctx.fillStyle = backgroundColor;
  166. ctx.fillRect(0, 0, frameWidth, frameHeight);
  167. }
  168. // If the sprite has an image
  169. if (resource && resource.image) {
  170. // If the sprite is an animation
  171. if (numFrames) {
  172. // Clear rect approach crashes native browser in Droid Samsung Gt-P3113
  173. //ctx.clearRect(0, 0, frameWidth, frameHeight);
  174. ctx.canvas.width = ctx.canvas.width;
  175. ctx.drawImage(
  176. resource.image,
  177. GLOBAL.Math.floor(curFrame * frameWidth),
  178. 0,
  179. frameWidth,
  180. frameHeight,
  181. 0,
  182. 0,
  183. frameWidth,
  184. frameHeight
  185. );
  186. } else {
  187. ctx.drawImage(resource.image, 0, 0, frameWidth, frameHeight);
  188. }
  189. ctx.globalAlpha = curAlpha;
  190. }
  191. } else {
  192. ctx.clearRect(0, 0, frameWidth, frameHeight);
  193. }
  194. // Don't render again until set to dirty
  195. that.dirty = false;
  196. }
  197. }
  198. };
  199. // Element property getter
  200. that.getElement = function () {
  201. return element;
  202. };
  203. that.play = function () {
  204. that.reset();
  205. paused = false;
  206. };
  207. that.isAnimation = function () {
  208. return (numFrames > 1);
  209. };
  210. that.resume = function () {
  211. paused = false;
  212. that.dirty = true;
  213. };
  214. that.stop = function () {
  215. paused = true;
  216. };
  217. that.reset = function () {
  218. if (curFrame !== 0) {
  219. curFrame = 0;
  220. updateIndex = 0;
  221. that.dirty = true;
  222. that.stop();
  223. }
  224. };
  225. that.press = function () {
  226. if (options.playOnPress) {
  227. that.play();
  228. } else if (options.stopOnPress) {
  229. that.stop();
  230. } else if (options.toggleOnPress) {
  231. if (paused) {
  232. that.resume();
  233. } else {
  234. that.stop();
  235. }
  236. }
  237. };
  238. // If the sprite has an image
  239. if (resource && resource.image) {
  240. // Listen to when the image is loaded
  241. resource.image.addEventListener("load", resourcesReady);
  242. } else {
  243. resourcesReady();
  244. }
  245. return that;
  246. };