alpha.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. // Copyright 2006 The Closure Library Authors. All Rights Reserved.
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS-IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. /**
  15. * @fileoverview Utilities related to alpha/transparent colors and alpha color
  16. * conversion.
  17. */
  18. goog.provide('goog.color.alpha');
  19. goog.require('goog.color');
  20. /**
  21. * Parses an alpha color out of a string.
  22. * @param {string} str Color in some format.
  23. * @return {{hex: string, type: string}} 'hex' is a string containing
  24. * a hex representation of the color, and 'type' is a string
  25. * containing the type of color format passed in ('hex', 'rgb', 'named').
  26. */
  27. goog.color.alpha.parse = function(str) {
  28. var result = {};
  29. str = String(str);
  30. var maybeHex = goog.color.prependHashIfNecessaryHelper(str);
  31. if (goog.color.alpha.isValidAlphaHexColor_(maybeHex)) {
  32. result.hex = goog.color.alpha.normalizeAlphaHex_(maybeHex);
  33. result.type = 'hex';
  34. return result;
  35. } else {
  36. var rgba = goog.color.alpha.isValidRgbaColor_(str);
  37. if (rgba.length) {
  38. result.hex = goog.color.alpha.rgbaArrayToHex(rgba);
  39. result.type = 'rgba';
  40. return result;
  41. } else {
  42. var hsla = goog.color.alpha.isValidHslaColor_(str);
  43. if (hsla.length) {
  44. result.hex = goog.color.alpha.hslaArrayToHex(hsla);
  45. result.type = 'hsla';
  46. return result;
  47. }
  48. }
  49. }
  50. throw Error(str + ' is not a valid color string');
  51. };
  52. /**
  53. * Converts a hex representation of a color to RGBA.
  54. * @param {string} hexColor Color to convert.
  55. * @return {string} string of the form 'rgba(R,G,B,A)' which can be used in
  56. * styles.
  57. */
  58. goog.color.alpha.hexToRgbaStyle = function(hexColor) {
  59. return goog.color.alpha.rgbaStyle_(goog.color.alpha.hexToRgba(hexColor));
  60. };
  61. /**
  62. * Extracts a substring, from startIdx to endIdx, of the normalized (lowercase
  63. * #rrggbbaa) form of a hex-with-alpha color.
  64. * @param {string} colorWithAlpha The alpha hex color to get the hex color from.
  65. * This may be four or eight digits.
  66. * @param {number} startIdx The start index within the #rrggbbaa color.
  67. * @param {number} endIdx The end index within the #rrggbbbaa color.
  68. * @return {string} The requested startIdx-to-endIdx substring from the color.
  69. * @private
  70. */
  71. goog.color.alpha.extractColor_ = function(colorWithAlpha, startIdx, endIdx) {
  72. if (goog.color.alpha.isValidAlphaHexColor_(colorWithAlpha)) {
  73. var fullColor = goog.color.prependHashIfNecessaryHelper(colorWithAlpha);
  74. var normalizedColor = goog.color.alpha.normalizeAlphaHex_(fullColor);
  75. return normalizedColor.substring(startIdx, endIdx);
  76. } else {
  77. throw Error(colorWithAlpha + ' is not a valid 8-hex color string');
  78. }
  79. };
  80. /**
  81. * Gets the hex color part of an alpha hex color. For example, both '#abcd' and
  82. * '#AABBCC12' return '#aabbcc'.
  83. * @param {string} colorWithAlpha The alpha hex color to get the hex color from.
  84. * @return {string} The hex color where the alpha part has been stripped off.
  85. */
  86. goog.color.alpha.extractHexColor = function(colorWithAlpha) {
  87. return goog.color.alpha.extractColor_(colorWithAlpha, 0, 7);
  88. };
  89. /**
  90. * Gets the alpha color part of an alpha hex color. For example, both '#123A'
  91. * and '#123456aa' return 'aa'. The result is always two characters long.
  92. * @param {string} colorWithAlpha The alpha hex color to get the hex color from.
  93. * @return {string} The two-character alpha from the given color.
  94. */
  95. goog.color.alpha.extractAlpha = function(colorWithAlpha) {
  96. return goog.color.alpha.extractColor_(colorWithAlpha, 7, 9);
  97. };
  98. /**
  99. * Regular expression for extracting the digits in a hex color quadruplet.
  100. * @type {RegExp}
  101. * @private
  102. */
  103. goog.color.alpha.hexQuadrupletRe_ = /#(.)(.)(.)(.)/;
  104. /**
  105. * Normalize a hex representation of an alpha color.
  106. * @param {string} hexColor an alpha hex color string.
  107. * @return {string} hex color in the format '#rrggbbaa' with all lowercase
  108. * literals.
  109. * @private
  110. */
  111. goog.color.alpha.normalizeAlphaHex_ = function(hexColor) {
  112. if (!goog.color.alpha.isValidAlphaHexColor_(hexColor)) {
  113. throw Error("'" + hexColor + "' is not a valid alpha hex color");
  114. }
  115. if (hexColor.length == 5) { // of the form #RGBA
  116. hexColor = hexColor.replace(
  117. goog.color.alpha.hexQuadrupletRe_, '#$1$1$2$2$3$3$4$4');
  118. }
  119. return hexColor.toLowerCase();
  120. };
  121. /**
  122. * Converts an 8-hex representation of a color to RGBA.
  123. * @param {string} hexColor Color to convert.
  124. * @return {!Array<number>} array containing [r, g, b, a].
  125. * r, g, b are ints between 0
  126. * and 255, and a is a value between 0 and 1.
  127. */
  128. goog.color.alpha.hexToRgba = function(hexColor) {
  129. // TODO(user): Enhance code sharing with goog.color, for example by
  130. // adding a goog.color.genericHexToRgb method.
  131. hexColor = goog.color.alpha.normalizeAlphaHex_(hexColor);
  132. var r = parseInt(hexColor.substr(1, 2), 16);
  133. var g = parseInt(hexColor.substr(3, 2), 16);
  134. var b = parseInt(hexColor.substr(5, 2), 16);
  135. var a = parseInt(hexColor.substr(7, 2), 16);
  136. return [r, g, b, a / 255];
  137. };
  138. /**
  139. * Converts a color from RGBA to hex representation.
  140. * @param {number} r Amount of red, int between 0 and 255.
  141. * @param {number} g Amount of green, int between 0 and 255.
  142. * @param {number} b Amount of blue, int between 0 and 255.
  143. * @param {number} a Amount of alpha, float between 0 and 1.
  144. * @return {string} hex representation of the color.
  145. */
  146. goog.color.alpha.rgbaToHex = function(r, g, b, a) {
  147. var intAlpha = Math.floor(a * 255);
  148. if (isNaN(intAlpha) || intAlpha < 0 || intAlpha > 255) {
  149. // TODO(user): The CSS spec says the value should be clamped.
  150. throw Error(
  151. '"(' + r + ',' + g + ',' + b + ',' + a +
  152. '") is not a valid RGBA color');
  153. }
  154. var hexA = goog.color.prependZeroIfNecessaryHelper(intAlpha.toString(16));
  155. return goog.color.rgbToHex(r, g, b) + hexA;
  156. };
  157. /**
  158. * Converts a color from HSLA to hex representation.
  159. * @param {number} h Amount of hue, int between 0 and 360.
  160. * @param {number} s Amount of saturation, int between 0 and 100.
  161. * @param {number} l Amount of lightness, int between 0 and 100.
  162. * @param {number} a Amount of alpha, float between 0 and 1.
  163. * @return {string} hex representation of the color.
  164. */
  165. goog.color.alpha.hslaToHex = function(h, s, l, a) {
  166. var intAlpha = Math.floor(a * 255);
  167. if (isNaN(intAlpha) || intAlpha < 0 || intAlpha > 255) {
  168. // TODO(user): The CSS spec says the value should be clamped.
  169. throw Error(
  170. '"(' + h + ',' + s + ',' + l + ',' + a +
  171. '") is not a valid HSLA color');
  172. }
  173. var hexA = goog.color.prependZeroIfNecessaryHelper(intAlpha.toString(16));
  174. return goog.color.hslToHex(h, s / 100, l / 100) + hexA;
  175. };
  176. /**
  177. * Converts a color from RGBA to hex representation.
  178. * @param {Array<number>} rgba Array of [r, g, b, a], with r, g, b in [0, 255]
  179. * and a in [0, 1].
  180. * @return {string} hex representation of the color.
  181. */
  182. goog.color.alpha.rgbaArrayToHex = function(rgba) {
  183. return goog.color.alpha.rgbaToHex(rgba[0], rgba[1], rgba[2], rgba[3]);
  184. };
  185. /**
  186. * Converts a color from RGBA to an RGBA style string.
  187. * @param {number} r Value of red, in [0, 255].
  188. * @param {number} g Value of green, in [0, 255].
  189. * @param {number} b Value of blue, in [0, 255].
  190. * @param {number} a Value of alpha, in [0, 1].
  191. * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
  192. */
  193. goog.color.alpha.rgbaToRgbaStyle = function(r, g, b, a) {
  194. if (isNaN(r) || r < 0 || r > 255 || isNaN(g) || g < 0 || g > 255 ||
  195. isNaN(b) || b < 0 || b > 255 || isNaN(a) || a < 0 || a > 1) {
  196. throw Error(
  197. '"(' + r + ',' + g + ',' + b + ',' + a +
  198. ')" is not a valid RGBA color');
  199. }
  200. return goog.color.alpha.rgbaStyle_([r, g, b, a]);
  201. };
  202. /**
  203. * Converts a color from RGBA to an RGBA style string.
  204. * @param {(Array<number>|Float32Array)} rgba Array of [r, g, b, a],
  205. * with r, g, b in [0, 255] and a in [0, 1].
  206. * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
  207. */
  208. goog.color.alpha.rgbaArrayToRgbaStyle = function(rgba) {
  209. return goog.color.alpha.rgbaToRgbaStyle(rgba[0], rgba[1], rgba[2], rgba[3]);
  210. };
  211. /**
  212. * Converts a color from HSLA to hex representation.
  213. * @param {Array<number>} hsla Array of [h, s, l, a], where h is an integer in
  214. * [0, 360], s and l are integers in [0, 100], and a is in [0, 1].
  215. * @return {string} hex representation of the color, such as '#af457eff'.
  216. */
  217. goog.color.alpha.hslaArrayToHex = function(hsla) {
  218. return goog.color.alpha.hslaToHex(hsla[0], hsla[1], hsla[2], hsla[3]);
  219. };
  220. /**
  221. * Converts a color from HSLA to an RGBA style string.
  222. * @param {Array<number>} hsla Array of [h, s, l, a], where h is and integer in
  223. * [0, 360], s and l are integers in [0, 100], and a is in [0, 1].
  224. * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
  225. */
  226. goog.color.alpha.hslaArrayToRgbaStyle = function(hsla) {
  227. return goog.color.alpha.hslaToRgbaStyle(hsla[0], hsla[1], hsla[2], hsla[3]);
  228. };
  229. /**
  230. * Converts a color from HSLA to an RGBA style string.
  231. * @param {number} h Amount of hue, int between 0 and 360.
  232. * @param {number} s Amount of saturation, int between 0 and 100.
  233. * @param {number} l Amount of lightness, int between 0 and 100.
  234. * @param {number} a Amount of alpha, float between 0 and 1.
  235. * @return {string} An 'rgba(r,g,b,a)' string ready for use in a CSS rule.
  236. * styles.
  237. */
  238. goog.color.alpha.hslaToRgbaStyle = function(h, s, l, a) {
  239. return goog.color.alpha.rgbaStyle_(goog.color.alpha.hslaToRgba(h, s, l, a));
  240. };
  241. /**
  242. * Converts a color from HSLA color space to RGBA color space.
  243. * @param {number} h Amount of hue, int between 0 and 360.
  244. * @param {number} s Amount of saturation, int between 0 and 100.
  245. * @param {number} l Amount of lightness, int between 0 and 100.
  246. * @param {number} a Amount of alpha, float between 0 and 1.
  247. * @return {!Array<number>} [r, g, b, a] values for the color, where r, g, b
  248. * are integers in [0, 255] and a is a float in [0, 1].
  249. */
  250. goog.color.alpha.hslaToRgba = function(h, s, l, a) {
  251. return goog.color.hslToRgb(h, s / 100, l / 100).concat(a);
  252. };
  253. /**
  254. * Converts a color from RGBA color space to HSLA color space.
  255. * Modified from {@link http://en.wikipedia.org/wiki/HLS_color_space}.
  256. * @param {number} r Value of red, in [0, 255].
  257. * @param {number} g Value of green, in [0, 255].
  258. * @param {number} b Value of blue, in [0, 255].
  259. * @param {number} a Value of alpha, in [0, 255].
  260. * @return {!Array<number>} [h, s, l, a] values for the color, with h an int in
  261. * [0, 360] and s, l and a in [0, 1].
  262. */
  263. goog.color.alpha.rgbaToHsla = function(r, g, b, a) {
  264. return goog.color.rgbToHsl(r, g, b).concat(a);
  265. };
  266. /**
  267. * Converts a color from RGBA color space to HSLA color space.
  268. * @param {Array<number>} rgba [r, g, b, a] values for the color, each in
  269. * [0, 255].
  270. * @return {!Array<number>} [h, s, l, a] values for the color, with h in
  271. * [0, 360] and s, l and a in [0, 1].
  272. */
  273. goog.color.alpha.rgbaArrayToHsla = function(rgba) {
  274. return goog.color.alpha.rgbaToHsla(rgba[0], rgba[1], rgba[2], rgba[3]);
  275. };
  276. /**
  277. * Helper for isValidAlphaHexColor_.
  278. * @type {RegExp}
  279. * @private
  280. */
  281. goog.color.alpha.validAlphaHexColorRe_ = /^#(?:[0-9a-f]{4}){1,2}$/i;
  282. /**
  283. * Checks if a string is a valid alpha hex color. We expect strings of the
  284. * format #RRGGBBAA (ex: #1b3d5f5b) or #RGBA (ex: #3CAF == #33CCAAFF).
  285. * @param {string} str String to check.
  286. * @return {boolean} Whether the string is a valid alpha hex color.
  287. * @private
  288. */
  289. // TODO(user): Support percentages when goog.color also supports them.
  290. goog.color.alpha.isValidAlphaHexColor_ = function(str) {
  291. return goog.color.alpha.validAlphaHexColorRe_.test(str);
  292. };
  293. /**
  294. * Helper for isNormalizedAlphaHexColor_.
  295. * @type {RegExp}
  296. * @private
  297. */
  298. goog.color.alpha.normalizedAlphaHexColorRe_ = /^#[0-9a-f]{8}$/;
  299. /**
  300. * Checks if a string is a normalized alpha hex color.
  301. * We expect strings of the format #RRGGBBAA (ex: #1b3d5f5b)
  302. * using only lowercase letters.
  303. * @param {string} str String to check.
  304. * @return {boolean} Whether the string is a normalized hex color.
  305. * @private
  306. */
  307. goog.color.alpha.isNormalizedAlphaHexColor_ = function(str) {
  308. return goog.color.alpha.normalizedAlphaHexColorRe_.test(str);
  309. };
  310. /**
  311. * Regular expression for matching and capturing RGBA style strings. Helper for
  312. * isValidRgbaColor_.
  313. * @type {RegExp}
  314. * @private
  315. */
  316. goog.color.alpha.rgbaColorRe_ =
  317. /^(?:rgba)?\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2}),\s?(0|1|0\.\d{0,10})\)$/i;
  318. /**
  319. * Regular expression for matching and capturing HSLA style strings. Helper for
  320. * isValidHslaColor_.
  321. * @type {RegExp}
  322. * @private
  323. */
  324. goog.color.alpha.hslaColorRe_ =
  325. /^(?:hsla)\((0|[1-9]\d{0,2}),\s?(0|[1-9]\d{0,2})\%,\s?(0|[1-9]\d{0,2})\%,\s?(0|1|0\.\d{0,10})\)$/i;
  326. /**
  327. * Checks if a string is a valid rgba color. We expect strings of the format
  328. * '(r, g, b, a)', or 'rgba(r, g, b, a)', where r, g, b are ints in [0, 255]
  329. * and a is a float in [0, 1].
  330. * @param {string} str String to check.
  331. * @return {!Array<number>} the integers [r, g, b, a] for valid colors or the
  332. * empty array for invalid colors.
  333. * @private
  334. */
  335. goog.color.alpha.isValidRgbaColor_ = function(str) {
  336. // Each component is separate (rather than using a repeater) so we can
  337. // capture the match. Also, we explicitly set each component to be either 0,
  338. // or start with a non-zero, to prevent octal numbers from slipping through.
  339. var regExpResultArray = str.match(goog.color.alpha.rgbaColorRe_);
  340. if (regExpResultArray) {
  341. var r = Number(regExpResultArray[1]);
  342. var g = Number(regExpResultArray[2]);
  343. var b = Number(regExpResultArray[3]);
  344. var a = Number(regExpResultArray[4]);
  345. if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 &&
  346. a >= 0 && a <= 1) {
  347. return [r, g, b, a];
  348. }
  349. }
  350. return [];
  351. };
  352. /**
  353. * Checks if a string is a valid hsla color. We expect strings of the format
  354. * 'hsla(h, s, l, a)', where s in an int in [0, 360], s and l are percentages
  355. * between 0 and 100 such as '50%' or '70%', and a is a float in [0, 1].
  356. * @param {string} str String to check.
  357. * @return {!Array<number>} the integers [h, s, l, a] for valid colors or the
  358. * empty array for invalid colors.
  359. * @private
  360. */
  361. goog.color.alpha.isValidHslaColor_ = function(str) {
  362. // Each component is separate (rather than using a repeater) so we can
  363. // capture the match. Also, we explicitly set each component to be either 0,
  364. // or start with a non-zero, to prevent octal numbers from slipping through.
  365. var regExpResultArray = str.match(goog.color.alpha.hslaColorRe_);
  366. if (regExpResultArray) {
  367. var h = Number(regExpResultArray[1]);
  368. var s = Number(regExpResultArray[2]);
  369. var l = Number(regExpResultArray[3]);
  370. var a = Number(regExpResultArray[4]);
  371. if (h >= 0 && h <= 360 && s >= 0 && s <= 100 && l >= 0 && l <= 100 &&
  372. a >= 0 && a <= 1) {
  373. return [h, s, l, a];
  374. }
  375. }
  376. return [];
  377. };
  378. /**
  379. * Takes an array of [r, g, b, a] and converts it into a string appropriate for
  380. * CSS styles. The alpha channel value is rounded to 3 decimal places to make
  381. * sure the produced string is not too long.
  382. * @param {Array<number>} rgba [r, g, b, a] with r, g, b in [0, 255] and a
  383. * in [0, 1].
  384. * @return {string} string of the form 'rgba(r,g,b,a)'.
  385. * @private
  386. */
  387. goog.color.alpha.rgbaStyle_ = function(rgba) {
  388. var roundedRgba = rgba.slice(0);
  389. roundedRgba[3] = Math.round(rgba[3] * 1000) / 1000;
  390. return 'rgba(' + roundedRgba.join(',') + ')';
  391. };
  392. /**
  393. * Converts from h,s,v,a values to a hex string
  394. * @param {number} h Hue, in [0, 1].
  395. * @param {number} s Saturation, in [0, 1].
  396. * @param {number} v Value, in [0, 255].
  397. * @param {number} a Alpha, in [0, 1].
  398. * @return {string} hex representation of the color.
  399. */
  400. goog.color.alpha.hsvaToHex = function(h, s, v, a) {
  401. var alpha = Math.floor(a * 255);
  402. return goog.color.hsvArrayToHex([h, s, v]) +
  403. goog.color.prependZeroIfNecessaryHelper(alpha.toString(16));
  404. };
  405. /**
  406. * Converts from an HSVA array to a hex string
  407. * @param {Array<number>} hsva Array of [h, s, v, a] in
  408. * [[0, 1], [0, 1], [0, 255], [0, 1]].
  409. * @return {string} hex representation of the color.
  410. */
  411. goog.color.alpha.hsvaArrayToHex = function(hsva) {
  412. return goog.color.alpha.hsvaToHex(hsva[0], hsva[1], hsva[2], hsva[3]);
  413. };