mirror of https://github.com/keeweb/keeweb.git
134 lines
3.6 KiB
JavaScript
134 lines
3.6 KiB
JavaScript
import { Colors } from 'const/colors';
|
|
|
|
const KnownColors = {};
|
|
|
|
const Color = function (arg) {
|
|
const rgbaMatch = /^rgba?\((\d+),\s*(\d+),\s*(\d+)(,\s*([\d.]+))?\)$/.exec(arg);
|
|
if (rgbaMatch) {
|
|
this.r = +rgbaMatch[1];
|
|
this.g = +rgbaMatch[2];
|
|
this.b = +rgbaMatch[2];
|
|
this.a = rgbaMatch[4] ? rgbaMatch[4] : 1;
|
|
this.setHsl();
|
|
} else {
|
|
const hexMatch = /^#?([0-9a-f]{3,6})$/i.exec(arg);
|
|
if (hexMatch) {
|
|
const digits = hexMatch[1];
|
|
const len = digits.length === 3 ? 1 : 2;
|
|
this.r = parseInt(digits.substr(0, len), 16);
|
|
this.g = parseInt(digits.substr(len, len), 16);
|
|
this.b = parseInt(digits.substr(len * 2, len), 16);
|
|
this.a = 1;
|
|
this.setHsl();
|
|
} else if (arg instanceof Color) {
|
|
this.r = arg.r;
|
|
this.g = arg.g;
|
|
this.b = arg.b;
|
|
this.h = arg.h;
|
|
this.s = arg.s;
|
|
this.l = arg.l;
|
|
this.a = arg.a;
|
|
} else {
|
|
this.r = this.g = this.b = this.h = this.s = this.l = 0;
|
|
this.a = 1;
|
|
}
|
|
}
|
|
};
|
|
|
|
Color.prototype.setHsl = function () {
|
|
const r = this.r / 255;
|
|
const g = this.g / 255;
|
|
const b = this.b / 255;
|
|
|
|
const max = Math.max(r, g, b);
|
|
const min = Math.min(r, g, b);
|
|
let h;
|
|
let s;
|
|
const l = (max + min) / 2;
|
|
|
|
if (max === min) {
|
|
h = s = 0; // achromatic
|
|
} else {
|
|
const d = max - min;
|
|
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
|
|
switch (max) {
|
|
case r:
|
|
h = (g - b) / d + (g < b ? 6 : 0);
|
|
break;
|
|
case g:
|
|
h = (b - r) / d + 2;
|
|
break;
|
|
case b:
|
|
h = (r - g) / d + 4;
|
|
break;
|
|
}
|
|
h /= 6;
|
|
}
|
|
|
|
this.h = h;
|
|
this.s = s;
|
|
this.l = l;
|
|
};
|
|
|
|
Color.prototype.toHex = function () {
|
|
return '#' + hex(this.r) + hex(this.g) + hex(this.b);
|
|
};
|
|
|
|
Color.prototype.toRgba = function () {
|
|
return `rgba(${Math.round(this.r)},${Math.round(this.g)},${Math.round(this.b)},${this.a})`;
|
|
};
|
|
|
|
Color.prototype.toHsla = function () {
|
|
return `hsla(${Math.round(this.h * 100)},${Math.round(this.s * 100)}%,${Math.round(
|
|
this.l * 100
|
|
)}%,${this.a})`;
|
|
};
|
|
|
|
Color.prototype.distanceTo = function (color) {
|
|
return Math.abs(this.h - color.h);
|
|
};
|
|
|
|
Color.prototype.mix = function (another, weight) {
|
|
const res = new Color(this);
|
|
const anotherWeight = 1 - weight;
|
|
res.r = this.r * weight + another.r * anotherWeight;
|
|
res.g = this.g * weight + another.g * anotherWeight;
|
|
res.b = this.b * weight + another.b * anotherWeight;
|
|
res.a = this.a * weight + another.a * anotherWeight;
|
|
return res;
|
|
};
|
|
|
|
Color.getNearest = function (colorStr) {
|
|
const color = new Color(colorStr);
|
|
if (!color.s) {
|
|
return null;
|
|
}
|
|
let selected = null,
|
|
minDistance = Number.MAX_VALUE;
|
|
for (const [name, col] of Object.entries(KnownColors)) {
|
|
const distance = color.distanceTo(col);
|
|
if (distance < minDistance) {
|
|
minDistance = distance;
|
|
selected = name;
|
|
}
|
|
}
|
|
return selected;
|
|
};
|
|
|
|
Color.getKnownBgColor = function (knownColor) {
|
|
return Colors.BgColors[knownColor] ? '#' + Colors.BgColors[knownColor] : undefined;
|
|
};
|
|
|
|
for (const [name, val] of Object.entries(Colors.ColorsValues)) {
|
|
KnownColors[name] = new Color(val);
|
|
}
|
|
|
|
Color.black = new Color('#000');
|
|
|
|
function hex(num) {
|
|
const str = (num || 0).toString(16);
|
|
return str.length < 2 ? '0' + str : str;
|
|
}
|
|
|
|
export { Color };
|