util.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /**
  2. * Extend object a with the properties of object b.
  3. * If there's a conflict, object b takes precedence.
  4. *
  5. * @param {object} a
  6. * @param {object} b
  7. */
  8. export const extend = ( a, b ) => {
  9. for( var i in b ) {
  10. a[ i ] = b[ i ];
  11. }
  12. return a;
  13. }
  14. /**
  15. * Converts the target object to an array.
  16. *
  17. * @param {object} o
  18. * @return {object[]}
  19. */
  20. export const toArray = ( o ) => {
  21. return Array.prototype.slice.call( o );
  22. }
  23. /**
  24. * Utility for deserializing a value.
  25. *
  26. * @param {*} value
  27. * @return {*}
  28. */
  29. export const deserialize = ( value ) => {
  30. if( typeof value === 'string' ) {
  31. if( value === 'null' ) return null;
  32. else if( value === 'true' ) return true;
  33. else if( value === 'false' ) return false;
  34. else if( value.match( /^-?[\d\.]+$/ ) ) return parseFloat( value );
  35. }
  36. return value;
  37. }
  38. /**
  39. * Measures the distance in pixels between point a
  40. * and point b.
  41. *
  42. * @param {object} a point with x/y properties
  43. * @param {object} b point with x/y properties
  44. *
  45. * @return {number}
  46. */
  47. export const distanceBetween = ( a, b ) => {
  48. var dx = a.x - b.x,
  49. dy = a.y - b.y;
  50. return Math.sqrt( dx*dx + dy*dy );
  51. }
  52. /**
  53. * Applies a CSS transform to the target element.
  54. *
  55. * @param {HTMLElement} element
  56. * @param {string} transform
  57. */
  58. export const transformElement = ( element, transform ) => {
  59. element.style.transform = transform;
  60. }
  61. /**
  62. * Injects the given CSS styles into the DOM.
  63. *
  64. * @param {string} value
  65. */
  66. export const injectStyleSheet = ( value ) => {
  67. let tag = document.createElement( 'style' );
  68. tag.type = 'text/css';
  69. if( tag.styleSheet ) {
  70. tag.styleSheet.cssText = value;
  71. }
  72. else {
  73. tag.appendChild( document.createTextNode( value ) );
  74. }
  75. document.getElementsByTagName( 'head' )[0].appendChild( tag );
  76. }
  77. /**
  78. * Find the closest parent that matches the given
  79. * selector.
  80. *
  81. * @param {HTMLElement} target The child element
  82. * @param {String} selector The CSS selector to match
  83. * the parents against
  84. *
  85. * @return {HTMLElement} The matched parent or null
  86. * if no matching parent was found
  87. */
  88. export const closestParent = ( target, selector ) => {
  89. let parent = target.parentNode;
  90. while( parent ) {
  91. // There's some overhead doing this each time, we don't
  92. // want to rewrite the element prototype but should still
  93. // be enough to feature detect once at startup...
  94. let matchesMethod = parent.matches || parent.matchesSelector || parent.msMatchesSelector;
  95. // If we find a match, we're all set
  96. if( matchesMethod && matchesMethod.call( parent, selector ) ) {
  97. return parent;
  98. }
  99. // Keep searching
  100. parent = parent.parentNode;
  101. }
  102. return null;
  103. }
  104. /**
  105. * Converts various color input formats to an {r:0,g:0,b:0} object.
  106. *
  107. * @param {string} color The string representation of a color
  108. * @example
  109. * colorToRgb('#000');
  110. * @example
  111. * colorToRgb('#000000');
  112. * @example
  113. * colorToRgb('rgb(0,0,0)');
  114. * @example
  115. * colorToRgb('rgba(0,0,0)');
  116. *
  117. * @return {{r: number, g: number, b: number, [a]: number}|null}
  118. */
  119. export const colorToRgb = ( color ) => {
  120. let hex3 = color.match( /^#([0-9a-f]{3})$/i );
  121. if( hex3 && hex3[1] ) {
  122. hex3 = hex3[1];
  123. return {
  124. r: parseInt( hex3.charAt( 0 ), 16 ) * 0x11,
  125. g: parseInt( hex3.charAt( 1 ), 16 ) * 0x11,
  126. b: parseInt( hex3.charAt( 2 ), 16 ) * 0x11
  127. };
  128. }
  129. let hex6 = color.match( /^#([0-9a-f]{6})$/i );
  130. if( hex6 && hex6[1] ) {
  131. hex6 = hex6[1];
  132. return {
  133. r: parseInt( hex6.substr( 0, 2 ), 16 ),
  134. g: parseInt( hex6.substr( 2, 2 ), 16 ),
  135. b: parseInt( hex6.substr( 4, 2 ), 16 )
  136. };
  137. }
  138. let rgb = color.match( /^rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)$/i );
  139. if( rgb ) {
  140. return {
  141. r: parseInt( rgb[1], 10 ),
  142. g: parseInt( rgb[2], 10 ),
  143. b: parseInt( rgb[3], 10 )
  144. };
  145. }
  146. let rgba = color.match( /^rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\,\s*([\d]+|[\d]*.[\d]+)\s*\)$/i );
  147. if( rgba ) {
  148. return {
  149. r: parseInt( rgba[1], 10 ),
  150. g: parseInt( rgba[2], 10 ),
  151. b: parseInt( rgba[3], 10 ),
  152. a: parseFloat( rgba[4] )
  153. };
  154. }
  155. return null;
  156. }
  157. /**
  158. * Calculates brightness on a scale of 0-255.
  159. *
  160. * @param {string} color See colorToRgb for supported formats.
  161. * @see {@link colorToRgb}
  162. */
  163. export const colorBrightness = ( color ) => {
  164. if( typeof color === 'string' ) color = colorToRgb( color );
  165. if( color ) {
  166. return ( color.r * 299 + color.g * 587 + color.b * 114 ) / 1000;
  167. }
  168. return null;
  169. }
  170. /**
  171. * Handling the fullscreen functionality via the fullscreen API
  172. *
  173. * @see http://fullscreen.spec.whatwg.org/
  174. * @see https://developer.mozilla.org/en-US/docs/DOM/Using_fullscreen_mode
  175. */
  176. export const enterFullscreen = () => {
  177. let element = document.documentElement;
  178. // Check which implementation is available
  179. let requestMethod = element.requestFullscreen ||
  180. element.webkitRequestFullscreen ||
  181. element.webkitRequestFullScreen ||
  182. element.mozRequestFullScreen ||
  183. element.msRequestFullscreen;
  184. if( requestMethod ) {
  185. requestMethod.apply( element );
  186. }
  187. }