You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
4.4 KiB
277 lines
4.4 KiB
|
|
/*! |
|
* Stylus - HSLA |
|
* Copyright (c) Automattic <developer.wordpress.com> |
|
* MIT Licensed |
|
*/ |
|
|
|
/** |
|
* Module dependencies. |
|
*/ |
|
|
|
var Node = require('./node') |
|
, nodes = require('./'); |
|
|
|
/** |
|
* Initialize a new `HSLA` with the given h,s,l,a component values. |
|
* |
|
* @param {Number} h |
|
* @param {Number} s |
|
* @param {Number} l |
|
* @param {Number} a |
|
* @api public |
|
*/ |
|
|
|
var HSLA = exports = module.exports = function HSLA(h,s,l,a){ |
|
Node.call(this); |
|
this.h = clampDegrees(h); |
|
this.s = clampPercentage(s); |
|
this.l = clampPercentage(l); |
|
this.a = clampAlpha(a); |
|
this.hsla = this; |
|
}; |
|
|
|
/** |
|
* Inherit from `Node.prototype`. |
|
*/ |
|
|
|
HSLA.prototype.__proto__ = Node.prototype; |
|
|
|
/** |
|
* Return hsla(n,n,n,n). |
|
* |
|
* @return {String} |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.toString = function(){ |
|
return 'hsla(' |
|
+ this.h + ',' |
|
+ this.s.toFixed(0) + '%,' |
|
+ this.l.toFixed(0) + '%,' |
|
+ this.a + ')'; |
|
}; |
|
|
|
/** |
|
* Return a clone of this node. |
|
* |
|
* @return {Node} |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.clone = function(parent){ |
|
var clone = new HSLA( |
|
this.h |
|
, this.s |
|
, this.l |
|
, this.a); |
|
clone.lineno = this.lineno; |
|
clone.column = this.column; |
|
clone.filename = this.filename; |
|
return clone; |
|
}; |
|
|
|
/** |
|
* Return a JSON representation of this node. |
|
* |
|
* @return {Object} |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.toJSON = function(){ |
|
return { |
|
__type: 'HSLA', |
|
h: this.h, |
|
s: this.s, |
|
l: this.l, |
|
a: this.a, |
|
lineno: this.lineno, |
|
column: this.column, |
|
filename: this.filename |
|
}; |
|
}; |
|
|
|
/** |
|
* Return rgba `RGBA` representation. |
|
* |
|
* @return {RGBA} |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.__defineGetter__('rgba', function(){ |
|
return nodes.RGBA.fromHSLA(this); |
|
}); |
|
|
|
/** |
|
* Return hash. |
|
* |
|
* @return {String} |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.__defineGetter__('hash', function(){ |
|
return this.rgba.toString(); |
|
}); |
|
|
|
/** |
|
* Add h,s,l to the current component values. |
|
* |
|
* @param {Number} h |
|
* @param {Number} s |
|
* @param {Number} l |
|
* @return {HSLA} new node |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.add = function(h,s,l){ |
|
return new HSLA( |
|
this.h + h |
|
, this.s + s |
|
, this.l + l |
|
, this.a); |
|
}; |
|
|
|
/** |
|
* Subtract h,s,l from the current component values. |
|
* |
|
* @param {Number} h |
|
* @param {Number} s |
|
* @param {Number} l |
|
* @return {HSLA} new node |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.sub = function(h,s,l){ |
|
return this.add(-h, -s, -l); |
|
}; |
|
|
|
/** |
|
* Operate on `right` with the given `op`. |
|
* |
|
* @param {String} op |
|
* @param {Node} right |
|
* @return {Node} |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.operate = function(op, right){ |
|
switch (op) { |
|
case '==': |
|
case '!=': |
|
case '<=': |
|
case '>=': |
|
case '<': |
|
case '>': |
|
case 'is a': |
|
case '||': |
|
case '&&': |
|
return this.rgba.operate(op, right); |
|
default: |
|
return this.rgba.operate(op, right).hsla; |
|
} |
|
}; |
|
|
|
/** |
|
* Return `HSLA` representation of the given `color`. |
|
* |
|
* @param {RGBA} color |
|
* @return {HSLA} |
|
* @api public |
|
*/ |
|
|
|
exports.fromRGBA = function(rgba){ |
|
var r = rgba.r / 255 |
|
, g = rgba.g / 255 |
|
, b = rgba.b / 255 |
|
, a = rgba.a; |
|
|
|
var min = Math.min(r,g,b) |
|
, max = Math.max(r,g,b) |
|
, l = (max + min) / 2 |
|
, d = max - min |
|
, h, s; |
|
|
|
switch (max) { |
|
case min: h = 0; break; |
|
case r: h = 60 * (g-b) / d; break; |
|
case g: h = 60 * (b-r) / d + 120; break; |
|
case b: h = 60 * (r-g) / d + 240; break; |
|
} |
|
|
|
if (max == min) { |
|
s = 0; |
|
} else if (l < .5) { |
|
s = d / (2 * l); |
|
} else { |
|
s = d / (2 - 2 * l); |
|
} |
|
|
|
h %= 360; |
|
s *= 100; |
|
l *= 100; |
|
|
|
return new HSLA(h,s,l,a); |
|
}; |
|
|
|
/** |
|
* Adjust lightness by `percent`. |
|
* |
|
* @param {Number} percent |
|
* @return {HSLA} for chaining |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.adjustLightness = function(percent){ |
|
this.l = clampPercentage(this.l + this.l * (percent / 100)); |
|
return this; |
|
}; |
|
|
|
/** |
|
* Adjust hue by `deg`. |
|
* |
|
* @param {Number} deg |
|
* @return {HSLA} for chaining |
|
* @api public |
|
*/ |
|
|
|
HSLA.prototype.adjustHue = function(deg){ |
|
this.h = clampDegrees(this.h + deg); |
|
return this; |
|
}; |
|
|
|
/** |
|
* Clamp degree `n` >= 0 and <= 360. |
|
* |
|
* @param {Number} n |
|
* @return {Number} |
|
* @api private |
|
*/ |
|
|
|
function clampDegrees(n) { |
|
n = n % 360; |
|
return n >= 0 ? n : 360 + n; |
|
} |
|
|
|
/** |
|
* Clamp percentage `n` >= 0 and <= 100. |
|
* |
|
* @param {Number} n |
|
* @return {Number} |
|
* @api private |
|
*/ |
|
|
|
function clampPercentage(n) { |
|
return Math.max(0, Math.min(n, 100)); |
|
} |
|
|
|
/** |
|
* Clamp alpha `n` >= 0 and <= 1. |
|
* |
|
* @param {Number} n |
|
* @return {Number} |
|
* @api private |
|
*/ |
|
|
|
function clampAlpha(n) { |
|
return Math.max(0, Math.min(n, 1)); |
|
}
|
|
|