Color.js 11.6 KB
Newer Older
R
Rich Harris 已提交
1 2
import { _Math } from './Math';

M
Mr.doob 已提交
3
/**
M
Mr.doob 已提交
4
 * @author mrdoob / http://mrdoob.com/
M
Mr.doob 已提交
5 6
 */

7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
A
Andres Cuervo 已提交
26
	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
27 28 29 30 31
	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };

M
Mr.doob 已提交
32
function Color( r, g, b ) {
M
Mr.doob 已提交
33

34
	if ( g === undefined && b === undefined ) {
M
Mr.doob 已提交
35

36 37
		// r is THREE.Color, hex or string
		return this.set( r );
38 39 40

	}

41
	return this.setRGB( r, g, b );
M
Mr.doob 已提交
42

M
Mr.doob 已提交
43
}
M
Mr.doob 已提交
44

45
Object.assign( Color.prototype, {
46

47 48
	isColor: true,

M
Mr.doob 已提交
49
	r: 1, g: 1, b: 1,
50

M
Mr.doob 已提交
51 52
	set: function ( value ) {

53
		if ( value && value.isColor ) {
M
Mr.doob 已提交
54

M
Mr.doob 已提交
55
			this.copy( value );
M
Mr.doob 已提交
56

M
Mr.doob 已提交
57 58 59 60 61 62 63
		} else if ( typeof value === 'number' ) {

			this.setHex( value );

		} else if ( typeof value === 'string' ) {

			this.setStyle( value );
M
Mr.doob 已提交
64

65
		}
M
Mr.doob 已提交
66

M
Mr.doob 已提交
67 68
		return this;

M
Mr.doob 已提交
69 70
	},

M
Mr.doob 已提交
71 72 73 74 75 76
	setScalar: function ( scalar ) {

		this.r = scalar;
		this.g = scalar;
		this.b = scalar;

77 78
		return this;

M
Mr.doob 已提交
79 80
	},

81 82 83 84 85 86 87 88 89 90 91 92
	setHex: function ( hex ) {

		hex = Math.floor( hex );

		this.r = ( hex >> 16 & 255 ) / 255;
		this.g = ( hex >> 8 & 255 ) / 255;
		this.b = ( hex & 255 ) / 255;

		return this;

	},

93
	setRGB: function ( r, g, b ) {
M
Mr.doob 已提交
94 95 96 97 98

		this.r = r;
		this.g = g;
		this.b = b;

M
Mr.doob 已提交
99
		return this;
M
Mr.doob 已提交
100 101 102

	},

103
	setHSL: function () {
104

M
Mr.doob 已提交
105
		function hue2rgb( p, q, t ) {
106

107 108 109 110 111 112
			if ( t < 0 ) t += 1;
			if ( t > 1 ) t -= 1;
			if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;
			if ( t < 1 / 2 ) return q;
			if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );
			return p;
113

D
dubejf 已提交
114
		}
115

W
WestLangley 已提交
116
		return function setHSL( h, s, l ) {
117

118
			// h,s,l ranges are in 0.0 - 1.0
R
Rich Harris 已提交
119 120 121
			h = _Math.euclideanModulo( h, 1 );
			s = _Math.clamp( s, 0, 1 );
			l = _Math.clamp( l, 0, 1 );
122

123
			if ( s === 0 ) {
124

125
				this.r = this.g = this.b = l;
126

127
			} else {
M
Mr.doob 已提交
128

129 130
				var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );
				var q = ( 2 * l ) - p;
131

132 133 134
				this.r = hue2rgb( q, p, h + 1 / 3 );
				this.g = hue2rgb( q, p, h );
				this.b = hue2rgb( q, p, h - 1 / 3 );
135

136
			}
137

138 139 140 141 142
			return this;

		};

	}(),
143

144
	setStyle: function ( style ) {
M
Mr.doob 已提交
145

M
Mr.doob 已提交
146
		function handleAlpha( string ) {
D
dubejf 已提交
147

M
Mr.doob 已提交
148
			if ( string === undefined ) return;
D
dubejf 已提交
149

M
Mr.doob 已提交
150
			if ( parseFloat( string ) < 1 ) {
D
dubejf 已提交
151

M
Mr.doob 已提交
152
				console.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );
D
dubejf 已提交
153 154 155 156 157 158

			}

		}


159
		var m;
160

161
		if ( m = /^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec( style ) ) {
M
Mr.doob 已提交
162

D
dubejf 已提交
163 164
			// rgb / hsl

165 166 167
			var color;
			var name = m[ 1 ];
			var components = m[ 2 ];
M
Mr.doob 已提交
168

169
			switch ( name ) {
170

171
				case 'rgb':
D
dubejf 已提交
172 173
				case 'rgba':

M
Mr.doob 已提交
174
					if ( color = /^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
D
dubejf 已提交
175

M
Mr.doob 已提交
176
						// rgb(255,0,0) rgba(255,0,0,0.5)
D
dubejf 已提交
177 178 179
						this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255;
						this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255;
						this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255;
M
Mr.doob 已提交
180 181

						handleAlpha( color[ 5 ] );
D
dubejf 已提交
182 183 184 185 186

						return this;

					}

M
Mr.doob 已提交
187
					if ( color = /^(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
D
dubejf 已提交
188

M
Mr.doob 已提交
189
						// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
D
dubejf 已提交
190 191 192
						this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100;
						this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100;
						this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100;
M
Mr.doob 已提交
193 194

						handleAlpha( color[ 5 ] );
D
dubejf 已提交
195 196 197 198 199 200 201

						return this;

					}

					break;

202
				case 'hsl':
D
dubejf 已提交
203
				case 'hsla':
204

M
Mr.doob 已提交
205
					if ( color = /^([0-9]*\.?[0-9]+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec( components ) ) {
206

M
Mr.doob 已提交
207
						// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
M
Mr.doob 已提交
208
						var h = parseFloat( color[ 1 ] ) / 360;
D
dubejf 已提交
209 210
						var s = parseInt( color[ 2 ], 10 ) / 100;
						var l = parseInt( color[ 3 ], 10 ) / 100;
M
Mr.doob 已提交
211 212

						handleAlpha( color[ 5 ] );
D
dubejf 已提交
213 214 215 216 217 218 219 220 221 222

						return this.setHSL( h, s, l );

					}

					break;

			}

		} else if ( m = /^\#([A-Fa-f0-9]+)$/.exec( style ) ) {
223

D
dubejf 已提交
224
			// hex color
225

226 227
			var hex = m[ 1 ];
			var size = hex.length;
228

229
			if ( size === 3 ) {
230

D
dubejf 已提交
231
				// #ff0
232 233 234
				this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 0 ), 16 ) / 255;
				this.g = parseInt( hex.charAt( 1 ) + hex.charAt( 1 ), 16 ) / 255;
				this.b = parseInt( hex.charAt( 2 ) + hex.charAt( 2 ), 16 ) / 255;
235

236 237
				return this;

D
dubejf 已提交
238
			} else if ( size === 6 ) {
239

D
dubejf 已提交
240
				// #ff0000
241 242 243 244 245 246 247 248
				this.r = parseInt( hex.charAt( 0 ) + hex.charAt( 1 ), 16 ) / 255;
				this.g = parseInt( hex.charAt( 2 ) + hex.charAt( 3 ), 16 ) / 255;
				this.b = parseInt( hex.charAt( 4 ) + hex.charAt( 5 ), 16 ) / 255;

				return this;

			}

249 250
		}

D
dubejf 已提交
251
		if ( style && style.length > 0 ) {
M
Mr.doob 已提交
252

D
dubejf 已提交
253
			// color keywords
R
Rich Harris 已提交
254
			var hex = ColorKeywords[ style ];
M
Mr.doob 已提交
255

D
dubejf 已提交
256 257 258 259 260 261 262 263 264 265 266
			if ( hex !== undefined ) {

				// red
				this.setHex( hex );

			} else {

				// unknown color
				console.warn( 'THREE.Color: Unknown color ' + style );

			}
M
Mr.doob 已提交
267 268

		}
G
gero3 已提交
269

270
		return this;
M
Mr.doob 已提交
271

P
philogb 已提交
272
	},
M
Mr.doob 已提交
273

274 275
	clone: function () {

M
Mr.doob 已提交
276
		return new this.constructor( this.r, this.g, this.b );
277 278 279

	},

280 281 282 283 284 285 286 287 288 289
	copy: function ( color ) {

		this.r = color.r;
		this.g = color.g;
		this.b = color.b;

		return this;

	},

290
	copyGammaToLinear: function ( color, gammaFactor ) {
291

292
		if ( gammaFactor === undefined ) gammaFactor = 2.0;
293 294 295 296

		this.r = Math.pow( color.r, gammaFactor );
		this.g = Math.pow( color.g, gammaFactor );
		this.b = Math.pow( color.b, gammaFactor );
297 298 299 300 301

		return this;

	},

302 303
	copyLinearToGamma: function ( color, gammaFactor ) {

304
		if ( gammaFactor === undefined ) gammaFactor = 2.0;
305

306
		var safeInverse = ( gammaFactor > 0 ) ? ( 1.0 / gammaFactor ) : 1.0;
307

308 309 310
		this.r = Math.pow( color.r, safeInverse );
		this.g = Math.pow( color.g, safeInverse );
		this.b = Math.pow( color.b, safeInverse );
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349

		return this;

	},

	convertGammaToLinear: function () {

		var r = this.r, g = this.g, b = this.b;

		this.r = r * r;
		this.g = g * g;
		this.b = b * b;

		return this;

	},

	convertLinearToGamma: function () {

		this.r = Math.sqrt( this.r );
		this.g = Math.sqrt( this.g );
		this.b = Math.sqrt( this.b );

		return this;

	},

	getHex: function () {

		return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0;

	},

	getHexString: function () {

		return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 );

	},

350
	getHSL: function ( optionalTarget ) {
351

352
		// h,s,l ranges are in 0.0 - 1.0
353

354 355
		var hsl = optionalTarget || { h: 0, s: 0, l: 0 };

356
		var r = this.r, g = this.g, b = this.b;
357

358 359
		var max = Math.max( r, g, b );
		var min = Math.min( r, g, b );
360

361 362
		var hue, saturation;
		var lightness = ( min + max ) / 2.0;
363

364
		if ( min === max ) {
365

366 367
			hue = 0;
			saturation = 0;
368

369
		} else {
370

371
			var delta = max - min;
372

373
			saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );
374

375
			switch ( max ) {
376

377 378 379
				case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;
				case g: hue = ( b - r ) / delta + 2; break;
				case b: hue = ( r - g ) / delta + 4; break;
380 381 382

			}

383
			hue /= 6;
384

385
		}
386

387 388 389 390 391
		hsl.h = hue;
		hsl.s = saturation;
		hsl.l = lightness;

		return hsl;
392

393
	},
394

M
Mr.doob 已提交
395 396 397 398 399 400
	getStyle: function () {

		return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')';

	},

401
	offsetHSL: function ( h, s, l ) {
402

403
		var hsl = this.getHSL();
404

405
		hsl.h += h; hsl.s += s; hsl.l += l;
406

407
		this.setHSL( hsl.h, hsl.s, hsl.l );
408

409
		return this;
410 411 412

	},

413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442
	add: function ( color ) {

		this.r += color.r;
		this.g += color.g;
		this.b += color.b;

		return this;

	},

	addColors: function ( color1, color2 ) {

		this.r = color1.r + color2.r;
		this.g = color1.g + color2.g;
		this.b = color1.b + color2.b;

		return this;

	},

	addScalar: function ( s ) {

		this.r += s;
		this.g += s;
		this.b += s;

		return this;

	},

M
Mr.doob 已提交
443 444 445 446 447 448 449 450 451 452
	sub: function( color ) {

		this.r = Math.max( 0, this.r - color.r );
		this.g = Math.max( 0, this.g - color.g );
		this.b = Math.max( 0, this.b - color.b );

		return this;

	},

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472
	multiply: function ( color ) {

		this.r *= color.r;
		this.g *= color.g;
		this.b *= color.b;

		return this;

	},

	multiplyScalar: function ( s ) {

		this.r *= s;
		this.g *= s;
		this.b *= s;

		return this;

	},

473
	lerp: function ( color, alpha ) {
M
Mr.doob 已提交
474 475 476 477 478 479 480 481 482

		this.r += ( color.r - this.r ) * alpha;
		this.g += ( color.g - this.g ) * alpha;
		this.b += ( color.b - this.b ) * alpha;

		return this;

	},

B
Ben Houston 已提交
483 484 485 486 487 488
	equals: function ( c ) {

		return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );

	},

M
Mr.doob 已提交
489
	fromArray: function ( array, offset ) {
490

M
Mr.doob 已提交
491 492 493 494 495
		if ( offset === undefined ) offset = 0;

		this.r = array[ offset ];
		this.g = array[ offset + 1 ];
		this.b = array[ offset + 2 ];
496 497 498 499 500

		return this;

	},

501
	toArray: function ( array, offset ) {
502

503 504
		if ( array === undefined ) array = [];
		if ( offset === undefined ) offset = 0;
505

506
		array[ offset ] = this.r;
507 508 509 510
		array[ offset + 1 ] = this.g;
		array[ offset + 2 ] = this.b;

		return array;
G
gero3 已提交
511

M
Mr.doob 已提交
512 513 514 515 516 517
	},

	toJSON: function () {

		return this.getHex();

518
	}
M
Mr.doob 已提交
519

520
} );
R
Rich Harris 已提交
521 522


523
export { Color };