|
|
- /* MIT license */
- var colorNames = require('color-name');
- var swizzle = require('simple-swizzle');
-
- var reverseNames = {};
-
- // create a list of reverse color names
- for (var name in colorNames) {
- if (colorNames.hasOwnProperty(name)) {
- reverseNames[colorNames[name]] = name;
- }
- }
-
- var cs = module.exports = {
- to: {},
- get: {}
- };
-
- cs.get = function (string) {
- var prefix = string.substring(0, 3).toLowerCase();
- var val;
- var model;
- switch (prefix) {
- case 'hsl':
- val = cs.get.hsl(string);
- model = 'hsl';
- break;
- case 'hwb':
- val = cs.get.hwb(string);
- model = 'hwb';
- break;
- default:
- val = cs.get.rgb(string);
- model = 'rgb';
- break;
- }
-
- if (!val) {
- return null;
- }
-
- return {model: model, value: val};
- };
-
- cs.get.rgb = function (string) {
- if (!string) {
- return null;
- }
-
- var abbr = /^#([a-f0-9]{3,4})$/i;
- var hex = /^#([a-f0-9]{6})([a-f0-9]{2})?$/i;
- var rgba = /^rgba?\(\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*,\s*([+-]?\d+)\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
- var per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*,\s*([+-]?[\d\.]+)\%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
- var keyword = /(\D+)/;
-
- var rgb = [0, 0, 0, 1];
- var match;
- var i;
- var hexAlpha;
-
- if (match = string.match(hex)) {
- hexAlpha = match[2];
- match = match[1];
-
- for (i = 0; i < 3; i++) {
- // https://jsperf.com/slice-vs-substr-vs-substring-methods-long-string/19
- var i2 = i * 2;
- rgb[i] = parseInt(match.slice(i2, i2 + 2), 16);
- }
-
- if (hexAlpha) {
- rgb[3] = Math.round((parseInt(hexAlpha, 16) / 255) * 100) / 100;
- }
- } else if (match = string.match(abbr)) {
- match = match[1];
- hexAlpha = match[3];
-
- for (i = 0; i < 3; i++) {
- rgb[i] = parseInt(match[i] + match[i], 16);
- }
-
- if (hexAlpha) {
- rgb[3] = Math.round((parseInt(hexAlpha + hexAlpha, 16) / 255) * 100) / 100;
- }
- } else if (match = string.match(rgba)) {
- for (i = 0; i < 3; i++) {
- rgb[i] = parseInt(match[i + 1], 0);
- }
-
- if (match[4]) {
- rgb[3] = parseFloat(match[4]);
- }
- } else if (match = string.match(per)) {
- for (i = 0; i < 3; i++) {
- rgb[i] = Math.round(parseFloat(match[i + 1]) * 2.55);
- }
-
- if (match[4]) {
- rgb[3] = parseFloat(match[4]);
- }
- } else if (match = string.match(keyword)) {
- if (match[1] === 'transparent') {
- return [0, 0, 0, 0];
- }
-
- rgb = colorNames[match[1]];
-
- if (!rgb) {
- return null;
- }
-
- rgb[3] = 1;
-
- return rgb;
- } else {
- return null;
- }
-
- for (i = 0; i < 3; i++) {
- rgb[i] = clamp(rgb[i], 0, 255);
- }
- rgb[3] = clamp(rgb[3], 0, 1);
-
- return rgb;
- };
-
- cs.get.hsl = function (string) {
- if (!string) {
- return null;
- }
-
- var hsl = /^hsla?\(\s*([+-]?(?:\d*\.)?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
- var match = string.match(hsl);
-
- if (match) {
- var alpha = parseFloat(match[4]);
- var h = (parseFloat(match[1]) + 360) % 360;
- var s = clamp(parseFloat(match[2]), 0, 100);
- var l = clamp(parseFloat(match[3]), 0, 100);
- var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
-
- return [h, s, l, a];
- }
-
- return null;
- };
-
- cs.get.hwb = function (string) {
- if (!string) {
- return null;
- }
-
- var hwb = /^hwb\(\s*([+-]?\d*[\.]?\d+)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?[\d\.]+)\s*)?\)$/;
- var match = string.match(hwb);
-
- if (match) {
- var alpha = parseFloat(match[4]);
- var h = ((parseFloat(match[1]) % 360) + 360) % 360;
- var w = clamp(parseFloat(match[2]), 0, 100);
- var b = clamp(parseFloat(match[3]), 0, 100);
- var a = clamp(isNaN(alpha) ? 1 : alpha, 0, 1);
- return [h, w, b, a];
- }
-
- return null;
- };
-
- cs.to.hex = function () {
- var rgba = swizzle(arguments);
-
- return (
- '#' +
- hexDouble(rgba[0]) +
- hexDouble(rgba[1]) +
- hexDouble(rgba[2]) +
- (rgba[3] < 1
- ? (hexDouble(Math.round(rgba[3] * 255)))
- : '')
- );
- };
-
- cs.to.rgb = function () {
- var rgba = swizzle(arguments);
-
- return rgba.length < 4 || rgba[3] === 1
- ? 'rgb(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ')'
- : 'rgba(' + Math.round(rgba[0]) + ', ' + Math.round(rgba[1]) + ', ' + Math.round(rgba[2]) + ', ' + rgba[3] + ')';
- };
-
- cs.to.rgb.percent = function () {
- var rgba = swizzle(arguments);
-
- var r = Math.round(rgba[0] / 255 * 100);
- var g = Math.round(rgba[1] / 255 * 100);
- var b = Math.round(rgba[2] / 255 * 100);
-
- return rgba.length < 4 || rgba[3] === 1
- ? 'rgb(' + r + '%, ' + g + '%, ' + b + '%)'
- : 'rgba(' + r + '%, ' + g + '%, ' + b + '%, ' + rgba[3] + ')';
- };
-
- cs.to.hsl = function () {
- var hsla = swizzle(arguments);
- return hsla.length < 4 || hsla[3] === 1
- ? 'hsl(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%)'
- : 'hsla(' + hsla[0] + ', ' + hsla[1] + '%, ' + hsla[2] + '%, ' + hsla[3] + ')';
- };
-
- // hwb is a bit different than rgb(a) & hsl(a) since there is no alpha specific syntax
- // (hwb have alpha optional & 1 is default value)
- cs.to.hwb = function () {
- var hwba = swizzle(arguments);
-
- var a = '';
- if (hwba.length >= 4 && hwba[3] !== 1) {
- a = ', ' + hwba[3];
- }
-
- return 'hwb(' + hwba[0] + ', ' + hwba[1] + '%, ' + hwba[2] + '%' + a + ')';
- };
-
- cs.to.keyword = function (rgb) {
- return reverseNames[rgb.slice(0, 3)];
- };
-
- // helpers
- function clamp(num, min, max) {
- return Math.min(Math.max(min, num), max);
- }
-
- function hexDouble(num) {
- var str = num.toString(16).toUpperCase();
- return (str.length < 2) ? '0' + str : str;
- }
|