1. /**
    2. * Normalize the browser animation API across implementations. This requests
    3. * the browser to schedule a repaint of the window for the next animation frame.
    4. * Checks for cross-browser support, and, failing to find it, falls back to setTimeout.
    5. * @param {function} callback Function to call when it's time to update your animation for the next repaint.
    6. * @param {HTMLElement} element Optional parameter specifying the element that visually bounds the entire animation.
    7. * @return {number} Animation frame request.
    8. */
    9. if (!window.requestAnimationFrame) {
    10. window.requestAnimationFrame = (window.webkitRequestAnimationFrame ||
    11. window.mozRequestAnimationFrame ||
    12. window.msRequestAnimationFrame ||
    13. window.oRequestAnimationFrame ||
    14. function (callback) {
    15. return window.setTimeout(callback, 17 /*~ 1000/60*/);
    16. });
    17. }
    18. /**
    19. * ERRATA: 'cancelRequestAnimationFrame' renamed to 'cancelAnimationFrame' to reflect an update to the W3C Animation-Timing Spec.
    20. *
    21. * Cancels an animation frame request.
    22. * Checks for cross-browser support, falls back to clearTimeout.
    23. * @param {number} Animation frame request.
    24. */
    25. if (!window.cancelAnimationFrame) {
    26. window.cancelAnimationFrame = (window.cancelRequestAnimationFrame ||
    27. window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame ||
    28. window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame ||
    29. window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame ||
    30. window.oCancelAnimationFrame || window.oCancelRequestAnimationFrame ||
    31. window.clearTimeout);
    32. }
    33. /* Object that contains our utility functions.
    34. * Attached to the window object which acts as the global namespace.
    35. */
    36. window.utils = {};
    37. /**
    38. * Keeps track of the current mouse position, relative to an element.
    39. * @param {HTMLElement} element
    40. * @return {object} Contains properties: x, y, event
    41. */
    42. window.utils.captureMouse = function (element) {
    43. var mouse = {x: 0, y: 0, event: null},
    44. body_scrollLeft = document.body.scrollLeft,
    45. element_scrollLeft = document.documentElement.scrollLeft,
    46. body_scrollTop = document.body.scrollTop,
    47. element_scrollTop = document.documentElement.scrollTop,
    48. offsetLeft = element.offsetLeft,
    49. offsetTop = element.offsetTop;
    50. element.addEventListener('mousemove', function (event) {
    51. var x, y;
    52. if (event.pageX || event.pageY) {
    53. x = event.pageX;
    54. y = event.pageY;
    55. } else {
    56. x = event.clientX + body_scrollLeft + element_scrollLeft;
    57. y = event.clientY + body_scrollTop + element_scrollTop;
    58. }
    59. x -= offsetLeft;
    60. y -= offsetTop;
    61. mouse.x = x;
    62. mouse.y = y;
    63. mouse.event = event;
    64. }, false);
    65. return mouse;
    66. };
    67. /**
    68. * Keeps track of the current (first) touch position, relative to an element.
    69. * @param {HTMLElement} element
    70. * @return {object} Contains properties: x, y, isPressed, event
    71. */
    72. window.utils.captureTouch = function (element) {
    73. var touch = {x: null, y: null, isPressed: false, event: null},
    74. body_scrollLeft = document.body.scrollLeft,
    75. element_scrollLeft = document.documentElement.scrollLeft,
    76. body_scrollTop = document.body.scrollTop,
    77. element_scrollTop = document.documentElement.scrollTop,
    78. offsetLeft = element.offsetLeft,
    79. offsetTop = element.offsetTop;
    80. element.addEventListener('touchstart', function (event) {
    81. touch.isPressed = true;
    82. touch.event = event;
    83. }, false);
    84. element.addEventListener('touchend', function (event) {
    85. touch.isPressed = false;
    86. touch.x = null;
    87. touch.y = null;
    88. touch.event = event;
    89. }, false);
    90. element.addEventListener('touchmove', function (event) {
    91. var x, y,
    92. touch_event = event.touches[0]; //first touch
    93. if (touch_event.pageX || touch_event.pageY) {
    94. x = touch_event.pageX;
    95. y = touch_event.pageY;
    96. } else {
    97. x = touch_event.clientX + body_scrollLeft + element_scrollLeft;
    98. y = touch_event.clientY + body_scrollTop + element_scrollTop;
    99. }
    100. x -= offsetLeft;
    101. y -= offsetTop;
    102. touch.x = x;
    103. touch.y = y;
    104. touch.event = event;
    105. }, false);
    106. return touch;
    107. };
    108. /**
    109. * Returns a color in the format: '#RRGGBB', or as a hex number if specified.
    110. * @param {number|string} color
    111. * @param {boolean=} toNumber=false Return color as a hex number.
    112. * @return {string|number}
    113. */
    114. window.utils.parseColor = function (color, toNumber) {
    115. if (toNumber === true) {
    116. if (typeof color === 'number') {
    117. return (color | 0); //chop off decimal
    118. }
    119. if (typeof color === 'string' && color[0] === '#') {
    120. color = color.slice(1);
    121. }
    122. return window.parseInt(color, 16);
    123. } else {
    124. if (typeof color === 'number') {
    125. color = '#' + ('00000' + (color | 0).toString(16)).substr(-6); //pad
    126. }
    127. return color;
    128. }
    129. };
    130. /**
    131. * Converts a color to the RGB string format: 'rgb(r,g,b)' or 'rgba(r,g,b,a)'
    132. * @param {number|string} color
    133. * @param {number} alpha
    134. * @return {string}
    135. */
    136. window.utils.colorToRGB = function (color, alpha) {
    137. //number in octal format or string prefixed with #
    138. if (typeof color === 'string' && color[0] === '#') {
    139. color = window.parseInt(color.slice(1), 16);
    140. }
    141. alpha = (alpha === undefined) ? 1 : alpha;
    142. //parse hex values
    143. var r = color >> 16 & 0xff,
    144. g = color >> 8 & 0xff,
    145. b = color & 0xff,
    146. a = (alpha < 0) ? 0 : ((alpha > 1) ? 1 : alpha);
    147. //only use 'rgba' if needed
    148. if (a === 1) {
    149. return "rgb("+ r +","+ g +","+ b +")";
    150. } else {
    151. return "rgba("+ r +","+ g +","+ b +","+ a +")";
    152. }
    153. };
    154. /**
    155. * Determine if a rectangle contains the coordinates (x,y) within it's boundaries.
    156. * @param {object} rect Object with properties: x, y, width, height.
    157. * @param {number} x Coordinate position x.
    158. * @param {number} y Coordinate position y.
    159. * @return {boolean}
    160. */
    161. window.utils.containsPoint = function (rect, x, y) {
    162. return !(x < rect.x ||
    163. x > rect.x + rect.width ||
    164. y < rect.y ||
    165. y > rect.y + rect.height);
    166. };
    167. /**
    168. * Determine if two rectangles overlap.
    169. * @param {object} rectA Object with properties: x, y, width, height.
    170. * @param {object} rectB Object with properties: x, y, width, height.
    171. * @return {boolean}
    172. */
    173. window.utils.intersects = function (rectA, rectB) {
    174. return !(rectA.x + rectA.width < rectB.x ||
    175. rectB.x + rectB.width < rectA.x ||
    176. rectA.y + rectA.height < rectB.y ||
    177. rectB.y + rectB.height < rectA.y);
    178. };