3d-core-raub
Version:
An extensible Node3D core for desktop applications
266 lines (209 loc) • 5.48 kB
JavaScript
'use strict';
const Vec4 = require('./vec4');
const Vec3 = require('./vec3');
/**
* Four-component color
* @author Luis Blanco
* @extends Vec4
*/
class Color extends Vec4 {
/**
* @constructs Color
* @desc Takes four numbers, or single array, or an object with `.r`, `.g`, `.b`, and `.a` properties.
* - If no arguments passed, constructs `Color(0, 0, 0, 1)`.
* - If only one number is given, constructs `Color(r, r, r, 1)`.
* - If only two numbers are given, constructs `Color(r, r, r, g)`.
* - If three numbers are given, constructs `Color(r, g, b, 1)`.
* @arg {number|number[]|object} [x=0]
* @arg {Number} [y=0]
* @arg {Number} [z=0]
* @arg {Number} [w=0]
*/
constructor() {
const args = arguments;
let method = 'rgbaFromEmpty';
if (args.length) {
if (typeof args[0] === 'object') {
method = 'rgbaFromObject';
} else if (typeof args[0] === 'number' && args[0] < 256) {
method = 'rgbaFromFloats';
} else if (typeof args[0] === 'number' || typeof args[0] === 'string') {
method = 'rgbaFromString';
}
}
const { r, g, b, a } = Color[method](args);
super(r, g, b, a);
}
static clampTo1(x) {
return x > 1 ? x / 255 : x;
}
static rgbaFromEmpty() {
let r = 0, g = 0, b = 0, a = 1;
return { r, g, b, a };
}
static rgbaFromObject(args) {
let r = 0, g = 0, b = 0, a = 1;
if (args[0] === null) {
return { r, g, b, a };
}
// [] or {} or Vec2
if (args[0].constructor === Array || args[0].constructor === Color) {
r = args[0][0];
g = args[0][1];
b = args[0][2];
a = typeof args[0][3] === 'number' ? args[0][3] : 1;
} else if (
typeof args[0].r === 'number' && typeof args[0].g === 'number' &&
typeof args[0].b === 'number'
) {
r = args[0].r;
g = args[0].g;
b = args[0].b;
a = typeof args[0].a === 'number' ? args[0].a : 1;
} else if (args[0].constructor === Vec3) {
r = args[0].x;
g = args[0].y;
b = args[0].z;
a = typeof args[1] === 'number' ? args[1] : 1;
}
r = Color.clampTo1(r);
g = Color.clampTo1(g);
b = Color.clampTo1(b);
a = Color.clampTo1(a);
return { r, g, b, a };
}
static rgbaFromFloats(args) {
let r = 0, g = 0, b = 0, a = 1;
if (isNaN(args[0])) {
return { r, g, b, a };
}
r = args[0];
g = (typeof args[1] === 'number' && typeof args[2] === 'number') ? args[1] : args[0];
b = (typeof args[2] === 'number') ? args[2] : args[0];
if (typeof args[3] === 'number') {
a = args[3];
} else if (typeof args[2] === 'number') {
a = 1;
} else if (typeof args[1] === 'number') {
a = args[1];
} else {
a = 1;
}
r = Color.clampTo1(r);
g = Color.clampTo1(g);
b = Color.clampTo1(b);
a = Color.clampTo1(a);
return { r, g, b, a };
}
static rgbaFromString(args) {
let r = 0, g = 0, b = 0, a = 1;
let rest = 0;
if (typeof args[0] === 'string') {
rest = parseInt(args[0], 16);
} else {
rest = args[0];
}
if (isNaN(rest)) {
return { r, g, b, a };
}
if (args[0] > 256 * 256 * 256) {
a = rest % 256;
rest = Math.floor(rest / 256);
}
b = rest % 256; rest = Math.floor(rest / 256);
g = rest % 256; rest = Math.floor(rest / 256);
r = rest % 256;
r = Color.clampTo1(r);
g = Color.clampTo1(g);
b = Color.clampTo1(b);
a = Color.clampTo1(a);
return { r, g, b, a };
}
/**
* The value of colors' red component
* @return {Number}
*/
get r() { return this.x; }
set r(_r) { this.x = _r; }
/**
* The value of colors' green component
* @return {Number}
*/
get g() { return this.y; }
set g(_g) { this.y = _g; }
/**
* The value of colors' blue component
* @return {Number}
*/
get b() { return this.z; }
set b(_b) { this.z = _b; }
/**
* The value of colors' alpha component
* @return {Number}
*/
get a() { return this.w; }
set a(_a) { this.w = _a; }
/**
* The **new** color, constructed as `Color(this.r, this.g, this.b)`
* @return {Color} rgb
*/
get rgb() { return new Color(this.r, this.g, this.b); }
set rgb(_rgb) { this.xyz = _rgb; }
/**
* The **new** color, constructed as `Color(this.r, this.g, this.b, this.a)`
* @return {Color} rgb
*/
get rgba() { return new Color(this.r, this.g, this.b, this.a); }
set rgba(_rgba) { this.xyzw = _rgba; }
/**
* The value of colors' alpha component
* @return {Number}
*/
get opacity() { return this.a; }
/**
* Integer representation of the color (without alpha)
* @return {Number} color
*/
get hex() {
const scaled = this.scale(255).rounded;
return scaled.b + 256 * scaled.g + 256 * 256 * scaled.r;
}
/**
* Integer representation of the color (without alpha)
* @return {Number} color
*/
toHex() {
return this.hex;
}
/**
* Integer representation of the color (including alpha)
* @return {Number} color
*/
get hexA() {
return Math.round(255 * this.a) + 256 * this.toHex;
}
/**
* Integer representation of the color (including alpha)
* @return {Number} color
*/
toHexA() {
return this.hexA;
}
/**
* String representation of the color (without alpha)
* @return {String} color
*/
toString() {
const r = Math.round(255 * this.r);
return (r > 15 ? '' : '0') + this.hex;
}
/**
* String representation of the color (including alpha)
* @return {String} color
*/
toStringA() {
const r = Math.round(255 * this.r);
return (r > 15 ? '' : '0') + this.hexA;
}
}
module.exports = Color;