hsla.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. /*!
  2. * Stylus - HSLA
  3. * Copyright (c) Automattic <developer.wordpress.com>
  4. * MIT Licensed
  5. */
  6. /**
  7. * Module dependencies.
  8. */
  9. var Node = require('./node')
  10. , nodes = require('./');
  11. /**
  12. * Initialize a new `HSLA` with the given h,s,l,a component values.
  13. *
  14. * @param {Number} h
  15. * @param {Number} s
  16. * @param {Number} l
  17. * @param {Number} a
  18. * @api public
  19. */
  20. var HSLA = exports = module.exports = function HSLA(h,s,l,a){
  21. Node.call(this);
  22. this.h = clampDegrees(h);
  23. this.s = clampPercentage(s);
  24. this.l = clampPercentage(l);
  25. this.a = clampAlpha(a);
  26. this.hsla = this;
  27. };
  28. /**
  29. * Inherit from `Node.prototype`.
  30. */
  31. HSLA.prototype.__proto__ = Node.prototype;
  32. /**
  33. * Return hsla(n,n,n,n).
  34. *
  35. * @return {String}
  36. * @api public
  37. */
  38. HSLA.prototype.toString = function(){
  39. return 'hsla('
  40. + this.h + ','
  41. + this.s.toFixed(0) + '%,'
  42. + this.l.toFixed(0) + '%,'
  43. + this.a + ')';
  44. };
  45. /**
  46. * Return a clone of this node.
  47. *
  48. * @return {Node}
  49. * @api public
  50. */
  51. HSLA.prototype.clone = function(parent){
  52. var clone = new HSLA(
  53. this.h
  54. , this.s
  55. , this.l
  56. , this.a);
  57. clone.lineno = this.lineno;
  58. clone.column = this.column;
  59. clone.filename = this.filename;
  60. return clone;
  61. };
  62. /**
  63. * Return a JSON representation of this node.
  64. *
  65. * @return {Object}
  66. * @api public
  67. */
  68. HSLA.prototype.toJSON = function(){
  69. return {
  70. __type: 'HSLA',
  71. h: this.h,
  72. s: this.s,
  73. l: this.l,
  74. a: this.a,
  75. lineno: this.lineno,
  76. column: this.column,
  77. filename: this.filename
  78. };
  79. };
  80. /**
  81. * Return rgba `RGBA` representation.
  82. *
  83. * @return {RGBA}
  84. * @api public
  85. */
  86. HSLA.prototype.__defineGetter__('rgba', function(){
  87. return nodes.RGBA.fromHSLA(this);
  88. });
  89. /**
  90. * Return hash.
  91. *
  92. * @return {String}
  93. * @api public
  94. */
  95. HSLA.prototype.__defineGetter__('hash', function(){
  96. return this.rgba.toString();
  97. });
  98. /**
  99. * Add h,s,l to the current component values.
  100. *
  101. * @param {Number} h
  102. * @param {Number} s
  103. * @param {Number} l
  104. * @return {HSLA} new node
  105. * @api public
  106. */
  107. HSLA.prototype.add = function(h,s,l){
  108. return new HSLA(
  109. this.h + h
  110. , this.s + s
  111. , this.l + l
  112. , this.a);
  113. };
  114. /**
  115. * Subtract h,s,l from the current component values.
  116. *
  117. * @param {Number} h
  118. * @param {Number} s
  119. * @param {Number} l
  120. * @return {HSLA} new node
  121. * @api public
  122. */
  123. HSLA.prototype.sub = function(h,s,l){
  124. return this.add(-h, -s, -l);
  125. };
  126. /**
  127. * Operate on `right` with the given `op`.
  128. *
  129. * @param {String} op
  130. * @param {Node} right
  131. * @return {Node}
  132. * @api public
  133. */
  134. HSLA.prototype.operate = function(op, right){
  135. switch (op) {
  136. case '==':
  137. case '!=':
  138. case '<=':
  139. case '>=':
  140. case '<':
  141. case '>':
  142. case 'is a':
  143. case '||':
  144. case '&&':
  145. return this.rgba.operate(op, right);
  146. default:
  147. return this.rgba.operate(op, right).hsla;
  148. }
  149. };
  150. /**
  151. * Return `HSLA` representation of the given `color`.
  152. *
  153. * @param {RGBA} color
  154. * @return {HSLA}
  155. * @api public
  156. */
  157. exports.fromRGBA = function(rgba){
  158. var r = rgba.r / 255
  159. , g = rgba.g / 255
  160. , b = rgba.b / 255
  161. , a = rgba.a;
  162. var min = Math.min(r,g,b)
  163. , max = Math.max(r,g,b)
  164. , l = (max + min) / 2
  165. , d = max - min
  166. , h, s;
  167. switch (max) {
  168. case min: h = 0; break;
  169. case r: h = 60 * (g-b) / d; break;
  170. case g: h = 60 * (b-r) / d + 120; break;
  171. case b: h = 60 * (r-g) / d + 240; break;
  172. }
  173. if (max == min) {
  174. s = 0;
  175. } else if (l < .5) {
  176. s = d / (2 * l);
  177. } else {
  178. s = d / (2 - 2 * l);
  179. }
  180. h %= 360;
  181. s *= 100;
  182. l *= 100;
  183. return new HSLA(h,s,l,a);
  184. };
  185. /**
  186. * Adjust lightness by `percent`.
  187. *
  188. * @param {Number} percent
  189. * @return {HSLA} for chaining
  190. * @api public
  191. */
  192. HSLA.prototype.adjustLightness = function(percent){
  193. this.l = clampPercentage(this.l + this.l * (percent / 100));
  194. return this;
  195. };
  196. /**
  197. * Adjust hue by `deg`.
  198. *
  199. * @param {Number} deg
  200. * @return {HSLA} for chaining
  201. * @api public
  202. */
  203. HSLA.prototype.adjustHue = function(deg){
  204. this.h = clampDegrees(this.h + deg);
  205. return this;
  206. };
  207. /**
  208. * Clamp degree `n` >= 0 and <= 360.
  209. *
  210. * @param {Number} n
  211. * @return {Number}
  212. * @api private
  213. */
  214. function clampDegrees(n) {
  215. n = n % 360;
  216. return n >= 0 ? n : 360 + n;
  217. }
  218. /**
  219. * Clamp percentage `n` >= 0 and <= 100.
  220. *
  221. * @param {Number} n
  222. * @return {Number}
  223. * @api private
  224. */
  225. function clampPercentage(n) {
  226. return Math.max(0, Math.min(n, 100));
  227. }
  228. /**
  229. * Clamp alpha `n` >= 0 and <= 1.
  230. *
  231. * @param {Number} n
  232. * @return {Number}
  233. * @api private
  234. */
  235. function clampAlpha(n) {
  236. return Math.max(0, Math.min(n, 1));
  237. }