csx
Version:
Utility functions for TypeStyle
404 lines (403 loc) • 15.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var _a;
var formatting_1 = require("./utils/formatting");
var math_1 = require("./utils/math");
var RGB = 'rgb', HSL = 'hsl';
var converters = (_a = {},
_a[RGB + HSL] = RGBtoHSL,
_a[HSL + RGB] = HSLtoRGB,
_a);
/**
* Describe the ceiling for each color channel for each format
*/
var maxChannelValues = {
r: 255,
g: 255,
b: 255,
h: 360,
s: 1,
l: 1,
a: 1
};
/**
* Creates a color from a hex color code or named color.
* e.g. color('red') or color('#FF0000') or color('#F00'))
*/
function color(value) {
return parseHexCode(value) || parseColorFunction(value) || rgb(255, 0, 0);
}
exports.color = color;
/**
* Creates a color from hue, saturation, and lightness. Alpha is automatically set to 100%
* @param hue The hue of the color. This should be a number between 0-360.
* @param saturation The saturation of the color. This should be a number between 0-1 or a percentage string between 0%-100%.
* @param lightness The lightness of the color. This should be a number between 0-1 or a percentage string between 0%-100%.
* @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%. If not specified, this defaults to 1.
*/
function hsl(hue, saturation, lightness, alpha) {
return new ColorHelper(HSL, modDegrees(hue), formatting_1.ensurePercent(saturation), formatting_1.ensurePercent(lightness), (alpha === undefined ? 1 : formatting_1.ensurePercent(alpha)), alpha !== undefined /* hasAlpha*/);
}
exports.hsl = hsl;
/**
* Creates a color from hue, saturation, lightness, and alpha
* @param hue The hue of the color. This should be a number between 0-360.
* @param saturation The saturation of the color. This should be a number between 0-1 or a percentage string between 0%-100%.
* @param lightness The lightness of the color. This should be a number between 0-1 or a percentage string between 0%-100%.
* @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%.
*/
function hsla(hue, saturation, lightness, alpha) {
return new ColorHelper(HSL, modDegrees(hue), formatting_1.ensurePercent(saturation), formatting_1.ensurePercent(lightness), formatting_1.ensurePercent(alpha), true);
}
exports.hsla = hsla;
/**
* Creates a color form the red, blue, and green color space. Alpha is automatically set to 100%
* @param red The red channel of the color. This should be a number between 0-255.
* @param blue The blue channel of the color. This should be a number between 0-255.
* @param green The green channel of the color. This should be a number between 0-255.
* @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%. If not specified, this defaults to 1.
*/
function rgb(red, blue, green, alpha) {
return new ColorHelper(RGB, red, blue, green, (alpha === undefined ? 1 : formatting_1.ensurePercent(alpha)), alpha !== undefined /* hasAlpha*/);
}
exports.rgb = rgb;
/**
* Creates a color form the red, blue, green, and alpha in the color space
* @param red The red channel of the color. This should be a number between 0-255.
* @param blue The blue channel of the color. This should be a number between 0-255.
* @param green The green channel of the color. This should be a number between 0-255.
* @param alpha The alpha of the color. This should be a number between 0-1 or a percentage string between 0%-100%.
*/
function rgba(red, blue, green, alpha) {
return new ColorHelper(RGB, red, blue, green, formatting_1.ensurePercent(alpha), true);
}
exports.rgba = rgba;
function convertHelper(toFormat, helper, forceAlpha) {
var fromFormat = helper.f, r = helper.r, g = helper.g, b = helper.b, a = helper.a;
var newAlpha = forceAlpha === undefined ? helper.o : forceAlpha;
if (fromFormat !== toFormat) {
return converters[fromFormat + toFormat](r, g, b, a, newAlpha);
}
return forceAlpha === undefined ? helper : new ColorHelper(fromFormat, r, g, b, a, newAlpha);
}
/**
* A CSS Color. Includes utilities for converting between color types
*/
var ColorHelper = /** @class */ (function () {
function ColorHelper(format, r, g, b, a, hasAlpha) {
var self = this;
self.f = format;
self.o = hasAlpha;
var isHSL = format === HSL;
self.r = clampColor(isHSL ? 'h' : 'r', r);
self.g = clampColor(isHSL ? 's' : 'g', g);
self.b = clampColor(isHSL ? 'l' : 'b', b);
self.a = clampColor('a', a);
}
/**
* Converts the stored color into string form (which is used by Free Style)
*/
ColorHelper.prototype.toString = function () {
var _a = this, hasAlpha = _a.o, format = _a.f, r = _a.r, g = _a.g, b = _a.b, a = _a.a;
var fnName;
var params;
// find function name and resolve first three channels
if (format === RGB) {
fnName = hasAlpha ? 'rgba' : RGB;
params = [math_1.round(r), math_1.round(g), math_1.round(b)];
}
else if (format === HSL) {
fnName = hasAlpha ? 'hsla' : HSL;
params = [math_1.round(r), formatting_1.formatPercent(math_1.roundFloat(g, 100)), formatting_1.formatPercent(math_1.roundFloat(b, 100))];
}
else {
throw new Error('Invalid color format');
}
// add alpha channel if needed
if (hasAlpha) {
params.push(formatting_1.formatFloat(math_1.roundFloat(a, 100000)));
}
// return as a string
return formatting_1.cssFunction(fnName, params);
};
/**
* Converts to hex rgb(255, 255, 255) to #FFFFFF
*/
ColorHelper.prototype.toHexString = function () {
var color = convertHelper(RGB, this);
return '#' + (toHex(color.r) + toHex(color.g) + toHex(color.b)).toUpperCase();
};
/**
* Converts to the Hue, Saturation, Lightness color space
*/
ColorHelper.prototype.toHSL = function () {
return convertHelper(HSL, this, false);
};
/**
* Converts to the Hue, Saturation, Lightness color space and adds an alpha channel
*/
ColorHelper.prototype.toHSLA = function () {
return convertHelper(HSL, this, true);
};
/**
* Converts to the Red, Green, Blue color space
*/
ColorHelper.prototype.toRGB = function () {
return convertHelper(RGB, this, false);
};
/**
* Converts to the Red, Green, Blue color space and adds an alpha channel
*/
ColorHelper.prototype.toRGBA = function () {
return convertHelper(RGB, this, true);
};
ColorHelper.prototype.red = function () {
var _ = this;
return (_.f === RGB ? _ : _.toRGB()).r;
};
ColorHelper.prototype.green = function () {
var _ = this;
return (_.f === RGB ? _ : _.toRGB()).g;
};
ColorHelper.prototype.blue = function () {
var _ = this;
return (_.f === RGB ? _ : _.toRGB()).b;
};
ColorHelper.prototype.hue = function () {
var _ = this;
return (_.f === HSL ? _ : _.toHSL()).r;
};
ColorHelper.prototype.saturation = function () {
var _ = this;
return (_.f === HSL ? _ : _.toHSL()).g;
};
ColorHelper.prototype.lightness = function () {
var _ = this;
return (_.f === HSL ? _ : _.toHSL()).b;
};
ColorHelper.prototype.alpha = function () {
return this.a;
};
ColorHelper.prototype.opacity = function () {
return this.a;
};
ColorHelper.prototype.invert = function () {
var _ = this;
var color2 = convertHelper(RGB, _);
return convertHelper(_.f, new ColorHelper(RGB, 255 - color2.r, 255 - color2.g, 255 - color2.b, _.a, _.o));
};
ColorHelper.prototype.lighten = function (percent, relative) {
var _ = this;
var color2 = convertHelper(HSL, _);
var max = maxChannelValues.l;
var l = color2.b + (relative ? max - color2.b : max) * formatting_1.ensurePercent(percent);
return convertHelper(_.f, new ColorHelper(HSL, color2.r, color2.g, l, _.a, _.o));
};
ColorHelper.prototype.darken = function (percent, relative) {
var _ = this;
var color2 = convertHelper(HSL, _);
var l = color2.b - (relative ? color2.b : maxChannelValues.l) * formatting_1.ensurePercent(percent);
return convertHelper(_.f, new ColorHelper(HSL, color2.r, color2.g, l, _.a, _.o));
};
ColorHelper.prototype.saturate = function (percent, relative) {
var _ = this;
var color2 = convertHelper(HSL, _);
var max = maxChannelValues.s;
var s = color2.g + (relative ? max - color2.g : max) * formatting_1.ensurePercent(percent);
return convertHelper(_.f, new ColorHelper(HSL, color2.r, s, color2.b, _.a, _.o));
};
ColorHelper.prototype.desaturate = function (percent, relative) {
var _ = this;
var color2 = convertHelper(HSL, _);
var max = maxChannelValues.s;
var s = color2.g - (relative ? color2.g : max) * formatting_1.ensurePercent(percent);
return convertHelper(_.f, new ColorHelper(HSL, color2.r, s, color2.b, _.a, _.o));
};
ColorHelper.prototype.grayscale = function () {
return this.desaturate(1);
};
ColorHelper.prototype.fade = function (percent) {
var _ = this;
var a = clampColor('a', formatting_1.ensurePercent(percent));
return convertHelper(_.f, new ColorHelper(_.f, _.r, _.g, _.b, a, true));
};
ColorHelper.prototype.fadeOut = function (percent, relative) {
var _ = this;
var max = 1;
var a = clampColor('a', _.a - (relative ? _.a : max) * formatting_1.ensurePercent(percent));
return convertHelper(_.f, new ColorHelper(_.f, _.r, _.g, _.b, a, true));
};
ColorHelper.prototype.fadeIn = function (percent, relative) {
var _ = this;
var max = 1;
var a = clampColor('a', _.a + (relative ? _.a : max) * formatting_1.ensurePercent(percent));
return convertHelper(_.f, new ColorHelper(_.f, _.r, _.g, _.b, a, true));
};
ColorHelper.prototype.mix = function (mixin, weight) {
var _ = this;
var color2 = ensureColor(mixin);
var g = convertHelper(RGB, _);
var b = convertHelper(RGB, color2);
var p = weight === undefined ? 0.5 : weight;
var w = 2 * p - 1;
var a = Math.abs(g.a - b.a);
var w1 = ((w * a === -1 ? w : (w + a) / (1 + w * a)) + 1) / 2.0;
var w2 = 1 - w1;
var helper = new ColorHelper(RGB, math_1.round(g.r * w1 + b.r * w2), math_1.round(g.g * w1 + b.g * w2), math_1.round(g.b * w1 + b.b * w2), g.a * p + b.a * (1 - p), _.o || color2.o);
return convertHelper(this.f, helper);
};
ColorHelper.prototype.tint = function (weight) {
return rgb(255, 255, 255).mix(this, weight);
};
ColorHelper.prototype.shade = function (weight) {
return rgb(0, 0, 0).mix(this, weight);
};
ColorHelper.prototype.spin = function (degrees) {
var _ = this;
var color2 = convertHelper(HSL, _);
return convertHelper(_.f, new ColorHelper(HSL, modDegrees(color2.r + degrees), color2.g, color2.b, _.a, _.o));
};
return ColorHelper;
}());
exports.ColorHelper = ColorHelper;
function toHex(n) {
var i = math_1.round(n);
return (i < 16 ? '0' : '') + i.toString(16);
}
function modDegrees(n) {
// note: maybe there is a way to simplify this
return ((n < 0 ? 360 : 0) + n % 360) % 360;
}
function RGBtoHSL(r, g, b, a, hasAlpha) {
var newR = r / 255;
var newG = g / 255;
var newB = b / 255;
var min = Math.min(newR, newG, newB);
var max = Math.max(newR, newG, newB);
var l = (min + max) / 2;
var delta = max - min;
var h;
if (max === min) {
h = 0;
}
else if (newR === max) {
h = (newG - newB) / delta;
}
else if (newG === max) {
h = 2 + (newB - newR) / delta;
}
else if (newB === max) {
h = 4 + (newR - newG) / delta;
}
else {
h = 0;
}
h = Math.min(h * 60, 360);
if (h < 0) {
h += 360;
}
var s;
if (max === min) {
s = 0;
}
else if (l <= 0.5) {
s = delta / (max + min);
}
else {
s = delta / (2 - max - min);
}
return new ColorHelper(HSL, h, s, l, a, hasAlpha);
}
function HSLtoRGB(r, g, b, a, hasAlpha) {
var newH = r / 360;
var newS = g;
var newL = b;
if (newS === 0) {
var val = newL * 255;
return new ColorHelper(RGB, val, val, val, a, hasAlpha);
}
var t2 = newL < 0.5 ? newL * (1 + newS) : newL + newS - newL * newS;
var t1 = 2 * newL - t2;
var newR = 0, newG = 0, newB = 0;
for (var i = 0; i < 3; i++) {
var t3 = newH + 1 / 3 * -(i - 1);
if (t3 < 0) {
t3++;
}
if (t3 > 1) {
t3--;
}
var val = void 0;
if (6 * t3 < 1) {
val = t1 + (t2 - t1) * 6 * t3;
}
else if (2 * t3 < 1) {
val = t2;
}
else if (3 * t3 < 2) {
val = t1 + (t2 - t1) * (2 / 3 - t3) * 6;
}
else {
val = t1;
}
val *= 255;
// manually set variables instead of using an array
if (i === 0) {
newR = val;
}
else if (i === 1) {
newG = val;
}
else {
newB = val;
}
}
return new ColorHelper(RGB, newR, newG, newB, a, hasAlpha);
}
function clampColor(channel, value) {
var min = 0;
var max = maxChannelValues[channel];
return value < min ? min : value > max ? max : value;
}
function ensureColor(c) {
return c instanceof ColorHelper ? c : color(c);
}
function parseHexCode(stringValue) {
var match = stringValue.match(/#(([a-f0-9]{6})|([a-f0-9]{3}))$/i);
if (!match) {
return undefined;
}
var hex = match[1];
var hexColor = parseInt(hex.length === 3 ? hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2] : hex, 16);
var r = (hexColor >> 16) & 0xff;
var b = (hexColor >> 8) & 0xff;
var g = hexColor & 0xff;
return new ColorHelper(RGB, r, b, g, 1, false);
}
function parseColorFunction(colorString) {
var cssParts = formatting_1.parseCSSFunction(colorString);
if (!cssParts || !(cssParts.length === 4 || cssParts.length === 5)) {
return undefined;
}
var fn = cssParts[0];
var isRGBA = fn === 'rgba';
var isHSLA = fn === 'hsla';
var isRGB = fn === RGB;
var isHSL = fn === HSL;
var hasAlpha = isHSLA || isRGBA;
var type;
if (isRGB || isRGBA) {
type = RGB;
}
else if (isHSL || isHSLA) {
type = HSL;
}
else {
throw new Error('unsupported color string');
}
var r = formatting_1.toFloat(cssParts[1]);
var g = isRGB || isRGBA ? formatting_1.toFloat(cssParts[2]) : formatting_1.ensurePercent(cssParts[2]);
var b = isRGB || isRGBA ? formatting_1.toFloat(cssParts[3]) : formatting_1.ensurePercent(cssParts[3]);
var a = hasAlpha ? formatting_1.toFloat(cssParts[4]) : 1;
return new ColorHelper(type, r, g, b, a, hasAlpha);
}