color.js 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603
  1. define(function(){
  2. var Events = {
  3. RGB_UPDATED : 'RGBUpdated',
  4. HSL_UPDATED : 'HSLUpdated',
  5. HSV_UPDATED : 'HSVUpdated',
  6. HEX_UPDATED : 'HexUpdated',
  7. INT_UPDATED : 'IntUpdated',
  8. UPDATED : 'updated'
  9. };
  10. var namedColors = {
  11. 'transparent':'rgba(0, 0, 0, 0)','aliceblue':'#F0F8FF','antiquewhite':'#FAEBD7','aqua':'#00FFFF','aquamarine':'#7FFFD4',
  12. 'azure':'#F0FFFF','beige':'#F5F5DC','bisque':'#FFE4C4','black':'#000000','blanchedalmond':'#FFEBCD','blue':'#0000FF','blueviolet':'#8A2BE2',
  13. 'brown':'#A52A2A','burlywood':'#DEB887','cadetblue':'#5F9EA0','chartreuse':'#7FFF00','chocolate':'#D2691E','coral':'#FF7F50',
  14. 'cornflowerblue':'#6495ED','cornsilk':'#FFF8DC','crimson':'#DC143C','cyan':'#00FFFF','darkblue':'#00008B','darkcyan':'#008B8B','darkgoldenrod':'#B8860B',
  15. 'darkgray':'#A9A9A9','darkgrey':'#A9A9A9','darkgreen':'#006400','darkkhaki':'#BDB76B','darkmagenta':'#8B008B','darkolivegreen':'#556B2F',
  16. 'darkorange':'#FF8C00','darkorchid':'#9932CC','darkred':'#8B0000','darksalmon':'#E9967A','darkseagreen':'#8FBC8F','darkslateblue':'#483D8B',
  17. 'darkslategray':'#2F4F4F','darkslategrey':'#2F4F4F','darkturquoise':'#00CED1','darkviolet':'#9400D3','deeppink':'#FF1493','deepskyblue':'#00BFFF',
  18. 'dimgray':'#696969','dimgrey':'#696969','dodgerblue':'#1E90FF','firebrick':'#B22222','floralwhite':'#FFFAF0','forestgreen':'#228B22',
  19. 'fuchsia':'#FF00FF','gainsboro':'#DCDCDC','ghostwhite':'#F8F8FF','gold':'#FFD700','goldenrod':'#DAA520','gray':'#808080','grey':'#808080',
  20. 'green':'#008000','greenyellow':'#ADFF2F','honeydew':'#F0FFF0','hotpink':'#FF69B4','indianred':'#CD5C5C','indigo':'#4B0082','ivory':'#FFFFF0',
  21. 'khaki':'#F0E68C','lavender':'#E6E6FA','lavenderblush':'#FFF0F5','lawngreen':'#7CFC00','lemonchiffon':'#FFFACD','lightblue':'#ADD8E6',
  22. 'lightcoral':'#F08080','lightcyan':'#E0FFFF','lightgoldenrodyellow':'#FAFAD2','lightgray':'#D3D3D3','lightgrey':'#D3D3D3','lightgreen':'#90EE90',
  23. 'lightpink':'#FFB6C1','lightsalmon':'#FFA07A','lightseagreen':'#20B2AA','lightskyblue':'#87CEFA','lightslategray':'#778899',
  24. 'lightslategrey':'#778899','lightsteelblue':'#B0C4DE','lightyellow':'#FFFFE0','lime':'#00FF00','limegreen':'#32CD32','linen':'#FAF0E6',
  25. 'magenta':'#FF00FF','maroon':'#800000','mediumaquamarine':'#66CDAA','mediumblue':'#0000CD','mediumorchid':'#BA55D3','mediumpurple':'#9370D8',
  26. 'mediumseagreen':'#3CB371','mediumslateblue':'#7B68EE','mediumspringgreen':'#00FA9A','mediumturquoise':'#48D1CC','mediumvioletred':'#C71585',
  27. 'midnightblue':'#191970','mintcream':'#F5FFFA','mistyrose':'#FFE4E1','moccasin':'#FFE4B5','navajowhite':'#FFDEAD','navy':'#000080','oldlace':'#FDF5E6',
  28. 'olive':'#808000','olivedrab':'#6B8E23','orange':'#FFA500','orangered':'#FF4500','orchid':'#DA70D6','palegoldenrod':'#EEE8AA',
  29. 'palegreen':'#98FB98','paleturquoise':'#AFEEEE','palevioletred':'#D87093','papayawhip':'#FFEFD5','peachpuff':'#FFDAB9','peru':'#CD853F',
  30. 'pink':'#FFC0CB','plum':'#DDA0DD','powderblue':'#B0E0E6','purple':'#800080','red':'#FF0000','rosybrown':'#BC8F8F','royalblue':'#4169E1',
  31. 'saddlebrown':'#8B4513','salmon':'#FA8072','sandybrown':'#F4A460','seagreen':'#2E8B57','seashell':'#FFF5EE','sienna':'#A0522D','silver':'#C0C0C0',
  32. 'skyblue':'#87CEEB','slateblue':'#6A5ACD','slategray':'#708090','slategrey':'#708090','snow':'#FFFAFA','springgreen':'#00FF7F','yellow':'#FFFF00',
  33. 'steelblue':'#4682B4','tan':'#D2B48C','teal':'#008080','thistle':'#D8BFD8','tomato':'#FF6347','turquoise':'#40E0D0','violet':'#EE82EE'
  34. };
  35. var absround = function(number){
  36. return (0.5 + number) << 0;
  37. };
  38. var hue2rgb = function(a, b, c) {
  39. if(c < 0) c += 1;
  40. if(c > 1) c -= 1;
  41. if(c < 1/6) return a + (b - a) * 6 * c;
  42. if(c < 1/2) return b;
  43. if(c < 2/3) return a + (b - a) * (2/3 - c) * 6;
  44. return a;
  45. };
  46. var p2v = function( p ){
  47. if ( typeof p === 'string' || typeof p === 'String' ) { p = Number( p ) }
  48. return isPercent.test( p ) ? absround( parseInt( p ) * 2.55 ) : p;
  49. };
  50. var isHex = /^#?([0-9a-f]{3}|[0-9a-f]{6})$/i;
  51. var isHSL = /^hsla?\((\d{1,3}?),\s*(\d{1,3}%),\s*(\d{1,3}%)(,\s*[01]?\.?\d*)?\)$/;
  52. var isRGB = /^rgba?\((\d{1,3}%?),\s*(\d{1,3}%?),\s*(\d{1,3}%?)(,\s*[01]?\.?\d*)?\)$/;
  53. var isPercent = /^\d+(\.\d+)*%$/;
  54. var isString = function( s ) {
  55. return ( typeof( s ) === 'string' || s instanceof String );
  56. }
  57. var hexBit = /([0-9a-f])/gi;
  58. var leadHex = /^#/;
  59. var matchHSL = /^hsla?\((\d{1,3}),\s*(\d{1,3})%,\s*(\d{1,3})%(,\s*([01]?\.?\d*))?\)$/;
  60. var matchRGB = /^rgba?\((\d{1,3}%?),\s*(\d{1,3}%?),\s*(\d{1,3}%?)(,\s*([01]?\.?\d*))?\)$/;
  61. function Color(value){
  62. this._listeners = {};
  63. this.subscribe(Events.RGB_UPDATED, this._RGBUpdated);
  64. this.subscribe(Events.HEX_UPDATED, this._HEXUpdated);
  65. this.subscribe(Events.HSL_UPDATED, this._HSLUpdated);
  66. this.subscribe(Events.HSV_UPDATED, this._HSVUpdated);
  67. this.subscribe(Events.INT_UPDATED, this._INTUpdated);
  68. this.parse(value);
  69. };
  70. Color.prototype._decimal = 0;
  71. Color.prototype._hex = '#000000';
  72. Color.prototype._red = 0;
  73. Color.prototype._green = 0;
  74. Color.prototype._blue = 0;
  75. Color.prototype._hue = 0;
  76. Color.prototype._saturation = 0;
  77. Color.prototype._lightness = 0;
  78. Color.prototype._brightness = 0;
  79. Color.prototype._alpha = 1;
  80. Color.prototype.parse = function(value){
  81. if(typeof value == 'undefined'){
  82. return this;
  83. };
  84. switch(true){
  85. case isFinite(value) :
  86. this.decimal(value);
  87. this.output = Color.INT;
  88. return this;
  89. case (value instanceof Color) :
  90. this.copy(value);
  91. return this;
  92. case ( isString( value ) ):
  93. value = value.replace( /\s/g, '' );
  94. switch(true){
  95. case (namedColors.hasOwnProperty(value)) :
  96. value = namedColors[value];
  97. var stripped = value.replace(leadHex, '');
  98. this.decimal(parseInt(stripped, 16));
  99. return this;
  100. case isHex.test(value) :
  101. var stripped = value.replace(leadHex, '');
  102. if(stripped.length == 3) {
  103. stripped = stripped.replace(hexBit, '$1$1');
  104. };
  105. this.decimal(parseInt(stripped, 16));
  106. return this;
  107. case isRGB.test(value) :
  108. var parts = value.match(matchRGB);
  109. var alphaIsValid = !( isNaN( parseFloat( parts[5] ) ) );
  110. this.red(p2v(parts[1]));
  111. this.green(p2v(parts[2]));
  112. this.blue(p2v(parts[3]));
  113. this.alpha( alphaIsValid ? parseFloat( parts[5] ) : 1 );
  114. this.output = alphaIsValid ? Color.RGBA : ( isPercent.test( parts[1] ) ? Color.PRGB : Color.RGB );
  115. return this;
  116. case isHSL.test(value) :
  117. var parts = value.match(matchHSL);
  118. this.hue(parseInt(parts[1]));
  119. this.saturation(parseInt(parts[2]));
  120. this.lightness(parseInt(parts[3]));
  121. this.alpha( isNaN( parseFloat( parts[5] ) ) ? 1 : parseFloat( parts[5] ) );
  122. this.output = parts[5] ? 6: 5;
  123. return this;
  124. default:
  125. console.info( "WARNING: color not parsed" );
  126. break;
  127. };
  128. break;
  129. default :
  130. switch(typeof value) {
  131. case 'object' :
  132. if ( value instanceof Array ) {
  133. if ( value.length == 3 ) {
  134. this.red( p2v( value[0] ) );
  135. this.green( p2v( value[1] ) );
  136. this.blue( p2v( value[2] ) );
  137. this.alpha( 1 );
  138. this.output = Color.RGB;
  139. } else if ( value.length == 4 ) {
  140. this.red( p2v( value[0] ) );
  141. this.green( p2v( value[1] ) );
  142. this.blue( p2v( value[2] ) );
  143. this.alpha( isNaN( parseFloat( value[3] ) ) ? 1 : parseFloat( value[3] ) );
  144. this.output = Color.RGBA;
  145. }
  146. } else {
  147. this.set( value );
  148. }
  149. return this;
  150. case 'string' :
  151. value = value.replace( /\s/g, '' );
  152. switch(true){
  153. case (namedColors.hasOwnProperty(value)) :
  154. value = namedColors[value];
  155. var stripped = value.replace(leadHex, '');
  156. this.decimal(parseInt(stripped, 16));
  157. return this;
  158. case isHex.test(value) :
  159. var stripped = value.replace(leadHex, '');
  160. if(stripped.length == 3) {
  161. stripped = stripped.replace(hexBit, '$1$1');
  162. };
  163. this.decimal(parseInt(stripped, 16));
  164. return this;
  165. case isRGB.test(value) :
  166. var parts = value.match(matchRGB);
  167. var alphaIsValid = !( isNaN( parseFloat( parts[5] ) ) );
  168. this.red(p2v(parts[1]));
  169. this.green(p2v(parts[2]));
  170. this.blue(p2v(parts[3]));
  171. this.alpha( alphaIsValid ? parseFloat( parts[5] ) : 1 );
  172. this.output = alphaIsValid ? Color.RGBA : ( isPercent.test( parts[1] ) ? Color.PRGB : Color.RGB );
  173. return this;
  174. case isHSL.test(value) :
  175. var parts = value.match(matchHSL);
  176. this.hue(parseInt(parts[1]));
  177. this.saturation(parseInt(parts[2]));
  178. this.lightness(parseInt(parts[3]));
  179. this.alpha( isNaN( parseFloat( parts[5] ) ) ? 1 : parseFloat( parts[5] ) );
  180. this.output = parts[5] ? 6: 5;
  181. return this;
  182. default:
  183. console.info( "WARNING: color not parsed" );
  184. break;
  185. };
  186. };
  187. };
  188. return this;
  189. };
  190. Color.prototype.clone = function(){
  191. return new Color(this.decimal());
  192. };
  193. Color.prototype.copy = function(color){
  194. this.set(color.decimal());
  195. return this;
  196. };
  197. Color.prototype.set = function(key, value){
  198. if(arguments.length == 1){
  199. if(typeof key == 'object'){
  200. for(var p in key){
  201. if(typeof this[p] == 'function'){
  202. this[p](key[p]);
  203. };
  204. };
  205. } else if(isFinite(key)){
  206. this.decimal(key);
  207. }
  208. } else if(typeof this[key] == 'function'){
  209. this[key](value);
  210. };
  211. return this;
  212. };
  213. Color.prototype.interpolate = function(destination, factor){
  214. if(!(destination instanceof Color)){
  215. destination = new Color(destination);
  216. };
  217. this._red = absround( +(this._red) + (destination._red - this._red) * factor );
  218. this._green = absround( +(this._green) + (destination._green - this._green) * factor );
  219. this._blue = absround( +(this._blue) + (destination._blue - this._blue) * factor );
  220. this._alpha = absround( +(this._alpha) + (destination._alpha - this._alpha) * factor );
  221. this.broadcast(Events.RGB_UPDATED);
  222. this.broadcast(Events.UPDATED);
  223. return this;
  224. };
  225. Color.prototype._RGB2HSL = function(){
  226. var r = this._red / 255;
  227. var g = this._green / 255;
  228. var b = this._blue / 255;
  229. var max = Math.max(r, g, b);
  230. var min = Math.min(r, g, b);
  231. var l = (max + min) / 2;
  232. var v = max;
  233. if(max == min) {
  234. this._hue = 0;
  235. this._saturation = 0;
  236. this._lightness = absround(l * 100);
  237. this._brightness = absround(v * 100);
  238. return;
  239. };
  240. var d = max - min;
  241. var s = d / ( ( l <= 0.5) ? (max + min) : (2 - max - min) );
  242. var h = ((max == r)
  243. ? (g - b) / d + (g < b ? 6 : 0)
  244. : (max == g)
  245. ? ((b - r) / d + 2)
  246. : ((r - g) / d + 4)) / 6;
  247. this._hue = absround(h * 360);
  248. this._saturation = absround(s * 100);
  249. this._lightness = absround(l * 100);
  250. this._brightness = absround(v * 100);
  251. };
  252. Color.prototype._HSL2RGB = function(){
  253. var h = this._hue / 360;
  254. var s = this._saturation / 100;
  255. var l = this._lightness / 100;
  256. var q = l < 0.5 ? l * (1 + s) : (l + s - l * s);
  257. var p = 2 * l - q;
  258. this._red = absround(hue2rgb(p, q, h + 1/3) * 255);
  259. this._green = absround(hue2rgb(p, q, h) * 255);
  260. this._blue = absround(hue2rgb(p, q, h - 1/3) * 255);
  261. };
  262. Color.prototype._HSV2RGB = function(){
  263. var h = this._hue / 360;
  264. var s = this._saturation / 100;
  265. var v = this._brightness / 100;
  266. var r = 0;
  267. var g = 0;
  268. var b = 0;
  269. var i = Math.floor(h * 6);
  270. var f = h * 6 - i;
  271. var p = v * (1 - s);
  272. var q = v * (1 - f * s);
  273. var t = v * (1 - (1 - f) * s);
  274. switch(i % 6){
  275. case 0 :
  276. r = v, g = t, b = p;
  277. break;
  278. case 1 :
  279. r = q, g = v, b = p;
  280. break;
  281. case 2 :
  282. r = p, g = v, b = t;
  283. break;
  284. case 3 :
  285. r = p, g = q, b = v;
  286. break;
  287. case 4 :
  288. r = t, g = p, b = v
  289. break;
  290. case 5 :
  291. r = v, g = p, b = q;
  292. break;
  293. }
  294. this._red = absround(r * 255);
  295. this._green = absround(g * 255);
  296. this._blue = absround(b * 255);
  297. };
  298. Color.prototype._INT2HEX = function(){
  299. var x = this._decimal.toString(16);
  300. x = '000000'.substr(0, 6 - x.length) + x;
  301. this._hex = '#' + x.toUpperCase();
  302. };
  303. Color.prototype._INT2RGB = function(){
  304. this._red = this._decimal >> 16;
  305. this._green = (this._decimal >> 8) & 0xFF;
  306. this._blue = this._decimal & 0xFF;
  307. };
  308. Color.prototype._HEX2INT = function(){
  309. this._decimal = parseInt(this._hex, 16);
  310. };
  311. Color.prototype._RGB2INT = function(){
  312. this._decimal = (this._red << 16 | (this._green << 8) & 0xffff | this._blue);
  313. };
  314. Color.prototype._RGBUpdated = function(){
  315. this._RGB2INT();
  316. this._RGB2HSL();
  317. this._INT2HEX();
  318. };
  319. Color.prototype._HSLUpdated = function(){
  320. this._HSL2RGB();
  321. this._RGB2INT();
  322. this._INT2HEX();
  323. };
  324. Color.prototype._HSVUpdated = function(){
  325. this._HSV2RGB();
  326. this._RGB2INT();
  327. this._INT2HEX();
  328. };
  329. Color.prototype._HEXUpdated = function(){
  330. this._HEX2INT();
  331. this._INT2RGB();
  332. this._RGB2HSL();
  333. };
  334. Color.prototype._INTUpdated = function(){
  335. this._INT2RGB();
  336. this._RGB2HSL();
  337. this._INT2HEX();
  338. };
  339. Color.prototype._broadcastUpdate = function(){
  340. this.broadcast(Event.UPDATED);
  341. };
  342. Color.prototype.decimal = function(value){
  343. return this._handle('_decimal', value, Events.INT_UPDATED);
  344. };
  345. Color.prototype.hex = function(value){
  346. return this._handle('_hex', value, Events.HEX_UPDATED);
  347. };
  348. Color.prototype.red = function(value){
  349. return this._handle('_red', value, Events.RGB_UPDATED);
  350. };
  351. Color.prototype.green = function(value){
  352. return this._handle('_green', value, Events.RGB_UPDATED);
  353. };
  354. Color.prototype.blue = function(value){
  355. return this._handle('_blue', value, Events.RGB_UPDATED);
  356. };
  357. Color.prototype.hue = function(value){
  358. return this._handle('_hue', value, Events.HSL_UPDATED);
  359. };
  360. Color.prototype.saturation = function(value){
  361. return this._handle('_saturation', value, Events.HSL_UPDATED);
  362. };
  363. Color.prototype.lightness = function(value){
  364. return this._handle('_lightness', value, Events.HSL_UPDATED);
  365. };
  366. Color.prototype.brightness = function(value){
  367. return this._handle('_brightness', value, Events.HSV_UPDATED);
  368. };
  369. Color.prototype.alpha = function(value){
  370. return this._handle('_alpha', value);
  371. };
  372. Color.prototype._handle = function(prop, value, event){
  373. if(typeof this[prop] != 'undefined'){
  374. if(typeof value != 'undefined'){
  375. if(value != this[prop]){
  376. this[prop] = value;
  377. if(event){
  378. this.broadcast(event);
  379. };
  380. };
  381. this.broadcast(Event.UPDATED);
  382. };
  383. };
  384. return this[prop];
  385. };
  386. Color.prototype.getHex = function(){
  387. return this._hex;
  388. };
  389. Color.prototype.getRGB = function(){
  390. var components = [absround(this._red), absround(this._green), absround(this._blue)];
  391. return 'rgb(' + components.join(', ') + ')';
  392. };
  393. Color.prototype.getPRGB = function(){
  394. var components = [absround(100 * this._red / 255) + '%', absround(100 * this._green / 255) + '%', absround(100 * this._blue / 255) + '%'];
  395. return 'rgb(' + components.join(', ') + ')';
  396. };
  397. Color.prototype.getRGBA = function(){
  398. var components = [absround(this._red), absround(this._green), absround(this._blue), this._alpha];
  399. return 'rgba(' + components.join(', ') + ')';
  400. };
  401. Color.prototype.getPRGBA = function(){
  402. var components = [absround(100 * this._red / 255) + '%', absround(100 * this._green / 255) + '%', absround(100 * this._blue / 255) + '%', this._alpha];
  403. return 'rgba(' + components.join(', ') + ')';
  404. };
  405. Color.prototype.getHSL = function(){
  406. var components = [absround(this._hue), absround(this._saturation) + '%', absround(this._lightness) + '%'];
  407. return 'hsl(' + components.join(', ') + ')';
  408. };
  409. Color.prototype.getHSLA = function(){
  410. var components = [absround(this._hue), absround(this._saturation) + '%', absround(this._lightness) + '%', this._alpha];
  411. return 'hsla(' + components.join(', ') + ')';
  412. };
  413. Color.prototype.format = function(string){
  414. var tokens = {
  415. r : this._red,
  416. g : this._green,
  417. b : this._blue,
  418. h : this._hue,
  419. s : this._saturation,
  420. l : this._lightness,
  421. v : this._brightness,
  422. a : this._alpha,
  423. x : this._hex,
  424. d : this._decimal
  425. };
  426. for(var token in tokens){
  427. string = string.split('%' + token + '%').join(tokens[token]);
  428. };
  429. return string;
  430. };
  431. Color.prototype.output = 0;
  432. Color.HEX = 0;
  433. Color.RGB = 1;
  434. Color.PRGB = 2;
  435. Color.RGBA = 3;
  436. Color.PRGBA = 4;
  437. Color.HSL = 5;
  438. Color.HSLA = 6;
  439. Color.INT = 7;
  440. Color.prototype.toString = function(){
  441. switch(this.output){
  442. case 0 :
  443. return this.getHex();
  444. case 1 :
  445. return this.getRGB();
  446. case 2 :
  447. return this.getPRGB();
  448. case 3 :
  449. return this.getRGBA();
  450. case 4 :
  451. return this.getPRGBA();
  452. case 5 :
  453. return this.getHSL();
  454. case 6 :
  455. return this.getHSLA();
  456. case 7 :
  457. return this._decimal;
  458. };
  459. return this.getHex();
  460. };
  461. Color.prototype.toArray = function(){
  462. if ( this._alpha != 1 ) {
  463. return [ this._red, this._green, this._blue, this._alpha ];
  464. } else {
  465. return [ this._red, this._green, this._blue ];
  466. }
  467. };
  468. Color.prototype._listeners = null;
  469. Color.prototype._isSubscribed = function(type){
  470. return this._listeners[type] != null;
  471. };
  472. Color.prototype.subscribe = function(type, callback){
  473. if(!this._isSubscribed(type)) {
  474. this._listeners[type] = [];
  475. };
  476. this._listeners[type].push(callback);
  477. };
  478. Color.prototype.unsubscribe = function(type, callback){
  479. if(!this._isSubscribed(type)) {
  480. return;
  481. };
  482. var stack = this._listeners[type];
  483. for(var i = 0, l = stack.length; i < l; i++){
  484. if(stack[i] === callback){
  485. stack.splice(i, 1);
  486. return this.unsubscribe(type, callback);
  487. };
  488. };
  489. };
  490. Color.prototype.broadcast = function(type, params){
  491. if(!this._isSubscribed(type)) {
  492. return;
  493. }
  494. var stack = this._listeners[type];
  495. var l = stack.length;
  496. for(var i = 0; i < l; i++) {
  497. stack[i].apply(this, params);
  498. }
  499. };
  500. Color.prototype.tween = function(duration, color){
  501. if(!(color instanceof Color)){
  502. color = new Color(color);
  503. };
  504. var start = +(new Date());
  505. var ref = this;
  506. this.broadcast('tweenStart');
  507. var interval = setInterval(function(){
  508. var ellapsed = +(new Date()) - start;
  509. var delta = Math.min(1, ellapsed / duration);
  510. ref.interpolate(color, delta);
  511. ref.broadcast('tweenProgress');
  512. if(delta == 1){
  513. clearInterval(interval);
  514. ref.broadcast('tweenComplete');
  515. };
  516. }, 20);
  517. return interval;
  518. };
  519. Color.prototype.bind = function(object, property){
  520. var ref = this;
  521. this.subscribe('updated', function(){
  522. object[property] = ref.toString();
  523. });
  524. };
  525. Color.random = function(){
  526. return new Color(absround(Math.random() * 16777215));
  527. };
  528. Color.bind = function(object, property){
  529. var color = new Color(object[property]);
  530. color.bind(object, property);
  531. return color;
  532. };
  533. Color.Events = Events;
  534. return Color;
  535. });