Initial commit of akmon project

This commit is contained in:
2026-01-20 08:04:15 +08:00
commit 77a2bab985
1309 changed files with 343305 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
## 0.0.62025-04-21
- feat: 兼容uniappx 鸿蒙next
## 0.0.52024-09-30
- fix: 修复 vue2类型问题
## 0.0.42024-06-25
- chore: 更改为非`utssdk`结构
## 0.0.32024-06-19
- feat: 支持`uniapp`
## 0.0.22024-03-30
- fix: 修复 因equals导致web可能报错
## 0.0.12024-03-12
- init

View File

@@ -0,0 +1,680 @@
// @ts-nocheck
import { numberInputToObject, rgbaToHex, rgbToHex, rgbToHsl, rgbToHsv } from './conversion';
import { names } from './css-color-names';
import { inputToRGB } from './format-input';
import { HSL, HSLA, HSV, HSVA, HSBA, RGB, RGBA, RGBAString, LColorInfo, LColorFormats, LColorOptions, LColorInput } from '../utssdk/interface.uts';
import { bound01, boundAlpha, clamp01, toBoolean, isNumber } from './util';
export class TinyColor {
r : number;
g : number;
b : number;
a : number;
/** 用于创建 limeColor 实例的格式 */
format ?: LColorFormats;
/** 传递给构造函数以创建 limeColor 实例的输入 */
originalInput : LColorInput;
/** 颜色已被成功解析 */
isValid : boolean;
gradientType ?: string;
/** rounded alpha */
roundA : number;
// #ifdef APP
reversedNames : Map<string, string>;
// #endif
constructor(color : LColorInput = '', opts : LColorOptions = {} as LColorOptions) {
let _color : any = color
// if(color instanceof TinyColor){
// return color as TinyColor
// }
if (isNumber(color)) {
_color = numberInputToObject(color as number);
}
this.originalInput = _color;
const rgb = inputToRGB(_color);
this.r = rgb.r;
this.g = rgb.g;
this.b = rgb.b;
this.a = rgb.a;
this.roundA = Math.round(100 * this.a) / 100;
this.format = opts.format ?? rgb.format;
this.gradientType = opts.gradientType;
// 不要让范围在 [0,255] 中的值返回成 [0,1]。
// 这里可能会失去一些精度,但可以解决原来
// .5 被解释为总数的半数而不是1的一半的问题
// 如果本来应该是128那么这个已经在 inputToRgb 中处理过了 if (this.r < 1) {
if (this.r < 1) {
this.r = Math.round(this.r);
}
if (this.g < 1) {
this.g = Math.round(this.g);
}
if (this.b < 1) {
this.b = Math.round(this.b);
}
this.isValid = rgb.ok ?? false;
// #ifdef APP
this.reversedNames = new Map<string, string>()
names.forEach((value : string, key : string) => {
this.reversedNames.set(value, key)
})
// #endif
}
/**
* 判断当前颜色是否为暗色。
* @returns 一个布尔值,表示当前颜色是否为暗色。
*/
isDark() : boolean {
return this.getBrightness() < 128;
}
/**
* 判断当前颜色是否为亮色。
* @returns 一个布尔值,表示当前颜色是否为亮色。
*/
isLight() : boolean {
return !this.isDark();
}
/**
* 计算当前颜色的亮度值。
* 亮度值是根据 RGB 颜色空间中的红、绿、蓝三个通道的值计算得出的,计算公式为:(r * 299 + g * 587 + b * 114) / 1000。
* @returns 返回颜色的感知亮度范围从0-255。
*/
getBrightness() : number {
// http://www.w3.org/TR/AERT#color-contrast
const rgb = this.toRgb();
return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
}
/**
* 计算当前颜色的相对亮度值。
* 相对亮度值是根据 RGB 颜色空间中的红、绿、蓝三个通道的值计算得出的计算公式为0.2126 * R + 0.7152 * G + 0.0722 * B。
* @returns 返回颜色的感知亮度范围从0-1。
*/
getLuminance() : number {
// http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef
const rgb = this.toRgb();
let R : number;
let G : number;
let B : number;
const RsRGB : number = rgb.r / 255;
const GsRGB : number = rgb.g / 255;
const BsRGB : number = rgb.b / 255;
if (RsRGB <= 0.03928) {
R = RsRGB / 12.92;
} else {
// eslint-disable-next-line prefer-exponentiation-operator
R = Math.pow((RsRGB + 0.055) / 1.055, 2.4);
}
if (GsRGB <= 0.03928) {
G = GsRGB / 12.92;
} else {
// eslint-disable-next-line prefer-exponentiation-operator
G = Math.pow((GsRGB + 0.055) / 1.055, 2.4);
}
if (BsRGB <= 0.03928) {
B = BsRGB / 12.92;
} else {
// eslint-disable-next-line prefer-exponentiation-operator
B = Math.pow((BsRGB + 0.055) / 1.055, 2.4);
}
return 0.2126 * R + 0.7152 * G + 0.0722 * B;
}
/**
* 获取当前颜色的透明度值。
* 透明度值的范围是 0 到 1其中 0 表示完全透明1 表示完全不透明。
* @returns 一个数字,表示当前颜色的透明度值。
*/
getAlpha() : number {
return this.a;
}
/**
* 设置当前颜色的透明度值。
* @param alpha - 要设置的透明度值。透明度值的范围是 0 到 1其中 0 表示完全透明1 表示完全不透明。
* @returns 一个 `TinyColor` 对象,表示设置透明度后的颜色。
*/
setAlpha(alpha ?: string) : TinyColor
setAlpha(alpha ?: number) : TinyColor
setAlpha(alpha ?: any) : TinyColor {
this.a = boundAlpha(alpha);
this.roundA = Math.round(100 * this.a) / 100;
return this;
}
/**
* 判断当前颜色是否为单色。
* 单色是指颜色的饱和度S为 0 的颜色这些颜色只有明度L变化没有颜色变化。
* @returns 一个布尔值,表示当前颜色是否为单色。
*/
isMonochrome() : boolean {
const { s } = this.toHsl();
return s == 0;
}
/**
* 将当前颜色转换为 HSV色相、饱和度、亮度颜色空间。
* @returns 一个对象,包含四个属性:`h`(色相)、`s`(饱和度)、`v`(亮度)和 `a`(透明度)。
*/
toHsv() : HSVA {
const hsv = rgbToHsv(this.r, this.g, this.b);
return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this.a } as HSVA;
}
/**
* 将当前颜色转换为 HSV色相、饱和度、亮度颜色空间的字符串表示。
* @returns 一个字符串,表示当前颜色的 HSV 或 HSVA 格式 hsva(xxx, xxx, xxx, xx)。
*/
toHsvString() : string {
const hsv = rgbToHsv(this.r, this.g, this.b);
const h = Math.round(hsv.h * 360);
const s = Math.round(hsv.s * 100);
const v = Math.round(hsv.v * 100);
return this.a == 1 ? `hsv(${h}, ${s}%, ${v}%)` : `hsva(${h}, ${s}%, ${v}%, ${this.roundA})`;
}
/**
* 将当前颜色对象转换为HSBA颜色空间,即Hue色相、Saturation饱和度、Brightness亮度和Alpha透明度
* @returns {HSBA} 返回一个HSBA对象表示当前颜色对象在HSBA颜色空间中的值
*/
toHsb() : HSBA {
const hsv = rgbToHsv(this.r, this.g, this.b);
return { h: hsv.h * 360, s: hsv.s, b: hsv.v, a: this.a } as HSBA;
}
/**
* 将当前颜色对象转换为CSS风格的HSB或HSVA字符串
* @returns {string} 返回一个CSS风格的HSB或HSVA字符串表示当前颜色对象的颜色值
*/
toHsbString() : string {
const hsb = this.toHsb();
const h = Math.round(hsb.h);
const s = Math.round(hsb.s * 100);
const b = Math.round(hsb.b * 100);
return this.a == 1
? `hsb(${h}, ${s}%, ${b}%)`
: `hsva(${h}, ${s}%, ${b}%, ${this.roundA})`;
}
/**
* 将当前颜色转换为 HSL色相、饱和度、明度颜色空间。
* @returns 一个对象,包含四个属性:`h`(色相)、`s`(饱和度)、`l`(明度)和 `a`(透明度)。
*/
toHsl() : HSLA {
const hsl = rgbToHsl(this.r, this.g, this.b);
return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this.a } as HSLA;
}
/**
* 将当前颜色转换为 HSL色相、饱和度、明度颜色空间的字符串表示。
* @returns 一个字符串,表示当前颜色的 HSL 或 HSLA 格式 hsla(xxx, xxx, xxx, xx)。
*/
toHslString() : string {
const hsl = rgbToHsl(this.r, this.g, this.b);
const h = Math.round(hsl.h * 360);
const s = Math.round(hsl.s * 100);
const l = Math.round(hsl.l * 100);
return this.a == 1 ? `hsl(${h}, ${s}%, ${l}%)` : `hsla(${h}, ${s}%, ${l}%, ${this.roundA})`;
}
/**
* 将当前颜色转换为十六进制颜色表示。
* @param allow3Char 是否允许返回简写的十六进制颜色表示(如果可能)。默认值为 `false`。
* @returns 一个字符串,表示当前颜色的十六进制格式。
*/
toHex(allow3Char = false) : string {
return rgbToHex(this.r, this.g, this.b, allow3Char);
}
/**
* 将当前颜色转换为带有井号(`#`)前缀的十六进制颜色表示。
* @param allow3Char 是否允许返回简写的十六进制颜色表示(如果可能)。默认值为 `false`。
* @returns 一个字符串,表示当前颜色的带有井号前缀的十六进制格式。
*/
toHexString(allow3Char = false) : string {
return '#' + this.toHex(allow3Char);
}
/**
* 返回颜色的八位十六进制值.
* @param allow4Char 如果可能的话将十六进制值缩短为4个字符
*/
toHex8(allow4Char = false) : string {
return rgbaToHex(this.r, this.g, this.b, this.a, allow4Char);
}
/**
* 返回颜色的八位十六进制值,并且值前面带有#符号.
* @param allow4Char 如果可能的话将十六进制值缩短为4个字符
*/
toHex8String(allow4Char = false) : string {
return '#' + this.toHex8(allow4Char);
}
/**
* 根据颜色的透明度Alpha值返回较短的十六进制值并且值前面带有#符号。
* @param allowShortChar 如果可能的话将十六进制值缩短至3个或4个字符
*/
toHexShortString(allowShortChar = false) : string {
return this.a == 1 ? this.toHexString(allowShortChar) : this.toHex8String(allowShortChar);
}
/**
* 将当前颜色转换为 RGB红、绿、蓝颜色空间的对象表示。
* @returns 一个包含 `r`、`g`、`b` 和 `a` 属性的对象,表示当前颜色的 RGB 格式。
*/
toRgb() : RGBA {
return {
r: Math.round(this.r),
g: Math.round(this.g),
b: Math.round(this.b),
a: this.a,
} as RGBA;
}
/**
* 将当前颜色对象转换为CSS风格的RGB或RGBA字符串
* @returns {string} 返回一个CSS风格的RGB或RGBA字符串表示当前颜色对象的颜色值
*/
toRgbString() : string {
const r = Math.round(this.r);
const g = Math.round(this.g);
const b = Math.round(this.b);
return this.a == 1 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${this.roundA})`;
}
/**
* 将当前颜色转换为百分比表示的 RGB红、绿、蓝颜色空间的对象表示。
* @returns 一个包含 `r`、`g`、`b` 和 `a` 属性的对象,表示当前颜色的百分比表示的 RGB 格式。
*/
toPercentageRgb() : RGBAString {
// 定义一个格式化函数,将颜色值转换为百分比表示
const fmt = (x : number) : string => `${Math.round(bound01(x, 255) * 100)}%`;
// 返回一个RGBA对象其中颜色值已转换为百分比表示
return {
r: fmt(this.r),
g: fmt(this.g),
b: fmt(this.b),
a: this.a,
} as RGBAString;
}
/**
* 将RGBA相对值插值为一个字符串颜色值以百分比表示。
*/
toPercentageRgbString() : string {
// 定义一个四舍五入函数,将颜色值转换为百分比表示的整数
const rnd = (x : number) : number => Math.round(bound01(x, 255) * 100);
// 根据alpha值返回不同的字符串表示
return this.a == 1
? `rgb(${rnd(this.r)}%, ${rnd(this.g)}%, ${rnd(this.b)}%)`
: `rgba(${rnd(this.r)}%, ${rnd(this.g)}%, ${rnd(this.b)}%, ${this.roundA})`;
}
/**
* 返回这个颜色的'真实'名称,不存在返回null
*/
toName() : string | null {
if (this.a == 0) {
return 'transparent';
}
if (this.a < 1) {
return null;
}
const hex = this.toHexString()//'#' + rgbToHex(this.r, this.g, this.b, false);
// #ifndef APP
const _names = Array.from(names.entries())
for (let [key, value] of _names) {
if (hex == value) {
return key;
}
}
return null;
// #endif
// #ifdef APP
return this.reversedNames.get(hex)
// #endif
}
/**
* 将颜色转换为字符串表示。
*
* @param format - 用于显示字符串表示的格式。
*/
// toString<T extends 'name'>(format : T) : string;
// toString<T extends LColorFormats>(format ?: T) : string;
// #ifdef APP-ANDROID
override toString() : string {
return this.toString(null)
}
// #endif
toString(format ?: LColorFormats) : string {
const formatSet = toBoolean(format);
let _format = format ?? this.format;
let formattedString : string | null = null;
const hasAlpha = this.a < 1 && this.a >= 0;
const needsAlphaFormat = !formatSet && hasAlpha && (_format != null && _format.startsWith('hex') || _format == 'name');
if (needsAlphaFormat) {
// 特殊情况透明度所有其他非透明度格式都会在有透明度时返回rgba。
// 当透明度为0时返回"transparent"。
if (_format == 'name' && this.a == 0) {
return this.toName() ?? 'transparent';
}
return this.toRgbString();
}
if (_format == 'rgb') {
formattedString = this.toRgbString();
}
if (_format == 'prgb') {
formattedString = this.toPercentageRgbString();
}
if (_format == 'hex' || _format == 'hex6') {
formattedString = this.toHexString();
}
if (_format == 'hex3') {
formattedString = this.toHexString(true);
}
if (_format == 'hex4') {
formattedString = this.toHex8String(true);
}
if (_format == 'hex8') {
formattedString = this.toHex8String();
}
if (_format == 'name') {
formattedString = this.toName();
}
if (_format == 'hsl') {
formattedString = this.toHslString();
}
if (_format == 'hsv') {
formattedString = this.toHsvString();
}
if (_format == 'hsb') {
formattedString = this.toHsbString();
}
return formattedString ?? this.toHexString();
}
toNumber() : number {
return (Math.round(this.r) << 16) + (Math.round(this.g) << 8) + Math.round(this.b);
}
clone() : TinyColor {
return new TinyColor(this.toString());
}
/**
* 将颜色变浅指定的量。提供100将始终返回白色。
* @param amount - 有效值介于1-100之间
*/
lighten(amount = 10) : TinyColor {
const hsl = this.toHsl();
hsl.l += amount / 100;
hsl.l = clamp01(hsl.l);
return new TinyColor(hsl, { format: this.format } as LColorOptions);
}
/**
* 将颜色变亮一定的量范围从0到100。
* @param amount - 有效值在1-100之间
*/
brighten(amount = 10) : TinyColor {
const rgb = this.toRgb();
rgb.r = Math.max(0, Math.min(255, rgb.r - Math.round(255 * -(amount / 100))));
rgb.g = Math.max(0, Math.min(255, rgb.g - Math.round(255 * -(amount / 100))));
rgb.b = Math.max(0, Math.min(255, rgb.b - Math.round(255 * -(amount / 100))));
return new TinyColor(rgb, { format: this.format } as LColorOptions);
}
/**
* 将颜色变暗一定的量范围从0到100。
* 提供100将始终返回黑色。
* @param amount - 有效值在1-100之间
*/
darken(amount = 10) : TinyColor {
const hsl = this.toHsl();
hsl.l -= amount / 100;
hsl.l = clamp01(hsl.l);
return new TinyColor(hsl, { format: this.format } as LColorOptions);
}
/**
* 将颜色与纯白色混合范围从0到100。
* 提供0将什么都不做提供100将始终返回白色。
* @param amount - 有效值在1-100之间
*/
tint(amount = 10) : TinyColor {
return this.mix('white', amount);
}
/**
* 将颜色与纯黑色混合范围从0到100。
* 提供0将什么都不做提供100将始终返回黑色。
* @param amount - 有效值在1-100之间
*/
shade(amount = 10) : TinyColor {
return this.mix('black', amount);
}
/**
* 将颜色的饱和度降低一定的量范围从0到100。
* 提供100与调用greyscale相同
* @param amount - 有效值在1-100之间
*/
desaturate(amount = 10) : TinyColor {
const hsl = this.toHsl();
hsl.s -= amount / 100;
hsl.s = clamp01(hsl.s);
return new TinyColor(hsl, { format: this.format } as LColorOptions);
}
/**
* 将颜色饱和度提高一定数量,范围从 0 到 100。
* @param amount - 有效值介于 1 到 100 之间。
*/
saturate(amount = 10) : TinyColor {
const hsl = this.toHsl();
hsl.s += amount / 100;
hsl.s = clamp01(hsl.s);
return new TinyColor(hsl, { format: this.format } as LColorOptions);
}
/**
* 将颜色完全去饱和为灰度。
* 等同于调用 `desaturate(100)`。
*/
greyscale() : TinyColor {
return this.desaturate(100);
}
/**
* spin 方法接收一个正数或负数作为参数,表示色相的变化量,变化范围在 [-360, 360] 之间。
* 如果提供的值超出此范围,它将被限制在此范围内。
*/
spin(amount : number) : TinyColor {
const hsl = this.toHsl();
const hue = (hsl.h + amount) % 360;
hsl.h = hue < 0 ? 360 + hue : hue;
return new TinyColor(hsl, { format: this.format } as LColorOptions);
}
/**
* 将当前颜色与另一种颜色按给定的比例混合范围从0到100。
* 0表示不混合返回当前颜色
*/
mix(color : LColorInput, amount = 50) : TinyColor {
const rgb1 = this.toRgb();
const rgb2 = new TinyColor(color).toRgb();
const p = amount / 100;
const rgba = {
r: (rgb2.r - rgb1.r) * p + rgb1.r,
g: (rgb2.g - rgb1.g) * p + rgb1.g,
b: (rgb2.b - rgb1.b) * p + rgb1.b,
a: (rgb2.a - rgb1.a) * p + rgb1.a,
};
return new TinyColor(rgba, { format: this.format } as LColorOptions);
}
/**
* 生成一组与当前颜色相似的颜色。
* 这些颜色在色相环上是相邻的,形成一个类似于彩虹的颜色序列。
* @param results - 要生成的相似颜色的数量,默认值为 6。
* @param slices - 将色相环划分为多少个部分,默认值为 30。
* @returns 一个包含当前颜色及其相似颜色的 TinyColor 对象数组。
*/
analogous(results = 6, slices = 30) : TinyColor[] {
const hsl = this.toHsl();
const part = 360 / slices;
const ret : TinyColor[] = [this];
let _results = results
// for (hsl.h = (hsl.h - ((part * results) >> 1) + 720) % 360; --results;) {
// hsl.h = (hsl.h + part) % 360;
// ret.push(new TinyColor(hsl));
// }
hsl.h = (hsl.h - ((part * _results) >> 1) + 720) % 360;
while (_results > 0) {
hsl.h = (hsl.h + part) % 360;
ret.push(new TinyColor(hsl));
_results--;
}
return ret;
}
/**
* 计算当前颜色的补色。
* 补色是指在色相环上相对位置的颜色,它们的色相差为 180°。
* taken from https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js
* @returns 一个 TinyColor 对象,表示当前颜色的补色。
*/
complement() : TinyColor {
const hsl = this.toHsl();
hsl.h = (hsl.h + 180) % 360;
return new TinyColor(hsl, { format: this.format } as LColorOptions);
}
/**
* 生成一组与当前颜色具有相同色相和饱和度的颜色。
* 这些颜色的亮度值不同,形成一个单色调的颜色序列。
* @param results - 要生成的单色调颜色的数量,默认值为 6。
* @returns 一个包含当前颜色及其单色调颜色的 TinyColor 对象数组。
*/
monochromatic(results = 6) : TinyColor[] {
const hsv = this.toHsv();
const { h } = hsv;
const { s } = hsv;
let { v } = hsv;
const res : TinyColor[] = [];
const modification = 1 / results;
let _results = results
// while (results--) {
// res.push(new TinyColor({ h, s, v }));
// v = (v + modification) % 1;
// }
while (_results > 0) {
res.push(new TinyColor({ h, s, v }));
v = (v + modification) % 1;
_results--
}
return res;
}
/**
* 生成当前颜色的分裂补色。
* 分裂补色是指在色相环上位于当前颜色的两侧的颜色,它们的色相差为 180°。
* @returns 一个包含当前颜色及其分裂补色的 TinyColor 对象数组。
*/
splitcomplement() : TinyColor[] {
const hsl = this.toHsl();
const { h } = hsl;
return [
this,
new TinyColor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l }),
new TinyColor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l }),
] as TinyColor[];
}
/**
* 计算当前颜色在给定背景颜色上的显示效果。
* @param background - 背景颜色,可以是任何 LColorInput 类型的值。
* @returns 一个 TinyColor 对象,表示当前颜色在给定背景颜色上的显示效果。
*/
onBackground(background : LColorInput) : TinyColor {
const fg = this.toRgb();
const bg = new TinyColor(background).toRgb();
const alpha = fg.a + bg.a * (1 - fg.a);
return new TinyColor({
r: (fg.r * fg.a + bg.r * bg.a * (1 - fg.a)) / alpha,
g: (fg.g * fg.a + bg.g * bg.a * (1 - fg.a)) / alpha,
b: (fg.b * fg.a + bg.b * bg.a * (1 - fg.a)) / alpha,
a: alpha,
});
}
/**
* 生成当前颜色的三色调。
* 三色调是指在色相环上位于当前颜色的两侧的颜色,它们的色相差为 120°。
* 这是 `polyad(3)` 方法的别名。
* @returns 一个包含当前颜色及其三色调颜色的 TinyColor 对象数组。
*/
triad() : TinyColor[] {
return this.polyad(3);
}
/**
* 生成当前颜色的四色调。
* 四色调是指在色相环上位于当前颜色的两侧的颜色,它们的色相差为 90°。
* 这是 `polyad(4)` 方法的别名。
* @returns 一个包含当前颜色及其四色调颜色的 TinyColor 对象数组。
*/
tetrad() : TinyColor[] {
return this.polyad(4);
}
/**
* 生成当前颜色的 n 色调。
* n 色调是指在色相环上位于当前颜色的两侧的颜色,它们的色相差为 360° / n。
* Get polyad colors, like (for 1, 2, 3, 4, 5, 6, 7, 8, etc...)
* monad, dyad, triad, tetrad, pentad, hexad, heptad, octad, etc...
* @param n - 一个整数,表示要生成的色调数量。
* @returns 一个包含当前颜色及其 n 色调颜色的 TinyColor 对象数组。
*/
polyad(n : number) : TinyColor[] {
const hsl = this.toHsl();
const { h } = hsl;
const result : TinyColor[] = [this];
const increment = 360 / n;
for (let i = 1; i < n; i++) {
result.push(new TinyColor({ h: (h + i * increment) % 360, s: hsl.s, l: hsl.l }));
}
return result;
}
/**
* 比较当前颜色与给定颜色是否相等。
* @param color - 一个 LColorInput 类型的值,表示要比较的颜色。
* @returns 一个布尔值,表示当前颜色与给定颜色是否相等。
*/
// #ifndef APP-ANDROID
equals(other ?: LColorInput) : boolean {
if (other == null) {
return false
} else if (other instanceof TinyColor) {
return this.toRgbString() == (other as TinyColor).toRgbString()
}
return this.toRgbString() == new TinyColor(other).toRgbString();
}
// #endif
// #ifdef APP-ANDROID
override equals(other ?: LColorInput) : boolean {
if (other == null) {
return false
} else if (other instanceof TinyColor) {
return this.toRgbString() == (other as TinyColor).toRgbString()
}
return this.toRgbString() == new TinyColor(other).toRgbString();
}
// #endif
}
export function tinyColor(color : LColorInput = '', opts : LColorOptions = {} as LColorOptions) : TinyColor {
return new TinyColor(color, opts);
}

View File

@@ -0,0 +1,306 @@
import { RGB,HSL,HSV } from '../utssdk/interface.uts';
import { bound01, pad2 } from './util';
/**
* Handle bounds / percentage checking to conform to CSS color spec
* 处理边界/百分比检查以符合 CSS 颜色规范
* <http://www.w3.org/TR/css3-color/>
* *Assumes:* r, g, b in [0, 255] or [0, 1]
* *Returns:* { r, g, b } in [0, 255]
*/
function rgbToRgb(r: string, g: string, b: string):RGB;
function rgbToRgb(r: number, g: string, b: string):RGB;
function rgbToRgb(r: number, g: number, b: string):RGB;
function rgbToRgb(r: number, g: number, b: number):RGB;
function rgbToRgb(r: any, g: any, b: any) : RGB {
return {
r: bound01(r, 255) * 255,
g: bound01(g, 255) * 255,
b: bound01(b, 255) * 255,
} as RGB;
}
export {
rgbToRgb
}
/**
* Converts an RGB color value to HSL.
* 将 RGB 颜色值转换为 HSL。
* *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
* *Returns:* { h, s, l } in [0,1]
*/
function rgbToHsl(r: string, g: string, b: string):HSL;
function rgbToHsl(r: number, g: string, b: string):HSL;
function rgbToHsl(r: number, g: number, b: string):HSL;
function rgbToHsl(r: number, g: number, b: number):HSL;
function rgbToHsl(r : any, g : any, b : any) : HSL {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h = 0;
let s:number// = 0;
const l = (max + min) / 2;
if (max == min) {
s = 0;
h = 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;
default:
console.log('h')
break;
}
h /= 6;
}
return { h, s, l } as HSL;
}
export {
rgbToHsl
}
export function hue2rgb(p : number, q : number, t : number) : number {
let _t = t
if (_t < 0) {
_t += 1;
}
if (_t > 1) {
_t -= 1;
}
if (_t < 1 / 6) {
return p + (q - p) * (6 * _t);
}
if (_t < 1 / 2) {
return q;
}
if (_t < 2 / 3) {
return p + (q - p) * (2 / 3 - _t) * 6;
}
return p;
}
/**
* Converts an HSL color value to RGB.
* 将 HSL 颜色值转换为 RGB。
* *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
* *Returns:* { r, g, b } in the set [0, 255]
*/
function hslToRgb(h : string,s : string,l : string) : RGB
function hslToRgb(h : number,s : string,l : string) : RGB
function hslToRgb(h : number,s : number,l : string) : RGB
function hslToRgb(h : number,s : number,l : number) : RGB
function hslToRgb(h : any,s : any,l : any) : RGB {
let r : number;
let g : number;
let b : number;
h = bound01(h, 360);
s = bound01(s, 100);
l = bound01(l, 100);
if (s == 0) {
// achromatic
g = l;
b = l;
r = l;
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return { r: r * 255, g: g * 255, b: b * 255 } as RGB;
}
export {
hslToRgb
}
/**
* Converts an RGB color value to HSV
* 将RGB颜色值转换为HSV颜色值
* *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
* *Returns:* { h, s, v } in [0,1]
*/
export function rgbToHsv(r : number, g : number, b : number) : HSV {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h = 0;
const v = max;
const d = max - min;
const s = max == 0 ? 0 : d / max;
if (max == min) {
h = 0; // achromatic
} else {
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;
default:
console.log('1')
break;
}
h /= 6;
}
return { h, s, v } as HSV;
}
/**
* Converts an HSV color value to RGB.
* 将HSV颜色值转换为RGB。
* *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
* *Returns:* { r, g, b } in the set [0, 255]
*/
function hsvToRgb( h : string, s : string, v : string) : RGB
function hsvToRgb( h : number, s : string, v : string) : RGB
function hsvToRgb( h : number, s : number, v : string) : RGB
function hsvToRgb( h : number, s : number, v : number) : RGB
function hsvToRgb( h : any, s : any, v : any) : RGB {
h = bound01(h, 360) * 6;
s = bound01(s, 100);
v = bound01(v, 100);
const i = Math.floor(h);
const f = h - i;
const p = v * (1 - s);
const q = v * (1 - f * s);
const t = v * (1 - (1 - f) * s);
const mod = i % 6;
const r = [v, q, p, p, t, v][mod];
const g = [t, v, v, q, p, p][mod];
const b = [p, p, t, v, v, q][mod];
return { r: r * 255, g: g * 255, b: b * 255 } as RGB;
}
export {
hsvToRgb
}
/**
* Converts an RGB color to hex
* 将RGB颜色转换为十六进制。
* Assumes r, g, and b are contained in the set [0, 255]
* Returns a 3 or 6 character hex
*/
export function rgbToHex(r : number, g : number, b : number, allow3Char : boolean = false) : string {
const hex = [
pad2(Math.round(r).toString(16)),
pad2(Math.round(g).toString(16)),
pad2(Math.round(b).toString(16)),
];
// Return a 3 character hex if possible
if (
allow3Char &&
hex[0].startsWith(hex[0].charAt(1)) &&
hex[1].startsWith(hex[1].charAt(1)) &&
hex[2].startsWith(hex[2].charAt(1))
) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
}
return hex.join('');
}
/**
* Converts an RGBA color plus alpha transparency to hex
* 将带有透明度的RGBA颜色转换为十六进制。
* Assumes r, g, b are contained in the set [0, 255] and
* a in [0, 1]. Returns a 4 or 8 character rgba hex
*/
// eslint-disable-next-line max-params
export function rgbaToHex(r : number, g : number, b : number, a : number, allow4Char : boolean = false) : string {
const hex = [
pad2(Math.round(r).toString(16)),
pad2(Math.round(g).toString(16)),
pad2(Math.round(b).toString(16)),
pad2(convertDecimalToHex(a)),
];
// Return a 4 character hex if possible
if (
allow4Char &&
hex[0].startsWith(hex[0].charAt(1)) &&
hex[1].startsWith(hex[1].charAt(1)) &&
hex[2].startsWith(hex[2].charAt(1)) &&
hex[3].startsWith(hex[3].charAt(1))
) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0) + hex[3].charAt(0);
}
return hex.join('');
}
/**
* Converts an RGBA color to an ARGB Hex8 string
* 将RGBA颜色转换为ARGB十六进制字符串。
* Rarely used, but required for "toFilter()"
*/
export function rgbaToArgbHex(r : number, g : number, b : number, a : number) : string {
const hex = [
pad2(convertDecimalToHex(a)),
pad2(Math.round(r).toString(16)),
pad2(Math.round(g).toString(16)),
pad2(Math.round(b).toString(16)),
];
return hex.join('');
}
/** Converts a decimal to a hex value */
/** 将十进制转换为十六进制值。 */
function convertDecimalToHex(d : number) : string
function convertDecimalToHex(d : string) : string
function convertDecimalToHex(d : any) : string {
return Math.round(parseFloat(`${d}`) * 255).toString(16);
}
export {convertDecimalToHex}
/** Converts a hex value to a decimal */
export function convertHexToDecimal(h : string) : number {
return parseIntFromHex(h) / 255;
}
/** Parse a base-16 hex value into a base-10 integer */
export function parseIntFromHex(val : string) : number {
return parseInt(val, 16);
}
export function numberInputToObject(color : number) : RGB {
return {
r: color >> 16,
g: (color & 0xff00) >> 8,
b: color & 0xff,
} as RGB;
}

View File

@@ -0,0 +1,155 @@
// @ts-nocheck
// https://github.com/bahamas10/css-color-names/blob/master/css-color-names.json
/**
* @hidden
*/
export const names: Map<string, string> = new Map<string, string>([
['aliceblue', '#f0f8ff'],
['antiquewhite', '#faebd7'],
['aqua', '#00ffff'],
['aquamarine', '#7fffd4'],
['azure', '#f0ffff'],
['beige', '#f5f5dc'],
['bisque', '#ffe4c4'],
['black', '#000000'],
['blanchedalmond', '#ffebcd'],
['blue', '#0000ff'],
['blueviolet', '#8a2be2'],
['brown', '#a52a2a'],
['burlywood', '#deb887'],
['cadetblue', '#5f9ea0'],
['chartreuse', '#7fff00'],
['chocolate', '#d2691e'],
['coral', '#ff7f50'],
['cornflowerblue', '#6495ed'],
['cornsilk', '#fff8dc'],
['crimson', '#dc143c'],
['cyan', '#00ffff'],
['darkblue', '#00008b'],
['darkcyan', '#008b8b'],
['darkgoldenrod', '#b8860b'],
['darkgray', '#a9a9a9'],
['darkgreen', '#006400'],
['darkgrey', '#a9a9a9'],
['darkkhaki', '#bdb76b'],
['darkmagenta', '#8b008b'],
['darkolivegreen', '#556b2f'],
['darkorange', '#ff8c00'],
['darkorchid', '#9932cc'],
['darkred', '#8b0000'],
['darksalmon', '#e9967a'],
['darkseagreen', '#8fbc8f'],
['darkslateblue', '#483d8b'],
['darkslategray', '#2f4f4f'],
['darkslategrey', '#2f4f4f'],
['darkturquoise', '#00ced1'],
['darkviolet', '#9400d3'],
['deeppink', '#ff1493'],
['deepskyblue', '#00bfff'],
['dimgray', '#696969'],
['dimgrey', '#696969'],
['dodgerblue', '#1e90ff'],
['firebrick', '#b22222'],
['floralwhite', '#fffaf0'],
['forestgreen', '#228b22'],
['fuchsia', '#ff00ff'],
['gainsboro', '#dcdcdc'],
['ghostwhite', '#f8f8ff'],
['goldenrod', '#daa520'],
['gold', '#ffd700'],
['gray', '#808080'],
['green', '#008000'],
['greenyellow', '#adff2f'],
['grey', '#808080'],
['honeydew', '#f0fff0'],
['hotpink', '#ff69b4'],
['indianred', '#cd5c5c'],
['indigo', '#4b0082'],
['ivory', '#fffff0'],
['khaki', '#f0e68c'],
['lavenderblush', '#fff0f5'],
['lavender', '#e6e6fa'],
['lawngreen', '#7cfc00'],
['lemonchiffon', '#fffacd'],
['lightblue', '#add8e6'],
['lightcoral', '#f08080'],
['lightcyan', '#e0ffff'],
['lightgoldenrodyellow', '#fafad2'],
['lightgray', '#d3d3d3'],
['lightgreen', '#90ee90'],
['lightgrey', '#d3d3d3'],
['lightpink', '#ffb6c1'],
['lightsalmon', '#ffa07a'],
['lightseagreen', '#20b2aa'],
['lightskyblue', '#87cefa'],
['lightslategray', '#778899'],
['lightslategrey', '#778899'],
['lightsteelblue', '#b0c4de'],
['lightyellow', '#ffffe0'],
['lime', '#00ff00'],
['limegreen', '#32cd32'],
['linen', '#faf0e6'],
['magenta', '#ff00ff'],
['maroon', '#800000'],
['mediumaquamarine', '#66cdaa'],
['mediumblue', '#0000cd'],
['mediumorchid', '#ba55d3'],
['mediumpurple', '#9370db'],
['mediumseagreen', '#3cb371'],
['mediumslateblue', '#7b68ee'],
['mediumspringgreen', '#00fa9a'],
['mediumturquoise', '#48d1cc'],
['mediumvioletred', '#c71585'],
['midnightblue', '#191970'],
['mintcream', '#f5fffa'],
['mistyrose', '#ffe4e1'],
['moccasin', '#ffe4b5'],
['navajowhite', '#ffdead'],
['navy', '#000080'],
['oldlace', '#fdf5e6'],
['olive', '#808000'],
['olivedrab', '#6b8e23'],
['orange', '#ffa500'],
['orangered', '#ff4500'],
['orchid', '#da70d6'],
['palegoldenrod', '#eee8aa'],
['palegreen', '#98fb98'],
['paleturquoise', '#afeeee'],
['palevioletred', '#db7093'],
['papayawhip', '#ffefd5'],
['peachpuff', '#ffdab9'],
['peru', '#cd853f'],
['pink', '#ffc0cb'],
['plum', '#dda0dd'],
['powderblue', '#b0e0e6'],
['purple', '#800080'],
['rebeccapurple', '#663399'],
['red', '#ff0000'],
['rosybrown', '#bc8f8f'],
['royalblue', '#4169e1'],
['saddlebrown', '#8b4513'],
['salmon', '#fa8072'],
['sandybrown', '#f4a460'],
['seagreen', '#2e8b57'],
['seashell', '#fff5ee'],
['sienna', '#a0522d'],
['silver', '#c0c0c0'],
['skyblue', '#87ceeb'],
['slateblue', '#6a5acd'],
['slategray', '#708090'],
['slategrey', '#708090'],
['snow', '#fffafa'],
['springgreen', '#00ff7f'],
['steelblue', '#4682b4'],
['tan', '#d2b48c'],
['teal', '#008080'],
['thistle', '#d8bfd8'],
['tomato', '#ff6347'],
['turquoise', '#40e0d0'],
['violet', '#ee82ee'],
['wheat', '#f5deb3'],
['white', '#ffffff'],
['whitesmoke', '#f5f5f5'],
['yellow', '#ffff00'],
['yellowgreen', '#9acd32'],
]);

View File

@@ -0,0 +1,356 @@
// @ts-nocheck
import { HSL, HSLA, HSV, HSVA, HSB, HSBA,RGB, RGBA, LColorInfo, LColorFormats } from '../utssdk/interface.uts';
import { convertHexToDecimal, hslToRgb, hsvToRgb, parseIntFromHex, rgbToRgb } from './conversion';
import { names } from './css-color-names';
import { boundAlpha, convertToPercentage, toBoolean } from './util';
type ColorMatchers = {
CSS_UNIT : RegExp,
rgb : RegExp,
rgba : RegExp,
hsl : RegExp,
hsla : RegExp,
hsv : RegExp,
hsva : RegExp,
hsb : RegExp,
hsba : RegExp,
hex3 : RegExp,
hex6 : RegExp,
hex4 : RegExp,
hex8 : RegExp,
}
// #ifndef UNI-APP-X
type UTSJSONObject = object
// #endif
// <http://www.w3.org/TR/css3-values/#integers>
const CSS_INTEGER = '[-\\+]?\\d+%?';
// <http://www.w3.org/TR/css3-values/#number-value>
const CSS_NUMBER = '[-\\+]?\\d*\\.\\d+%?';
// Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
// 允许正负整数/数字。不要捕获要么/或者,只需捕获整个结果。
const CSS_UNIT = `(?:${CSS_NUMBER})|(?:${CSS_INTEGER})`;
// Actual matching.
// Parentheses and commas are optional, but not required.
// Whitespace can take the place of commas or opening paren
// 实际匹配。
// 圆括号和逗号是可选的,但不是必需的。
// 空格可以代替逗号或左括号
const PERMISSIVE_MATCH3 = '[\\s|\\(]+(' +
CSS_UNIT +
')[,|\\s]+(' +
CSS_UNIT +
')[,|\\s]+(' +
CSS_UNIT +
')\\s*\\)?';;
// const PERMISSIVE_MATCH3 = `[\\s|\\(]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})\\s*\\)?`;
const PERMISSIVE_MATCH4 = '[\\s|\\(]+(' +
CSS_UNIT +
')[,|\\s]+(' +
CSS_UNIT +
')[,|\\s]+(' +
CSS_UNIT +
')[,|\\s]+(' +
CSS_UNIT +
')\\s*\\)?';
// const PERMISSIVE_MATCH4 = `[\\s|\\(]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})[,|\\s]+(${CSS_UNIT})\\s*\\)?`;
export const matchers = {
CSS_UNIT: new RegExp(CSS_UNIT),
rgb: new RegExp('rgb' + PERMISSIVE_MATCH3),
rgba: new RegExp('rgba' + PERMISSIVE_MATCH4),
hsl: new RegExp('hsl' + PERMISSIVE_MATCH3),
hsla: new RegExp('hsla' + PERMISSIVE_MATCH4),
hsv: new RegExp('hsv' + PERMISSIVE_MATCH3),
hsva: new RegExp('hsva' + PERMISSIVE_MATCH4),
hsb: new RegExp('hsb' + PERMISSIVE_MATCH3),
hsba: new RegExp('hsba' + PERMISSIVE_MATCH4),
hex3: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex6: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
hex4: /^#?([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex8: /^#?([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
} as ColorMatchers;
/**
* Check to see if it looks like a CSS unit
* 检查它是否看起来像一个 CSS 单位
* (see `matchers` above for definition).
*/
function isValidCSSUnit(color : string) : boolean
function isValidCSSUnit(color : number) : boolean
// #ifndef APP
function isValidCSSUnit(color : any|null) : boolean
// #endif
function isValidCSSUnit(color : any|null) : boolean {
return toBoolean(matchers.CSS_UNIT.exec(`${color}`));
}
export { isValidCSSUnit }
function inputToRGB(color : string) : LColorInfo
function inputToRGB(color : RGB) : LColorInfo
function inputToRGB(color : RGBA) : LColorInfo
function inputToRGB(color : HSL) : LColorInfo
function inputToRGB(color : HSLA) : LColorInfo
function inputToRGB(color : HSV) : LColorInfo
function inputToRGB(color : HSVA) : LColorInfo
function inputToRGB(color : HSB) : LColorInfo
function inputToRGB(color : HSBA) : LColorInfo
function inputToRGB(color : any) : LColorInfo {
let _color: UTSJSONObject|null = null
let rgb = { r: 0, g: 0, b: 0 } as RGB;
let a:any = 1;
let s: any | null;
let v: any | null;
let l: any | null;
let ok = false;
let format: LColorFormats | null = null;
if (typeof color == 'string') {
_color = stringInputToObject(color as string);
} else if(typeof color == 'object'){
_color = JSON.parse(JSON.stringify(color)) as UTSJSONObject
} else {
// _color = {} as UTSJSONObject
}
if(_color != null){
if (isValidCSSUnit(_color['r']) && isValidCSSUnit(_color['g']) && isValidCSSUnit(_color['b'])){
rgb = rgbToRgb(_color['r']!, _color['g']!, _color['b']!);
ok = true;
format = `${_color['r']}`.endsWith('%') ? 'prgb' : 'rgb';
} else if(isValidCSSUnit(_color['h']) && isValidCSSUnit(_color['s']) && (isValidCSSUnit(_color['v']) || isValidCSSUnit(_color['b'])) ){
const isHSV = _color['v'] != null
s = convertToPercentage(_color['s']!);
v = isHSV ? convertToPercentage(_color['v']!) : convertToPercentage(_color['b']!);
rgb = hsvToRgb(_color['h']!, s, v);
ok = true;
format = isHSV ? 'hsv' : 'hsb';
} else if(isValidCSSUnit(_color['h']) && isValidCSSUnit(_color['s']) && isValidCSSUnit(_color['l'])){
s = convertToPercentage(_color['s']!);
l = convertToPercentage(_color['l']!);
rgb = hslToRgb(_color['h']!, s, l);
ok = true;
format = 'hsl';
}
if(_color['a']!=null){
a = _color['a']!;
}
}
a = boundAlpha(a);
return {
ok,
format: _color?.['format'] as (string | null) ?? format,
r: Math.min(255, Math.max(rgb.r, 0)),
g: Math.min(255, Math.max(rgb.g, 0)),
b: Math.min(255, Math.max(rgb.b, 0)),
a,
} as LColorInfo
}
export {
inputToRGB
}
/**
* Permissive string parsing. Take in a number of formats, and output an object
* based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
*/
export function stringInputToObject(color : string) : UTSJSONObject | null {
let _color = color.trim().toLowerCase();
if (_color.length == 0) {
return null;
}
let named = false;
if (names.get(_color) != null) {
_color = names.get(_color)!;
named = true;
} else if (_color == 'transparent') {
return { r: 0, g: 0, b: 0, a: 0, format: 'name' } as UTSJSONObject;
// return new Map([
// ['r', 0],
// ['g', 0],
// ['b', 0],
// ['a', 0],
// ['format', 'name'],
// ])
}
// Try to match string input using regular expressions.
// Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
// Just return an object and let the conversion functions handle that.
// This way the result will be the same whether the tinycolor is initialized with string or object.
let match = matchers.rgb.exec(_color);
if (match != null) {
const r = match[1]
const g = match[2]
const b = match[3]
return { r, g, b } as UTSJSONObject;
// return new Map([
// ['r', match[1]],
// ['g', match[2]],
// ['b', match[3]],
// ])
}
match = matchers.rgba.exec(_color);
if (match != null) {
const r = match[1]
const g = match[2]
const b = match[3]
const a = match[4]
return { r, g, b, a } as UTSJSONObject;
// return new Map([
// ['r', match[1]],
// ['g', match[2]],
// ['b', match[3]],
// ['a', match[4]],
// ])
}
match = matchers.hsl.exec(_color);
if (match != null) {
const h = match[1]
const s = match[2]
const l = match[3]
return { h, s, l } as UTSJSONObject;
// return new Map([
// ['h', match[1]],
// ['s', match[2]],
// ['l', match[3]],
// ])
}
match = matchers.hsla.exec(_color);
if (match != null) {
const h = match[1]
const s = match[2]
const l = match[3]
const a = match[4]
return { h, s, l, a } as UTSJSONObject;
// return new Map([
// ['h', match[1]],
// ['s', match[2]],
// ['l', match[3]],
// ['a', match[4]],
// ])
}
match = matchers.hsv.exec(_color);
if (match != null) {
const h = match[1]
const s = match[2]
const v = match[3]
return { h, s, v } as UTSJSONObject;
// return new Map([
// ['h', match[1]],
// ['s', match[2]],
// ['v', match[3]],
// ])
}
match = matchers.hsva.exec(_color);
if (match != null) {
const h = match[1]
const s = match[2]
const v = match[3]
const a = match[4]
return { h, s, v, a } as UTSJSONObject;
// return new Map([
// ['h', match[1]],
// ['s', match[2]],
// ['v', match[3]],
// ['a', match[4]],
// ])
}
match = matchers.hex8.exec(_color);
if (match != null) {
const r = parseIntFromHex(match[1]!)
const g = parseIntFromHex(match[2]!)
const b = parseIntFromHex(match[3]!)
const a = convertHexToDecimal(match[4]!)
return {
r,
g,
b,
a,
format: named ? 'name' : 'hex8',
} as UTSJSONObject;
// return new Map([
// ['r', parseIntFromHex(match[1])],
// ['g', parseIntFromHex(match[2])],
// ['b', parseIntFromHex(match[3])],
// ['a', convertHexToDecimal(match[4])],
// ['format', named ? 'name' : 'hex8'],
// ])
}
match = matchers.hex6.exec(_color);
if (match != null) {
const r = parseIntFromHex(match[1]!)
const g = parseIntFromHex(match[2]!)
const b = parseIntFromHex(match[3]!)
// const a = parseIntFromHex(match[4])
return {
r,
g,
b,
format: named ? 'name' : 'hex',
} as UTSJSONObject;
// return new Map([
// ['r', parseIntFromHex(match[1])],
// ['g', parseIntFromHex(match[2])],
// ['b', parseIntFromHex(match[3])],
// ['format', named ? 'name' : 'hex'],
// ])
}
match = matchers.hex4.exec(_color);
if (match != null) {
const r = parseIntFromHex((match[1] + match[1]))
const g = parseIntFromHex((match[2] + match[2]))
const b = parseIntFromHex((match[3] + match[3]))
const a = convertHexToDecimal((match[4] + match[4]))
return {
r,
g,
b,
a,
format: named ? 'name' : 'hex8',
} as UTSJSONObject;
// return new Map([
// ['r', parseIntFromHex(match[1] + match[1])],
// ['g', parseIntFromHex(match[2] + match[2])],
// ['b', parseIntFromHex(match[3] + match[3])],
// ['a', convertHexToDecimal(match[4] + match[4])],
// ['format', named ? 'name' : 'hex8'],
// ])
}
match = matchers.hex3.exec(_color);
if (match != null) {
const r = parseIntFromHex((match[1] + match[1]))
const g = parseIntFromHex((match[2] + match[2]))
const b = parseIntFromHex((match[3] + match[3]))
return {
r,
g,
b,
format: named ? 'name' : 'hex',
} as UTSJSONObject;
// return new Map([
// ['r', parseIntFromHex(match[1] + match[1])],
// ['g', parseIntFromHex(match[2] + match[2])],
// ['b', parseIntFromHex(match[3] + match[3])],
// ['format', named ? 'name' : 'hex'],
// ])
}
return null
}

View File

@@ -0,0 +1,202 @@
// https://github.com/ant-design/ant-design-colors/blob/main/src/generate.ts
import { inputToRGB } from './format-input';
import { rgbToHex, rgbToHsv } from './conversion';
import { HSV, LColorInfo, LGenerateOptions} from '../utssdk/interface.uts';
type DarkColorMapItem = {
index : number;
opacity : number;
};
const hueStep = 2; // 色相阶梯
const saturationStep = 0.16; // 饱和度阶梯,浅色部分
const saturationStep2 = 0.05; // 饱和度阶梯,深色部分
const brightnessStep1 = 0.05; // 亮度阶梯,浅色部分
const brightnessStep2 = 0.15; // 亮度阶梯,深色部分
const lightColorCount = 5; // 浅色数量,主色上
const darkColorCount = 4; // 深色数量,主色下
// 暗色主题颜色映射关系表
const darkColorMap = [
{ index: 7, opacity: 0.15 },
{ index: 6, opacity: 0.25 },
{ index: 5, opacity: 0.3 },
{ index: 5, opacity: 0.45 },
{ index: 5, opacity: 0.65 },
{ index: 5, opacity: 0.85 },
{ index: 4, opacity: 0.9 },
{ index: 3, opacity: 0.95 },
{ index: 2, opacity: 0.97 },
{ index: 1, opacity: 0.98 },
] as DarkColorMapItem[];
// 从 TinyColor.toHsv 移植的包装函数
// 保留这里,因为有 `hsv.h * 360`
function toHsv({ r, g, b } : LColorInfo) : HSV {
// 将 RGB 值转换为 HSV 值
const hsv = rgbToHsv(r, g, b);
// 返回一个 HsvObject其中 h 值乘以 360
return { h: hsv.h * 360, s: hsv.s, v: hsv.v } as HSV;
}
// 从 TinyColor.toHexString 移植的包装函数
// 保留这里,因为有前缀 `#`
function toHex({ r, g, b }: LColorInfo) : string {
// 将 RGB 值转换为十六进制字符串,并添加前缀 `#`
return `#${rgbToHex(r, g, b, false)}`;
}
// 从 TinyColor.mix 移植的包装函数,无法进行 tree-shaking
// 数量范围为 [0, 1]
// 假设 color1 和 color2 没有透明度,因为以下源代码也是如此
function mix(rgb1 : LColorInfo, rgb2 : LColorInfo, amount : number) : LColorInfo {
// 将 amount 除以 100得到一个范围为 [0, 1] 的值
const p = amount / 100;
// 计算混合后的 RGB 值
const rgb = {
r: (rgb2.r - rgb1.r) * p + rgb1.r,
g: (rgb2.g - rgb1.g) * p + rgb1.g,
b: (rgb2.b - rgb1.b) * p + rgb1.b,
a: 1
} as LColorInfo;
// 返回混合后的 RGB 对象
return rgb;
}
// 根据给定的 HSV 对象和索引值计算新的色相值
// 如果 light 参数为 true则色相向左转动否则向右转动
function getHue(hsv : HSV, i : number, light : boolean = false) : number {
let hue : number;
// 根据色相不同,色相转向不同
if (Math.round(hsv.h) >= 60 && Math.round(hsv.h) <= 240) {
// 如果色相在 60 到 240 之间,向左转动
hue = light ? Math.round(hsv.h) - hueStep * i : Math.round(hsv.h) + hueStep * i;
} else {
hue = light ? Math.round(hsv.h) + hueStep * i : Math.round(hsv.h) - hueStep * i;
}
if (hue < 0) {
// 如果新的色相值小于 0则加上 360
hue += 360;
} else if (hue >= 360) {
// 如果新的色相值大于等于 360则减去 360
hue -= 360;
}
return hue;
}
// 根据给定的 HSV 对象和索引值计算新的饱和度值
// 如果 light 参数为 true则饱和度减小否则增加
function getSaturation(hsv : HSV, i : number, light : boolean = false) : number {
// grey color don't change saturation
// 如果颜色是灰色(色相和饱和度都为 0则饱和度不变
if (hsv.h == 0 && hsv.s == 0) {
return hsv.s;
}
let saturation : number;
// 如果 light 参数为 true则饱和度减小
if (light) {
saturation = hsv.s - saturationStep * i;
}
// 如果 i 等于 darkColorCount则饱和度增加
else if (i == darkColorCount) {
saturation = hsv.s + saturationStep;
}
// 否则,饱和度增加
else {
saturation = hsv.s + saturationStep2 * i;
}
// 边界值修正
if (saturation > 1) {
saturation = 1;
}
// 第一格的 s 限制在 0.06-0.1 之间
if (light && i == lightColorCount && saturation > 0.1) {
saturation = 0.1;
}
if (saturation < 0.06) {
saturation = 0.06;
}
return parseFloat(saturation.toFixed(2))
}
// 根据给定的 HSV 对象和索引值计算新的亮度值
// 如果 light 参数为 true则亮度增加否则减少
function getValue(hsv : HSV, i : number, light : boolean = false) : number {
let value : number;
// 如果 light 参数为 true则亮度增加
if (light) {
value = hsv.v + brightnessStep1 * i;
} else {
value = hsv.v - brightnessStep2 * i;
}
if (value > 1) {
value = 1;
}
// 返回保留两位小数的亮度值
return parseFloat(value.toFixed(2));
}
/**
* generate 函数用于生成一组基于给定颜色的色彩模式。
* 它可以生成亮色、暗色和深色主题颜色模式。
*
* @param {string} color - 输入的颜色值可以是十六进制、RGB、RGBA、HSL、HSLA或颜色名称。
* @param {LGenerateOptions} [opts] - 可选的生成选项。
* @returns {string[]} - 返回一个包含生成的颜色模式的字符串数组。
*/
export function generate(color : string, opts : LGenerateOptions = {} as LGenerateOptions) : string[] {
const patterns : string[] = [];
const pColor = inputToRGB(color);
// 生成亮色模式
for (let i = lightColorCount; i > 0; i -= 1) {
const hsv = toHsv(pColor);
const colorString : string = toHex(
inputToRGB({
h: getHue(hsv, i, true),
s: getSaturation(hsv, i, true),
v: getValue(hsv, i, true),
}),
);
patterns.push(colorString);
}
// 添加原始颜色
patterns.push(toHex(pColor));
// 生成暗色模式
for (let i = 1; i <= darkColorCount; i += 1) {
const hsv = toHsv(pColor);
const colorString : string = toHex(
inputToRGB({
h: getHue(hsv, i),
s: getSaturation(hsv, i),
v: getValue(hsv, i),
}),
);
patterns.push(colorString);
}
// 如果选项中指定了 dark 主题,则生成深色主题颜色模式
if (opts.theme == 'dark') {
return darkColorMap.map(({ index, opacity }, _):string => {
const darkColorString : string = toHex(
mix(
inputToRGB(opts.backgroundColor ?? '#141414'),
inputToRGB(patterns[index]),
opacity * 100,
),
);
return darkColorString;
});
}
// 返回默认颜色模式
return patterns;
}

View File

@@ -0,0 +1,211 @@
// import * as util from './util-test'
// import * as util from './conversion-test'
// import * as util from './format-input-test'
// import * as util from './color-test'
// import * as util from './generate-test'
import { tinyColor } from './color'
// console.log('generate:', generate('red'))
console.log('tinyColor~~~~~~~~~~~~~~test')
// console.log('示例1',tinyColor('#000'));
// console.log('示例2',tinyColor('000'));
// console.log('示例3',tinyColor('#369C'));
// console.log('示例4',tinyColor('369C'));
// console.log('示例5',tinyColor('#f0f0f6'));
// console.log('示例6',tinyColor('f0f0f6'));
// console.log('示例7',tinyColor('#f0f0f688'));
// console.log(tinyColor('f0f0f688'));
// console.log('示例1',tinyColor('hsl(0, 100%, 50%)').toString());
// console.log('示例2',tinyColor('hsla(0, 100%, 50%, .5)').toString());
// console.log('示例3',tinyColor('hsl(0, 100%, 50%)').toString());
// console.log('示例4',tinyColor('hsl 0 1.0 0.5').toString());
// console.log('示例5',tinyColor({ h: 0, s: 1, l: 0.5 }).toString());
// console.log('示例1',tinyColor('hsv(0, 100%, 100%)').toString());
// console.log('示例2',tinyColor('hsva(0, 100%, 100%, .5)').toString());
// console.log('示例3',tinyColor('hsv (0 100% 100%)').toString());
// console.log('示例4',tinyColor('hsv 0 1 1').toString());
// console.log('示例5',tinyColor({ h: 0, s: 100, v: 100 }).toString());
// console.log('示例1',tinyColor('RED').toString(), tinyColor('RED'));
// console.log('示例2',tinyColor('blanchedalmond').toString());
// console.log('示例3',tinyColor('darkblue').toString());
// console.log('示例1:',0x0,tinyColor(0x0).toString());
// console.log('示例2',tinyColor(0xaabbcc).toString());
// console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
// const color = tinyColor('red')
// const color2 = tinyColor({ r: 255, g: 255, b: 255 })
// console.log('示例1:',color.originalInput);
// console.log('示例2:',color2.originalInput);
// const color3 = tinyColor('red')
// const color4 = tinyColor({ r: 255, g: 255, b: 255 })
// console.log('示例3:',color3.format);
// console.log('示例4:',color4.format);
// const color5 = tinyColor('red');
// console.log(color5.isValid, color5.toHexString())
// const color6 = tinyColor('not a color');
// console.log(color6.isValid, color6.toHexString())
// const color7 = tinyColor('#fff');
// const color8 = tinyColor('#000')
// console.log(color7.getBrightness())
// console.log(color8.getBrightness())
// const color9 = tinyColor('#fff');
// const color10 = tinyColor('#000')
// console.log(color9.isLight())
// console.log(color10.isLight())
// const color11 = tinyColor('#fff');
// const color12 = tinyColor('#000')
// console.log(color11.isDark())
// console.log(color12.isDark())
// const color13 = tinyColor('#fff');
// const color14 = tinyColor('#000')
// console.log(color13.getLuminance())
// console.log(color14.getLuminance())
// const color15 = tinyColor('rgba(255, 0, 0, .5)');
// const color16 = tinyColor('rgb(255, 0, 0)')
// const color17 = tinyColor('transparent')
// console.log(color15.getAlpha())
// console.log(color16.getAlpha())
// console.log(color17.getAlpha())
// const color18 = tinyColor('red');
// console.log(color18.getAlpha()) ; // 1
// color18.setAlpha(0.5);
// console.log(color18.getAlpha()); // .5
// console.log(color18.toRgbString()); // "rgba(255, 0, 0, .5)"
// const color19 = tinyColor('rgba(255, 0, 0, .5)');
// const computedColor = color19.onBackground('rgb(0, 0, 255)');
// console.log('color19',computedColor.toRgbString()); // "rgb(128, 0, 128)"
// const color20 = tinyColor('red');
// console.log('color20',color20.toHsv()); // { h: 0, s: 1, v: 1, a: 1 }
// const color21 = tinyColor('red');
// console.log(color21.toHsvString()); // "hsv(0, 100%, 100%)"
// color21.setAlpha(0.5);
// console.log(color21.toHsvString()); // "hsva(0, 100%, 100%, 0.5)"
// const color33 = tinyColor('red');
// console.log(color33.toHsl()); // { h: 0, s: 1, l: 0.5, a: 1 }
// const color34 = tinyColor('red');
// console.log(color34.toHsvString()); // "hsl(0, 100%, 50%)"
// color34.setAlpha(0.5);
// console.log(color34.toHsvString()); // "hsla(0, 100%, 50%, 0.5)"
// console.log(tinyColor('#aabbcc').toNumber() == 0xaabbcc)
// console.log(tinyColor('rgb(1, 1, 1)').toNumber() == (1 << 16) + (1 << 8) + 1)
// const color35 = tinyColor('red');
// console.log(color35.toHex()); // "ff0000"
// const color36 = tinyColor('red');
// console.log(color36.toHexString()); // "#ff0000"
// const color37 = tinyColor('red');
// console.log(color37.toHex8()); // "ff0000ff"
// const color38 = tinyColor('red');
// console.log(color38.toHex8String()); // "#ff0000ff"
// const color39 = tinyColor('#ff000000');
// console.log(color39.toHexShortString()); // "#ff000000"
// console.log(color39.toHexShortString(true)); // "#f000"
// const color40 = tinyColor('#ff0000ff');
// console.log(color40.toHexShortString()); // "#ff0000"
// console.log(color40.toHexShortString(true)); // "#f00"
// const color41 = tinyColor('red');
// console.log(color41.toRgb()); // { r: 255, g: 0, b: 0, a: 1 }
// const color42 = tinyColor('red');
// console.log(color42.toRgbString()); // "rgb(255, 0, 0)"
// color42.setAlpha(0.5);
// console.log(color42.toRgbString()); // "rgba(255, 0, 0, 0.5)"
// const color43 = tinyColor('red')
// console.log(color43.toPercentageRgb())
// const color44 = tinyColor('red');
// console.log(color44.toPercentageRgbString()); // "rgb(100%, 0%, 0%)"
// color44.setAlpha(0.5);
// console.log(color44.toPercentageRgbString()); // "rgba(100%, 0%, 0%, 0.5)"
// const color45 = tinyColor('red');
// console.log(color45.toName()); // "red"
// const color46 = tinyColor('red');
// console.log(color46.toString()); // "red"
// console.log(color46.toString('hsv')); // "hsv(0, 100%, 100%)"
// const color47 = tinyColor('rgb(255, 0, 0)');
// console.log(color47.toString()); // "rgb(255, 0, 0)"
// color47.setAlpha(0.5);
// console.log(color47.toString()); // "rgba(255, 0, 0, 0.5)"
// const color48 = tinyColor('red')
// .lighten()
// .desaturate()
// .toHexString()
// console.log(color48)
// console.log(tinyColor('#f00').lighten().toString())
// console.log(tinyColor('#f00').lighten(100).toString())
// console.log(tinyColor('#f00').brighten().toString())
console.log('tinyColor',tinyColor({a: 1, h: 0, l: 0.4, s: 1}))
// console.log(tinyColor('#f00').darken(100).toString())
// console.log(tinyColor('#f00').tint().toString())
// console.log(tinyColor('#f00').tint(100).toString())
// console.log(tinyColor('#f00').shade().toString())
// console.log(tinyColor('#f00').shade(100).toString())
// console.log(tinyColor('#f00').desaturate().toString())
// console.log(tinyColor('#f00').desaturate(100).toString())
// console.log(tinyColor('hsl(0, 10%, 50%)').saturate().toString())
// console.log(tinyColor('#f00').greyscale().toString())
// console.log(tinyColor('#f00').spin(180).toString())
// console.log(tinyColor('#f00').spin(-90).toString())
// console.log(tinyColor('#f00').spin(90).toString())
// console.log(tinyColor('#f00').spin(0).toString())
// console.log(tinyColor('#f00').spin(360).toString())
// let color51 = tinyColor('#f0f');
// let color52 = tinyColor('#0f0');
// console.log(color51.mix(color52).toHexString())
// const colors52 = tinyColor('#f00').analogous()
// console.log(colors52.map((t):string => t.toHexString()))
// const colors53 = tinyColor('#f00').monochromatic();
// console.log(colors53.map((t):string => t.toHexString()))
// const colors54 = tinyColor('#f00').splitcomplement();
// console.log(colors54.map((t):string => t.toHexString()));
// const colors55 = tinyColor('#f00').triad();
// console.log(colors55.map((t):string => t.toHexString()));
// const colors56 = tinyColor('#f00').tetrad();
// console.log(colors56.map((t):string => t.toHexString()));
// const colors57 = tinyColor('#f00').polyad(4);
// console.log(colors57.map((t):string => t.toHexString()));
// console.log(tinyColor('#f00').complement().toHexString())
// let color158 = tinyColor('red');
// let color58 = tinyColor('#f00');
// function a():string{
// return 'rgb(255, 0, 0)'
// }
// console.log('tinyColor equals', color158.equals(color58), color158.equals('#f00'), a() == a());

View File

@@ -0,0 +1,200 @@
// import {isNumber} from '@/uni_modules/lime-shared/isNumber'
// import {isString} from '@/uni_modules/lime-shared/isString'
// import {isNumeric} from '@/uni_modules/lime-shared/isNumeric'
// #ifdef APP-ANDROID
import BigDecimal from 'java.math.BigDecimal'
// #endif
export function isNumber(value: any|null):boolean{
// #ifdef APP-ANDROID
return ['Byte', 'UByte','Short','UShort','Int','UInt','Long','ULong','Float','Double','number'].includes(typeof value)
// #endif
// #ifdef APP-IOS
return ['Int8', 'UInt8','Int16','UInt16','Int32','UInt32','Int64','UInt64','Int','UInt','Float','Float16','Float32','Float64','Double', 'number'].includes(typeof value)
// #endif
// #ifndef APP-ANDROID || APP-IOS
return typeof value == 'number' && !isNaN(value);
// #endif
}
export function isString(value: any|null):boolean{
return typeof value == 'string';
}
export function isNumeric(value: any|null):boolean{
if(isNumber(value)) {
return true
} else if(isString(value)) {
// const regex = "-?\\d+(\\.\\d+)?".toRegex()
const regex = new RegExp("^(-)?\\d+(\\.\\d+)?$")
return regex.test(value as string) //regex.matches(value as string)
}
return false
}
export function toBoolean(value: any|null):boolean{
// #ifdef APP
// 根据输入值的类型,返回相应的布尔值
if(isNumber(value)){
return (value as number) != 0;
}
if(isString(value)){
return `${value}`.length > 0;
}
if(typeof value == 'boolean'){
return value as boolean;
}
return value != null
// #endif
// #ifndef APP
return Boolean(value)
// #endif
}
/**
* Check to see if string passed in is a percentage
* 检查传入的字符串是否为百分比
* @hidden
*/
export function isPercentage(n : any) : boolean {
return isString(n) && (n as string).indexOf('%') != -1;
}
/**
* Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
* 需要处理 1.0 为 100%,因为一旦它是数字,它与 1 没有区别
* <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
* @hidden
*/
export function isOnePointZero(n : any) : boolean {
return isString(n) && (n as string).indexOf('.') != -1 && parseFloat(n as string) == 1;
}
/**
* Take input from [0, n] and return it as [0, 1]
* 将输入值从 [0, n] 转换为 [0, 1]
* @hidden
*/
function bound01(n: string, max: number): number
function bound01(n: number, max: number): number
// #ifndef APP
function bound01(n : any, max : number) : number
// #endif
function bound01(n : any, max : number) : number {
if(!(isNumber(n) || isString(n))){
return 1
}
if (isOnePointZero(n)) {
n = '100%';
}
const isPercent = isPercentage(n);
n = (isNumber(n) ? n : parseFloat(n as string)) as number
n = max == 360 ? n : Math.min(max, Math.max(0, n));
// Automatically convert percentage into number
// 自动将百分比转换为数字
if (isPercent) {
n = parseInt(`${Math.min(n, 100) * max}`, 10) / 100;
}
// Handle floating point rounding errors
// 处理浮点数舍入误差
if ( Math.abs(n - max) < 0.000001) {
return 1;
}
// Convert into [0, 1] range if it isn't already
// 如果它还不是,将其转换为 [0, 1] 范围
if (max == 360) {
// If n is a hue given in degrees,
// wrap around out-of-range values into [0, 360] range
// then convert into [0, 1].
// 如果 n 是以度为单位的色调,
// 将超出范围的值环绕到 [0, 360] 范围内
// 然后将其转换为 [0, 1]。
n = (n < 0 ? (n % max) + max : n % max) / max // parseFloat(`${max}`);
} else {
// If n not a hue given in degrees
// Convert into [0, 1] range if it isn't already.
// 如果 n 不是以度为单位的色调
// 如果它还不是,将其转换为 [0, 1] 范围。
n = (n % max) / max //parseFloat(`${max}`);
}
return n;
}
export {bound01}
/**
* Force a number between 0 and 1
* 在 0 和 1 之间强制一个数字
* @hidden
*/
export function clamp01(val : number) : number {
return Math.min(1, Math.max(0, val));
}
/**
* Return a valid alpha value [0,1] with all invalid values being set to 1
* 返回一个有效的 alpha 值 [0,1],将所有无效值设置为 1
* @hidden
*/
function boundAlpha(a: number):number
function boundAlpha(a: string):number
// #ifndef APP
function boundAlpha(a: any|null) : number
// #endif
function boundAlpha(a: any|null) : number {
let n = a == null ? 1 : (isString(a) ? parseFloat(a as string) : a as number)
if (isNaN(n) || n < 0 || n > 1) {
n = 1;
}
return n;
}
export {
boundAlpha
}
/**
* Replace a decimal with it's percentage value
* 用百分比值替换小数
* number | string
* @hidden
*/
function convertToPercentage(n:number):number
function convertToPercentage(n:string):string
// #ifndef APP
function convertToPercentage(n:any): any
// #endif
function convertToPercentage(n:any): any{
// #ifdef APP-ANDROID
n = isNumeric(n) ? parseFloat(typeof n == 'string' ? n as string : BigDecimal.valueOf((n as number).toDouble()).toPlainString()) : n// as number
// #endif
// #ifndef APP-ANDROID
n = isNumeric(n) ? parseFloat(`${n}`) : n// as number
// #endif
if(isNumber(n) && (n as number) <= 1){
return `${n * 100}%`.replace('.0%','%');
}
return n;
}
export {convertToPercentage}
/**
* Force a hex value to have 2 characters
* 强制使十六进制值具有 2 个字符
* @hidden
*/
export function pad2(c : string) : string {
//c.padStart(2, '0');//
return c.length == 1 ? '0' + c : `${c}`;
}

View File

@@ -0,0 +1,10 @@
<template>
<view>lime-color test</view>
</template>
<script setup>
import * as test from '@/uni_modules/lime-color/common/test'
</script>
<style>
</style>

View File

@@ -0,0 +1,5 @@
// @ts-nocheck
export * from './common/color'
export * from './common/generate'
export * from './utssdk/interface'
// export {LGenerateOptions} from './utssdk/interface'

View File

@@ -0,0 +1,87 @@
export type RGB = {
r : number;
g : number;
b : number;
}
export type RGBA = {
r : number;
g : number;
b : number;
a : number;
}
export type RGBAString = {
r : string;
g : string;
b : string;
a : number;
}
export type HSL = {
h : number;
s : number;
l : number;
}
export type HSLA = {
h : number;
s : number;
l : number;
a : number;
}
export type HSV = {
h : number;
s : number;
v : number;
}
export type HSVA = {
h : number;
s : number;
v : number;
a : number;
}
// 增加部分
export type HSB = {
h : number;
s : number;
b : number;
}
export type HSBA = {
h : number;
s : number;
b : number;
a : number;
}
export type LColorInfo = {
ok ?: boolean;
format ?: LColorFormats;
r : number;
g : number;
b : number;
a : number;
}
export type LColorFormats =
| 'rgb'
| 'prgb'
| 'hex'
| 'hex3'
| 'hex4'
| 'hex6'
| 'hex8'
| 'name'
| 'hsl'
| 'hsb'
| 'hsv';
export type LColorOptions = {
format ?: LColorFormats;
gradientType ?: string;
}
export type LColorInput = any //string | number | RGB | RGBA | HSL | HSLA | HSV | HSVA | LimeColor;
export type LGenerateOptions = {
theme ?: 'dark' | 'default';
backgroundColor ?: string;
}

View File

@@ -0,0 +1,87 @@
{
"id": "lime-color",
"displayName": "lime-color tinycolor颜色转换",
"version": "0.0.6",
"description": "lime-color是tinycolor UTS版的小型库用于颜色操作和转换,内容Ant Design 的颜色等级生成算法",
"keywords": [
"lime-color",
"TinyColor",
"color",
"颜色转换",
"uts"
],
"repository": "",
"engines": {
"HBuilderX": "^4.0"
},
"dcloudext": {
"type": "uts",
"sale": {
"regular": {
"price": "0.00"
},
"sourcecode": {
"price": "0.00"
}
},
"contact": {
"qq": ""
},
"declaration": {
"ads": "无",
"data": "无",
"permissions": "无"
},
"npmurl": ""
},
"uni_modules": {
"dependencies": [],
"encrypt": [],
"platforms": {
"cloud": {
"tcb": "y",
"aliyun": "y",
"alipay": "y"
},
"client": {
"Vue": {
"vue2": "y",
"vue3": "y"
},
"App": {
"app-android": "y",
"app-ios": "y",
"app-harmony": "y"
},
"H5-mobile": {
"Safari": "y",
"Android Browser": "y",
"微信浏览器(Android)": "y",
"QQ浏览器(Android)": "y"
},
"H5-pc": {
"Chrome": "y",
"IE": "u",
"Edge": "u",
"Firefox": "u",
"Safari": "u"
},
"小程序": {
"微信": "y",
"阿里": "u",
"百度": "u",
"字节跳动": "u",
"QQ": "u",
"钉钉": "u",
"快手": "u",
"飞书": "u",
"京东": "u"
},
"快应用": {
"华为": "u",
"联盟": "u"
}
}
}
}
}

View File

@@ -0,0 +1,550 @@
# lime-color
- 颜色转换
## 安装
插件市场导入插件即可
## 使用
```js
import {tinyColor} from '@/uni_modules/lime-color'
```
## 接受的字符串输入
字符串解析非常宽容。它的目的是使输入颜色尽可能简单。所有的逗号、百分比、括号都是可选的,大多数输入允许使用 0-1、0%-100% 或 0-n其中 n 取决于值的 100、255 或 360
HSL 和 HSV 都需要 0%-100% 或 0-1 作为 S/L/V 属性。H色相可以在 0%-100% 或 0-360 之间取值。
RGB 输入需要 0-255 或 0%-100%。
以下是一些字符串输入的示例:
### Hex, 8-digit (RGBA) Hex
```ts
tinyColor('#000');
tinyColor('000');
tinyColor('#369C');
tinyColor('369C');
tinyColor('#f0f0f6');
tinyColor('f0f0f6');
tinyColor('#f0f0f688');
tinyColor('f0f0f688');
```
### RGB, RGBA
```ts
tinyColor('rgb (255, 0, 0)');
tinyColor('rgb 255 0 0');
tinyColor('rgba (255, 0, 0, .5)');
tinyColor({ r: 255, g: 0, b: 0 });
```
### HSL, HSLA
```ts
tinyColor('hsl(0, 100%, 50%)');
tinyColor('hsla(0, 100%, 50%, .5)');
tinyColor('hsl(0, 100%, 50%)');
tinyColor('hsl 0 1.0 0.5');
tinyColor({ h: 0, s: 1, l: 0.5 });
```
### HSV, HSVA
```ts
tinyColor('hsv(0, 100%, 100%)');
tinyColor('hsva(0, 100%, 100%, .5)');
tinyColor('hsv (0 100% 100%)');
tinyColor('hsv 0 1 1');
tinyColor({ h: 0, s: 100, v: 100 });
```
### Named
```ts
tinyColor('RED');
tinyColor('blanchedalmond');
tinyColor('darkblue');
```
### Number
```ts
tinyColor(0x0);
tinyColor(0xaabbcc);
```
## 属性
### originalInput
传递到构造函数中用于创建`tinyColor`实例的原始输入。
```ts
const color = tinyColor('red');
color.originalInput; // "red"
const color2 = tinyColor({ r: 255, g: 255, b: 255 });
color2.originalInput; // "{r: 255, g: 255, b: 255}"
```
### format
返回用于创建`tinyColor`实例的格式
```ts
const color = tinyColor('red');
color.format; // "name"
const color2 = tinyColor({ r: 255, g: 255, b: 255 });
color2.format; // "rgb"
```
### isValid
一个布尔值,指示颜色是否成功被解析。注意:如果颜色无效,则在与其他方法一起使用时将表现得像“黑色”。
```ts
const color1 = tinyColor('red');
color1.isValid; // true
color1.toHexString(); // "#ff0000"
const color2 = tinyColor('not a color');
color2.isValid; // false
color2.toString(); // "#000000"
```
## Methods 方法
### getBrightness
返回颜色的感知亮度,范围从 0-255这是根据 [Web内容无障碍指南第1版](http://www.w3.org/TR/AERT#color-contrast) 定义的。
```ts
const color1 = tinyColor('#fff');
color1.getBrightness(); // 255
const color2 = tinyColor('#000');
color2.getBrightness(); // 0
```
### isLight
返回一个布尔值,指示颜色的感知亮度是否为浅色。
```ts
const color1 = tinyColor('#fff');
color1.isLight(); // true
const color2 = tinyColor('#000');
color2.isLight(); // false
```
### isDark
返回一个布尔值,指示颜色的感知亮度是否为深色。
```ts
const color1 = tinyColor('#fff');
color1.isDark(); // false
const color2 = tinyColor('#000');
color2.isDark(); // true
```
### getLuminance
返回颜色的感知亮度luminance范围从 0-1这是根据 [Web内容无障碍指南第2版](http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef) 定义的。
```ts
const color1 = tinyColor('#fff');
color1.getLuminance(); // 1
const color2 = tinyColor('#000');
color2.getLuminance(); // 0
```
### getAlpha
返回颜色的`alpha`(透明度)值,范围从 `0-1`
```ts
const color1 = tinyColor('rgba(255, 0, 0, .5)');
color1.getAlpha(); // 0.5
const color2 = tinyColor('rgb(255, 0, 0)');
color2.getAlpha(); // 1
const color3 = tinyColor('transparent');
color3.getAlpha(); // 0
```
### setAlpha
在当前颜色上设置`alpha`(透明度)值。接受的范围是 `0-1` 之间。
```ts
const color = tinyColor('red');
color.getAlpha(); // 1
color.setAlpha(0.5);
color.getAlpha(); // .5
color.toRgbString(); // "rgba(255, 0, 0, .5)"
```
### onBackground
计算颜色在背景上的显示效果。当颜色完全透明(即 `getAlpha() == 0`)时,结果将是背景颜色。当颜色完全不透明(即 `getAlpha() == 1`)时,结果将是颜色本身。否则,你将得到一个计算结果。
```ts
const color = tinyColor('rgba(255, 0, 0, .5)');
const computedColor = color.onBackground('rgb(0, 0, 255)');
computedColor.toRgbString(); // "rgb(128, 0, 128)"
```
### toHsv
```ts
const color = tinyColor('red');
color.toHsv(); // { h: 0, s: 1, v: 1, a: 1 }
```
### toHsvString
```ts
const color = tinyColor('red');
color.toHsvString(); // "hsv(0, 100%, 100%)"
color.setAlpha(0.5);
color.toHsvString(); // "hsva(0, 100%, 100%, 0.5)"
```
### toHsl
```ts
const color = tinyColor('red');
color.toHsl(); // { h: 0, s: 1, l: 0.5, a: 1 }
```
### toHslString
```ts
const color = tinyColor('red');
color.toHslString(); // "hsl(0, 100%, 50%)"
color.setAlpha(0.5);
color.toHslString(); // "hsla(0, 100%, 50%, 0.5)"
```
### toNumber
```ts
tinyColor('#aabbcc').toNumber() === 0xaabbcc // true
tinyColor('rgb(1, 1, 1)').toNumber() === (1 << 16) + (1 << 8) + 1 // true
```
### toHex
```ts
const color = tinyColor('red');
color.toHex(); // "ff0000"
```
### toHexString
```ts
const color = tinyColor('red');
color.toHexString(); // "#ff0000"
```
### toHex8
```ts
const color = tinyColor('red');
color.toHex8(); // "ff0000ff"
```
### toHex8String
```ts
const color = tinyColor('red');
color.toHex8String(); // "#ff0000ff"
```
### toHexShortString
根据颜色的透明度Alpha值返回较短的十六进制值并且值前面带有#符号
```ts
const color1 = tinyColor('#ff000000');
color1.toHexShortString(); // "#ff000000"
color1.toHexShortString(true); // "#f000"
const color2 = tinyColor('#ff0000ff');
color2.toHexShortString(); // "#ff0000"
color2.toHexShortString(true); // "#f00"
```
### toRgb
```ts
const color = tinyColor('red');
color.toRgb(); // { r: 255, g: 0, b: 0, a: 1 }
```
### toRgbString
```ts
const color = tinyColor('red');
color.toRgbString(); // "rgb(255, 0, 0)"
color.setAlpha(0.5);
color.toRgbString(); // "rgba(255, 0, 0, 0.5)"
```
### toPercentageRgb
将当前颜色转换为百分比表示的 RGB
```ts
const color = tinyColor('red');
color.toPercentageRgb(); // { r: "100%", g: "0%", b: "0%", a: 1 }
```
### toPercentageRgbString
```ts
const color = tinyColor('red');
color.toPercentageRgbString(); // "rgb(100%, 0%, 0%)"
color.setAlpha(0.5);
color.toPercentageRgbString(); // "rgba(100%, 0%, 0%, 0.5)"
```
### toName
```ts
const color = tinyColor('red');
color.toName(); // "red"
```
### toString
根据输入格式打印成字符串。你也可以通过向函数中传入以下之一来覆盖这个行为:`"rgb", "prgb", "hex6", "hex3", "hex8", "name", "hsl", "hsv"`
```ts
const color1 = tinyColor('red');
color1.toString(); // "red"
color1.toString('hsv'); // "hsv(0, 100%, 100%)"
const color2 = tinyColor('rgb(255, 0, 0)');
color2.toString(); // "rgb(255, 0, 0)"
color2.setAlpha(0.5);
color2.toString(); // "rgba(255, 0, 0, 0.5)"
```
### 颜色修改
这些方法操纵当前颜色,并返回它以进行链式调用。例如:
```ts
tinyColor('red')
.lighten()
.desaturate()
.toHexString(); // '#f53d3d'
```
### lighten
`lighten: function(amount = 10) -> TinyColor`.根据给定的量从0到100调亮颜色。提供100将始终返回白色.
```ts
tinyColor('#f00').lighten().toString(); // '#ff3333'
tinyColor('#f00').lighten(100).toString(); // '#ffffff'
```
### brighten
`brighten: function(amount = 10) -> TinyColor`. 根据给定的量从0到100提高颜色的亮度。
```ts
tinyColor('#f00').brighten().toString(); // '#ff1919'
```
### darken
`darken: function(amount = 10) -> TinyColor`. 根据给定的量从0到100调暗颜色。提供100将始终返回黑色.
```ts
tinyColor('#f00').darken().toString(); // '#cc0000'
tinyColor('#f00').darken(100).toString(); // '#000000'
```
### tint
将颜色与纯白色混合范围从0到100。提供0将不进行任何操作提供100将始终返回白色.
```ts
tinyColor('#f00').tint().toString(); // "#ff1a1a"
tinyColor('#f00').tint(100).toString(); // "#ffffff"
```
### shade
将颜色与纯黑色混合范围从0到100。提供0将不进行任何操作提供100将始终返回黑色。
```ts
tinyColor('#f00').shade().toString(); // "#e60000"
tinyColor('#f00').shade(100).toString(); // "#000000"
```
### desaturate
`desaturate: function(amount = 10) -> TinyColor`. 根据给定的量从0到100降低颜色的饱和度。提供100将与调用`greyscale`相同。
```ts
tinyColor('#f00').desaturate().toString(); // "#f20d0d"
tinyColor('#f00').desaturate(100).toString(); // "#808080"
```
### saturate
`saturate: function(amount = 10) -> TinyColor`. 根据给定的量从0到100增加颜色的饱和度。
```ts
tinyColor('hsl(0, 10%, 50%)').saturate().toString(); // "hsl(0, 20%, 50%)"
```
### greyscale
`greyscale: function() -> TinyColor`. 完全降低颜色的饱和度,使其变为灰度。与调用`desaturate(100)`相同。
```ts
tinyColor('#f00').greyscale().toString(); // "#808080"
```
### spin
`spin: function(amount = 0) -> TinyColor`. 根据给定的量(从-360到360旋转色相。调用时使用0、360或-360将不进行任何操作因为它将色相设置回原来的值
```ts
tinyColor('#f00').spin(180).toString(); // "#00ffff"
tinyColor('#f00').spin(-90).toString(); // "#7f00ff"
tinyColor('#f00').spin(90).toString(); // "#80ff00"
// spin(0) and spin(360) do nothing
tinyColor('#f00').spin(0).toString(); // "#ff0000"
tinyColor('#f00').spin(360).toString(); // "#ff0000"
```
### mix
`mix: function(amount = 50) => TinyColor`. 将当前颜色与另一种颜色按给定量从0到100混合。0表示不混合返回当前颜色
```ts
let color1 = tinyColor('#f0f');
let color2 = tinyColor('#0f0');
color1.mix(color2).toHexString(); // #808080
```
### 颜色组合
组合函数除非特别说明,否则返回一个`TinyColor`对象的数组。
### analogous
生成一组与当前颜色相似的颜色。
`analogous: function(results = 6, slices = 30) -> array<TinyColor>`.
```ts
const colors = tinyColor('#f00').analogous();
colors.map((t):string => t.toHexString()); // [ "#ff0000", "#ff0066", "#ff0033", "#ff0000", "#ff3300", "#ff6600" ]
```
### monochromatic
生成一组与当前颜色具有相同色相和饱和度的颜色。
`monochromatic: function(, results = 6) -> array<TinyColor>`.
```ts
const colors = tinyColor('#f00').monochromatic();
colors.map((t):string => t.toHexString()); // [ "#ff0000", "#2a0000", "#550000", "#800000", "#aa0000", "#d40000" ]
```
### splitcomplement
生成当前颜色的分裂补色。
`splitcomplement: function() -> array<TinyColor>`.
```ts
const colors = tinyColor('#f00').splitcomplement();
colors.map((t):string => t.toHexString()); // [ "#ff0000", "#ccff00", "#0066ff" ]
```
### triad
生成当前颜色的三色调。
`triad: function() -> array<TinyColor>`. Alias for `polyad(3)`.
```ts
const colors = tinyColor('#f00').triad();
colors.map((t):string => t.toHexString()); // [ "#ff0000", "#00ff00", "#0000ff" ]
```
### tetrad
生成当前颜色的四色调。
`tetrad: function() -> array<TinyColor>`. Alias for `polyad(4)`.
```ts
const colors = tinyColor('#f00').tetrad();
colors.map((t):string => t.toHexString()); // [ "#ff0000", "#80ff00", "#00ffff", "#7f00ff" ]
```
### polyad
生成当前颜色的 n 色调。
`polyad: function(number) -> array<TinyColor>`.
```ts
const colors = tinyColor('#f00').polyad(4);
colors.map((t):string => t.toHexString()); // [ "#ff0000", "#80ff00", "#00ffff", "#7f00ff" ]
```
### complement
计算当前颜色的补色。
`complement: function() -> TinyColor`.
```ts
tinyColor('#f00').complement().toHexString(); // "#00ffff"
```
## 颜色工具
### equals
判断两色是否相同
```ts
let color1 = tinyColor('red');
let color2 = tinyColor('#f00');
color1.equals(color2); // true
```
## 常见操作
### clone
`clone: function() -> TinyColor`.
使用相同的颜色实例化一个新的`TinyColor`对象。对新的对象的任何更改都不会影响旧的对象。
```ts
const color1 = tinyColor('#F00');
const color2 = color1.clone();
color2.setAlpha(0.5);
color1.toString(); // "#ff0000"
color2.toString(); // "rgba(255, 0, 0, 0.5)"
```
### generate
通过一个主色生成10个等级的颜色数组使用 Ant Design 的颜色生成算法。
```ts
import {generate, LGenerateOptions} from '@/uni_modules/lime-color'
// 第二个参数为选填,如果不填则默认为 'default'
generate('red',{ theme: 'default'|'dark'} as LGenerateOptions)
// ['#2c1113', '#450f11', '#5b0e0e', '#7e0b0b', '#ad0707', '#dc0303', '#e82d27', '#f3594f', '#f88577', '#faaca0']
```
## 打赏
如果你觉得本插件,解决了你的问题,赠人玫瑰,手留余香。
![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/alipay.png)
![](https://testingcf.jsdelivr.net/gh/liangei/image@1.9/wpay.png)

View File

@@ -0,0 +1,3 @@
{
"minSdkVersion": "21"
}

View File

@@ -0,0 +1,2 @@
export * from '../../common/color'
export * from '../../common/generate'

View File

@@ -0,0 +1,3 @@
{
"deploymentTarget": "9"
}

View File

@@ -0,0 +1,2 @@
export * from '../../common/color'
export * from '../../common/generate'

View File

@@ -0,0 +1,3 @@
export * from '../common/color'
export * from '../common/generate'
export * from './interface'

View File

@@ -0,0 +1,87 @@
export type RGB = {
r : number;
g : number;
b : number;
}
export type RGBA = {
r : number;
g : number;
b : number;
a : number;
}
export type RGBAString = {
r : string;
g : string;
b : string;
a : number;
}
export type HSL = {
h : number;
s : number;
l : number;
}
export type HSLA = {
h : number;
s : number;
l : number;
a : number;
}
export type HSV = {
h : number;
s : number;
v : number;
}
export type HSVA = {
h : number;
s : number;
v : number;
a : number;
}
// 增加部分
export type HSB = {
h : number;
s : number;
b : number;
}
export type HSBA = {
h : number;
s : number;
b : number;
a : number;
}
export type LColorInfo = {
ok ?: boolean;
format ?: LColorFormats;
r : number;
g : number;
b : number;
a : number;
}
export type LColorFormats =
| 'rgb'
| 'prgb'
| 'hex'
| 'hex3'
| 'hex4'
| 'hex6'
| 'hex8'
| 'name'
| 'hsl'
| 'hsb'
| 'hsv';
export type LColorOptions = {
format ?: LColorFormats;
gradientType ?: string;
}
export type LColorInput = any //string | number | RGB | RGBA | HSL | HSLA | HSV | HSVA | LimeColor;
export type LGenerateOptions = {
theme ?: 'dark' | 'default';
backgroundColor ?: string;
}

View File

@@ -0,0 +1,41 @@
/* 此规范为 uni 规范,可以按照自己的需要选择是否实现 */
import { MyApiErrorCode, MyApiFail } from "./interface.uts"
/**
* 错误主题
* 注意:错误主题一般为插件名称,每个组件不同,需要使用时请更改。
* [可选实现]
*/
export const UniErrorSubject = 'uts-api';
/**
* 错误信息
* @UniError
* [可选实现]
*/
export const UniErrors : Map<MyApiErrorCode, string> = new Map([
/**
* 错误码及对应的错误信息
*/
[9010001, 'custom error mseeage1'],
[9010002, 'custom error mseeage2'],
]);
/**
* 错误对象实现
*/
export class MyApiFailImpl extends UniError implements MyApiFail {
/**
* 错误对象构造函数
*/
constructor(errCode : MyApiErrorCode) {
super();
this.errSubject = UniErrorSubject;
this.errCode = errCode;
this.errMsg = UniErrors[errCode] ?? "";
}
}