first commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# 1.0.0 - 2016-01-07
|
||||
|
||||
- Removed: unused speed test
|
||||
- Added: Automatic routing between previously unsupported conversions
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Removed: `xxx2xxx()` and `xxx2xxxRaw()` functions
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Removed: `convert()` class
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Changed: all functions to lookup dictionary
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Changed: `ansi` to `ansi256`
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
- Fixed: argument grouping for functions requiring only one argument
|
||||
([#27](https://github.com/Qix-/color-convert/pull/27))
|
||||
|
||||
# 0.6.0 - 2015-07-23
|
||||
|
||||
- Added: methods to handle
|
||||
[ANSI](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors) 16/256 colors:
|
||||
- rgb2ansi16
|
||||
- rgb2ansi
|
||||
- hsl2ansi16
|
||||
- hsl2ansi
|
||||
- hsv2ansi16
|
||||
- hsv2ansi
|
||||
- hwb2ansi16
|
||||
- hwb2ansi
|
||||
- cmyk2ansi16
|
||||
- cmyk2ansi
|
||||
- keyword2ansi16
|
||||
- keyword2ansi
|
||||
- ansi162rgb
|
||||
- ansi162hsl
|
||||
- ansi162hsv
|
||||
- ansi162hwb
|
||||
- ansi162cmyk
|
||||
- ansi162keyword
|
||||
- ansi2rgb
|
||||
- ansi2hsl
|
||||
- ansi2hsv
|
||||
- ansi2hwb
|
||||
- ansi2cmyk
|
||||
- ansi2keyword
|
||||
([#18](https://github.com/harthur/color-convert/pull/18))
|
||||
|
||||
# 0.5.3 - 2015-06-02
|
||||
|
||||
- Fixed: hsl2hsv does not return `NaN` anymore when using `[0,0,0]`
|
||||
([#15](https://github.com/harthur/color-convert/issues/15))
|
||||
|
||||
---
|
||||
|
||||
Check out commit logs for older releases
|
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2011-2016 Heather Arthur <fayearthur@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
@@ -0,0 +1,68 @@
|
||||
# color-convert
|
||||
|
||||
[](https://travis-ci.org/Qix-/color-convert)
|
||||
|
||||
Color-convert is a color conversion library for JavaScript and node.
|
||||
It converts all ways between `rgb`, `hsl`, `hsv`, `hwb`, `cmyk`, `ansi`, `ansi16`, `hex` strings, and CSS `keyword`s (will round to closest):
|
||||
|
||||
```js
|
||||
var convert = require('color-convert');
|
||||
|
||||
convert.rgb.hsl(140, 200, 100); // [96, 48, 59]
|
||||
convert.keyword.rgb('blue'); // [0, 0, 255]
|
||||
|
||||
var rgbChannels = convert.rgb.channels; // 3
|
||||
var cmykChannels = convert.cmyk.channels; // 4
|
||||
var ansiChannels = convert.ansi16.channels; // 1
|
||||
```
|
||||
|
||||
# Install
|
||||
|
||||
```console
|
||||
$ npm install color-convert
|
||||
```
|
||||
|
||||
# API
|
||||
|
||||
Simply get the property of the _from_ and _to_ conversion that you're looking for.
|
||||
|
||||
All functions have a rounded and unrounded variant. By default, return values are rounded. To get the unrounded (raw) results, simply tack on `.raw` to the function.
|
||||
|
||||
All 'from' functions have a hidden property called `.channels` that indicates the number of channels the function expects (not including alpha).
|
||||
|
||||
```js
|
||||
var convert = require('color-convert');
|
||||
|
||||
// Hex to LAB
|
||||
convert.hex.lab('DEADBF'); // [ 76, 21, -2 ]
|
||||
convert.hex.lab.raw('DEADBF'); // [ 75.56213190997677, 20.653827952644754, -2.290532499330533 ]
|
||||
|
||||
// RGB to CMYK
|
||||
convert.rgb.cmyk(167, 255, 4); // [ 35, 0, 98, 0 ]
|
||||
convert.rgb.cmyk.raw(167, 255, 4); // [ 34.509803921568626, 0, 98.43137254901961, 0 ]
|
||||
```
|
||||
|
||||
### Arrays
|
||||
All functions that accept multiple arguments also support passing an array.
|
||||
|
||||
Note that this does **not** apply to functions that convert from a color that only requires one value (e.g. `keyword`, `ansi256`, `hex`, etc.)
|
||||
|
||||
```js
|
||||
var convert = require('color-convert');
|
||||
|
||||
convert.rgb.hex(123, 45, 67); // '7B2D43'
|
||||
convert.rgb.hex([123, 45, 67]); // '7B2D43'
|
||||
```
|
||||
|
||||
## Routing
|
||||
|
||||
Conversions that don't have an _explicitly_ defined conversion (in [conversions.js](conversions.js)), but can be converted by means of sub-conversions (e.g. XYZ -> **RGB** -> CMYK), are automatically routed together. This allows just about any color model supported by `color-convert` to be converted to any other model, so long as a sub-conversion path exists. This is also true for conversions requiring more than one step in between (e.g. LCH -> **LAB** -> **XYZ** -> **RGB** -> Hex).
|
||||
|
||||
Keep in mind that extensive conversions _may_ result in a loss of precision, and exist only to be complete. For a list of "direct" (single-step) conversions, see [conversions.js](conversions.js).
|
||||
|
||||
# Contribute
|
||||
|
||||
If there is a new model you would like to support, or want to add a direct conversion between two existing models, please send us a pull request.
|
||||
|
||||
# License
|
||||
Copyright © 2011-2016, Heather Arthur and Josh Junon. Licensed under the [MIT License](LICENSE).
|
@@ -0,0 +1,839 @@
|
||||
/* MIT license */
|
||||
/* eslint-disable no-mixed-operators */
|
||||
import cssKeywords from '../color-name';
|
||||
|
||||
// NOTE: conversions should only return primitive values (i.e. arrays, or
|
||||
// values that give correct `typeof` results).
|
||||
// do not use box values types (i.e. Number(), String(), etc.)
|
||||
|
||||
const reverseKeywords = {};
|
||||
for (const key of Object.keys(cssKeywords)) {
|
||||
reverseKeywords[cssKeywords[key]] = key;
|
||||
}
|
||||
|
||||
const convert = {
|
||||
rgb: {channels: 3, labels: 'rgb'},
|
||||
hsl: {channels: 3, labels: 'hsl'},
|
||||
hsv: {channels: 3, labels: 'hsv'},
|
||||
hwb: {channels: 3, labels: 'hwb'},
|
||||
cmyk: {channels: 4, labels: 'cmyk'},
|
||||
xyz: {channels: 3, labels: 'xyz'},
|
||||
lab: {channels: 3, labels: 'lab'},
|
||||
lch: {channels: 3, labels: 'lch'},
|
||||
hex: {channels: 1, labels: ['hex']},
|
||||
keyword: {channels: 1, labels: ['keyword']},
|
||||
ansi16: {channels: 1, labels: ['ansi16']},
|
||||
ansi256: {channels: 1, labels: ['ansi256']},
|
||||
hcg: {channels: 3, labels: ['h', 'c', 'g']},
|
||||
apple: {channels: 3, labels: ['r16', 'g16', 'b16']},
|
||||
gray: {channels: 1, labels: ['gray']}
|
||||
};
|
||||
|
||||
export default convert;
|
||||
|
||||
// Hide .channels and .labels properties
|
||||
for (const model of Object.keys(convert)) {
|
||||
if (!('channels' in convert[model])) {
|
||||
throw new Error('missing channels property: ' + model);
|
||||
}
|
||||
|
||||
if (!('labels' in convert[model])) {
|
||||
throw new Error('missing channel labels property: ' + model);
|
||||
}
|
||||
|
||||
if (convert[model].labels.length !== convert[model].channels) {
|
||||
throw new Error('channel and label counts mismatch: ' + model);
|
||||
}
|
||||
|
||||
const {channels, labels} = convert[model];
|
||||
delete convert[model].channels;
|
||||
delete convert[model].labels;
|
||||
Object.defineProperty(convert[model], 'channels', {value: channels});
|
||||
Object.defineProperty(convert[model], 'labels', {value: labels});
|
||||
}
|
||||
|
||||
convert.rgb.hsl = function (rgb) {
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
const min = Math.min(r, g, b);
|
||||
const max = Math.max(r, g, b);
|
||||
const delta = max - min;
|
||||
let h;
|
||||
let s;
|
||||
|
||||
if (max === min) {
|
||||
h = 0;
|
||||
} else if (r === max) {
|
||||
h = (g - b) / delta;
|
||||
} else if (g === max) {
|
||||
h = 2 + (b - r) / delta;
|
||||
} else if (b === max) {
|
||||
h = 4 + (r - g) / delta;
|
||||
}
|
||||
|
||||
h = Math.min(h * 60, 360);
|
||||
|
||||
if (h < 0) {
|
||||
h += 360;
|
||||
}
|
||||
|
||||
const l = (min + max) / 2;
|
||||
|
||||
if (max === min) {
|
||||
s = 0;
|
||||
} else if (l <= 0.5) {
|
||||
s = delta / (max + min);
|
||||
} else {
|
||||
s = delta / (2 - max - min);
|
||||
}
|
||||
|
||||
return [h, s * 100, l * 100];
|
||||
};
|
||||
|
||||
convert.rgb.hsv = function (rgb) {
|
||||
let rdif;
|
||||
let gdif;
|
||||
let bdif;
|
||||
let h;
|
||||
let s;
|
||||
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
const v = Math.max(r, g, b);
|
||||
const diff = v - Math.min(r, g, b);
|
||||
const diffc = function (c) {
|
||||
return (v - c) / 6 / diff + 1 / 2;
|
||||
};
|
||||
|
||||
if (diff === 0) {
|
||||
h = 0;
|
||||
s = 0;
|
||||
} else {
|
||||
s = diff / v;
|
||||
rdif = diffc(r);
|
||||
gdif = diffc(g);
|
||||
bdif = diffc(b);
|
||||
|
||||
if (r === v) {
|
||||
h = bdif - gdif;
|
||||
} else if (g === v) {
|
||||
h = (1 / 3) + rdif - bdif;
|
||||
} else if (b === v) {
|
||||
h = (2 / 3) + gdif - rdif;
|
||||
}
|
||||
|
||||
if (h < 0) {
|
||||
h += 1;
|
||||
} else if (h > 1) {
|
||||
h -= 1;
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
h * 360,
|
||||
s * 100,
|
||||
v * 100
|
||||
];
|
||||
};
|
||||
|
||||
convert.rgb.hwb = function (rgb) {
|
||||
const r = rgb[0];
|
||||
const g = rgb[1];
|
||||
let b = rgb[2];
|
||||
const h = convert.rgb.hsl(rgb)[0];
|
||||
const w = 1 / 255 * Math.min(r, Math.min(g, b));
|
||||
|
||||
b = 1 - 1 / 255 * Math.max(r, Math.max(g, b));
|
||||
|
||||
return [h, w * 100, b * 100];
|
||||
};
|
||||
|
||||
convert.rgb.cmyk = function (rgb) {
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
|
||||
const k = Math.min(1 - r, 1 - g, 1 - b);
|
||||
const c = (1 - r - k) / (1 - k) || 0;
|
||||
const m = (1 - g - k) / (1 - k) || 0;
|
||||
const y = (1 - b - k) / (1 - k) || 0;
|
||||
|
||||
return [c * 100, m * 100, y * 100, k * 100];
|
||||
};
|
||||
|
||||
function comparativeDistance(x, y) {
|
||||
/*
|
||||
See https://en.m.wikipedia.org/wiki/Euclidean_distance#Squared_Euclidean_distance
|
||||
*/
|
||||
return (
|
||||
((x[0] - y[0]) ** 2) +
|
||||
((x[1] - y[1]) ** 2) +
|
||||
((x[2] - y[2]) ** 2)
|
||||
);
|
||||
}
|
||||
|
||||
convert.rgb.keyword = function (rgb) {
|
||||
const reversed = reverseKeywords[rgb];
|
||||
if (reversed) {
|
||||
return reversed;
|
||||
}
|
||||
|
||||
let currentClosestDistance = Infinity;
|
||||
let currentClosestKeyword;
|
||||
|
||||
for (const keyword of Object.keys(cssKeywords)) {
|
||||
const value = cssKeywords[keyword];
|
||||
|
||||
// Compute comparative distance
|
||||
const distance = comparativeDistance(rgb, value);
|
||||
|
||||
// Check if its less, if so set as closest
|
||||
if (distance < currentClosestDistance) {
|
||||
currentClosestDistance = distance;
|
||||
currentClosestKeyword = keyword;
|
||||
}
|
||||
}
|
||||
|
||||
return currentClosestKeyword;
|
||||
};
|
||||
|
||||
convert.keyword.rgb = function (keyword) {
|
||||
return cssKeywords[keyword];
|
||||
};
|
||||
|
||||
convert.rgb.xyz = function (rgb) {
|
||||
let r = rgb[0] / 255;
|
||||
let g = rgb[1] / 255;
|
||||
let b = rgb[2] / 255;
|
||||
|
||||
// Assume sRGB
|
||||
r = r > 0.04045 ? (((r + 0.055) / 1.055) ** 2.4) : (r / 12.92);
|
||||
g = g > 0.04045 ? (((g + 0.055) / 1.055) ** 2.4) : (g / 12.92);
|
||||
b = b > 0.04045 ? (((b + 0.055) / 1.055) ** 2.4) : (b / 12.92);
|
||||
|
||||
const x = (r * 0.4124) + (g * 0.3576) + (b * 0.1805);
|
||||
const y = (r * 0.2126) + (g * 0.7152) + (b * 0.0722);
|
||||
const z = (r * 0.0193) + (g * 0.1192) + (b * 0.9505);
|
||||
|
||||
return [x * 100, y * 100, z * 100];
|
||||
};
|
||||
|
||||
convert.rgb.lab = function (rgb) {
|
||||
const xyz = convert.rgb.xyz(rgb);
|
||||
let x = xyz[0];
|
||||
let y = xyz[1];
|
||||
let z = xyz[2];
|
||||
|
||||
x /= 95.047;
|
||||
y /= 100;
|
||||
z /= 108.883;
|
||||
|
||||
x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);
|
||||
y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);
|
||||
z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);
|
||||
|
||||
const l = (116 * y) - 16;
|
||||
const a = 500 * (x - y);
|
||||
const b = 200 * (y - z);
|
||||
|
||||
return [l, a, b];
|
||||
};
|
||||
|
||||
convert.hsl.rgb = function (hsl) {
|
||||
const h = hsl[0] / 360;
|
||||
const s = hsl[1] / 100;
|
||||
const l = hsl[2] / 100;
|
||||
let t2;
|
||||
let t3;
|
||||
let val;
|
||||
|
||||
if (s === 0) {
|
||||
val = l * 255;
|
||||
return [val, val, val];
|
||||
}
|
||||
|
||||
if (l < 0.5) {
|
||||
t2 = l * (1 + s);
|
||||
} else {
|
||||
t2 = l + s - l * s;
|
||||
}
|
||||
|
||||
const t1 = 2 * l - t2;
|
||||
|
||||
const rgb = [0, 0, 0];
|
||||
for (let i = 0; i < 3; i++) {
|
||||
t3 = h + 1 / 3 * -(i - 1);
|
||||
if (t3 < 0) {
|
||||
t3++;
|
||||
}
|
||||
|
||||
if (t3 > 1) {
|
||||
t3--;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
rgb[i] = val * 255;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
};
|
||||
|
||||
convert.hsl.hsv = function (hsl) {
|
||||
const h = hsl[0];
|
||||
let s = hsl[1] / 100;
|
||||
let l = hsl[2] / 100;
|
||||
let smin = s;
|
||||
const lmin = Math.max(l, 0.01);
|
||||
|
||||
l *= 2;
|
||||
s *= (l <= 1) ? l : 2 - l;
|
||||
smin *= lmin <= 1 ? lmin : 2 - lmin;
|
||||
const v = (l + s) / 2;
|
||||
const sv = l === 0 ? (2 * smin) / (lmin + smin) : (2 * s) / (l + s);
|
||||
|
||||
return [h, sv * 100, v * 100];
|
||||
};
|
||||
|
||||
convert.hsv.rgb = function (hsv) {
|
||||
const h = hsv[0] / 60;
|
||||
const s = hsv[1] / 100;
|
||||
let v = hsv[2] / 100;
|
||||
const hi = Math.floor(h) % 6;
|
||||
|
||||
const f = h - Math.floor(h);
|
||||
const p = 255 * v * (1 - s);
|
||||
const q = 255 * v * (1 - (s * f));
|
||||
const t = 255 * v * (1 - (s * (1 - f)));
|
||||
v *= 255;
|
||||
|
||||
switch (hi) {
|
||||
case 0:
|
||||
return [v, t, p];
|
||||
case 1:
|
||||
return [q, v, p];
|
||||
case 2:
|
||||
return [p, v, t];
|
||||
case 3:
|
||||
return [p, q, v];
|
||||
case 4:
|
||||
return [t, p, v];
|
||||
case 5:
|
||||
return [v, p, q];
|
||||
}
|
||||
};
|
||||
|
||||
convert.hsv.hsl = function (hsv) {
|
||||
const h = hsv[0];
|
||||
const s = hsv[1] / 100;
|
||||
const v = hsv[2] / 100;
|
||||
const vmin = Math.max(v, 0.01);
|
||||
let sl;
|
||||
let l;
|
||||
|
||||
l = (2 - s) * v;
|
||||
const lmin = (2 - s) * vmin;
|
||||
sl = s * vmin;
|
||||
sl /= (lmin <= 1) ? lmin : 2 - lmin;
|
||||
sl = sl || 0;
|
||||
l /= 2;
|
||||
|
||||
return [h, sl * 100, l * 100];
|
||||
};
|
||||
|
||||
// http://dev.w3.org/csswg/css-color/#hwb-to-rgb
|
||||
convert.hwb.rgb = function (hwb) {
|
||||
const h = hwb[0] / 360;
|
||||
let wh = hwb[1] / 100;
|
||||
let bl = hwb[2] / 100;
|
||||
const ratio = wh + bl;
|
||||
let f;
|
||||
|
||||
// Wh + bl cant be > 1
|
||||
if (ratio > 1) {
|
||||
wh /= ratio;
|
||||
bl /= ratio;
|
||||
}
|
||||
|
||||
const i = Math.floor(6 * h);
|
||||
const v = 1 - bl;
|
||||
f = 6 * h - i;
|
||||
|
||||
if ((i & 0x01) !== 0) {
|
||||
f = 1 - f;
|
||||
}
|
||||
|
||||
const n = wh + f * (v - wh); // Linear interpolation
|
||||
|
||||
let r;
|
||||
let g;
|
||||
let b;
|
||||
/* eslint-disable max-statements-per-line,no-multi-spaces */
|
||||
switch (i) {
|
||||
default:
|
||||
case 6:
|
||||
case 0: r = v; g = n; b = wh; break;
|
||||
case 1: r = n; g = v; b = wh; break;
|
||||
case 2: r = wh; g = v; b = n; break;
|
||||
case 3: r = wh; g = n; b = v; break;
|
||||
case 4: r = n; g = wh; b = v; break;
|
||||
case 5: r = v; g = wh; b = n; break;
|
||||
}
|
||||
/* eslint-enable max-statements-per-line,no-multi-spaces */
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
};
|
||||
|
||||
convert.cmyk.rgb = function (cmyk) {
|
||||
const c = cmyk[0] / 100;
|
||||
const m = cmyk[1] / 100;
|
||||
const y = cmyk[2] / 100;
|
||||
const k = cmyk[3] / 100;
|
||||
|
||||
const r = 1 - Math.min(1, c * (1 - k) + k);
|
||||
const g = 1 - Math.min(1, m * (1 - k) + k);
|
||||
const b = 1 - Math.min(1, y * (1 - k) + k);
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
};
|
||||
|
||||
convert.xyz.rgb = function (xyz) {
|
||||
const x = xyz[0] / 100;
|
||||
const y = xyz[1] / 100;
|
||||
const z = xyz[2] / 100;
|
||||
let r;
|
||||
let g;
|
||||
let b;
|
||||
|
||||
r = (x * 3.2406) + (y * -1.5372) + (z * -0.4986);
|
||||
g = (x * -0.9689) + (y * 1.8758) + (z * 0.0415);
|
||||
b = (x * 0.0557) + (y * -0.2040) + (z * 1.0570);
|
||||
|
||||
// Assume sRGB
|
||||
r = r > 0.0031308
|
||||
? ((1.055 * (r ** (1.0 / 2.4))) - 0.055)
|
||||
: r * 12.92;
|
||||
|
||||
g = g > 0.0031308
|
||||
? ((1.055 * (g ** (1.0 / 2.4))) - 0.055)
|
||||
: g * 12.92;
|
||||
|
||||
b = b > 0.0031308
|
||||
? ((1.055 * (b ** (1.0 / 2.4))) - 0.055)
|
||||
: b * 12.92;
|
||||
|
||||
r = Math.min(Math.max(0, r), 1);
|
||||
g = Math.min(Math.max(0, g), 1);
|
||||
b = Math.min(Math.max(0, b), 1);
|
||||
|
||||
return [r * 255, g * 255, b * 255];
|
||||
};
|
||||
|
||||
convert.xyz.lab = function (xyz) {
|
||||
let x = xyz[0];
|
||||
let y = xyz[1];
|
||||
let z = xyz[2];
|
||||
|
||||
x /= 95.047;
|
||||
y /= 100;
|
||||
z /= 108.883;
|
||||
|
||||
x = x > 0.008856 ? (x ** (1 / 3)) : (7.787 * x) + (16 / 116);
|
||||
y = y > 0.008856 ? (y ** (1 / 3)) : (7.787 * y) + (16 / 116);
|
||||
z = z > 0.008856 ? (z ** (1 / 3)) : (7.787 * z) + (16 / 116);
|
||||
|
||||
const l = (116 * y) - 16;
|
||||
const a = 500 * (x - y);
|
||||
const b = 200 * (y - z);
|
||||
|
||||
return [l, a, b];
|
||||
};
|
||||
|
||||
convert.lab.xyz = function (lab) {
|
||||
const l = lab[0];
|
||||
const a = lab[1];
|
||||
const b = lab[2];
|
||||
let x;
|
||||
let y;
|
||||
let z;
|
||||
|
||||
y = (l + 16) / 116;
|
||||
x = a / 500 + y;
|
||||
z = y - b / 200;
|
||||
|
||||
const y2 = y ** 3;
|
||||
const x2 = x ** 3;
|
||||
const z2 = z ** 3;
|
||||
y = y2 > 0.008856 ? y2 : (y - 16 / 116) / 7.787;
|
||||
x = x2 > 0.008856 ? x2 : (x - 16 / 116) / 7.787;
|
||||
z = z2 > 0.008856 ? z2 : (z - 16 / 116) / 7.787;
|
||||
|
||||
x *= 95.047;
|
||||
y *= 100;
|
||||
z *= 108.883;
|
||||
|
||||
return [x, y, z];
|
||||
};
|
||||
|
||||
convert.lab.lch = function (lab) {
|
||||
const l = lab[0];
|
||||
const a = lab[1];
|
||||
const b = lab[2];
|
||||
let h;
|
||||
|
||||
const hr = Math.atan2(b, a);
|
||||
h = hr * 360 / 2 / Math.PI;
|
||||
|
||||
if (h < 0) {
|
||||
h += 360;
|
||||
}
|
||||
|
||||
const c = Math.sqrt(a * a + b * b);
|
||||
|
||||
return [l, c, h];
|
||||
};
|
||||
|
||||
convert.lch.lab = function (lch) {
|
||||
const l = lch[0];
|
||||
const c = lch[1];
|
||||
const h = lch[2];
|
||||
|
||||
const hr = h / 360 * 2 * Math.PI;
|
||||
const a = c * Math.cos(hr);
|
||||
const b = c * Math.sin(hr);
|
||||
|
||||
return [l, a, b];
|
||||
};
|
||||
|
||||
convert.rgb.ansi16 = function (args, saturation = null) {
|
||||
const [r, g, b] = args;
|
||||
let value = saturation === null ? convert.rgb.hsv(args)[2] : saturation; // Hsv -> ansi16 optimization
|
||||
|
||||
value = Math.round(value / 50);
|
||||
|
||||
if (value === 0) {
|
||||
return 30;
|
||||
}
|
||||
|
||||
let ansi = 30
|
||||
+ ((Math.round(b / 255) << 2)
|
||||
| (Math.round(g / 255) << 1)
|
||||
| Math.round(r / 255));
|
||||
|
||||
if (value === 2) {
|
||||
ansi += 60;
|
||||
}
|
||||
|
||||
return ansi;
|
||||
};
|
||||
|
||||
convert.hsv.ansi16 = function (args) {
|
||||
// Optimization here; we already know the value and don't need to get
|
||||
// it converted for us.
|
||||
return convert.rgb.ansi16(convert.hsv.rgb(args), args[2]);
|
||||
};
|
||||
|
||||
convert.rgb.ansi256 = function (args) {
|
||||
const r = args[0];
|
||||
const g = args[1];
|
||||
const b = args[2];
|
||||
|
||||
// We use the extended greyscale palette here, with the exception of
|
||||
// black and white. normal palette only has 4 greyscale shades.
|
||||
if (r === g && g === b) {
|
||||
if (r < 8) {
|
||||
return 16;
|
||||
}
|
||||
|
||||
if (r > 248) {
|
||||
return 231;
|
||||
}
|
||||
|
||||
return Math.round(((r - 8) / 247) * 24) + 232;
|
||||
}
|
||||
|
||||
const ansi = 16
|
||||
+ (36 * Math.round(r / 255 * 5))
|
||||
+ (6 * Math.round(g / 255 * 5))
|
||||
+ Math.round(b / 255 * 5);
|
||||
|
||||
return ansi;
|
||||
};
|
||||
|
||||
convert.ansi16.rgb = function (args) {
|
||||
let color = args % 10;
|
||||
|
||||
// Handle greyscale
|
||||
if (color === 0 || color === 7) {
|
||||
if (args > 50) {
|
||||
color += 3.5;
|
||||
}
|
||||
|
||||
color = color / 10.5 * 255;
|
||||
|
||||
return [color, color, color];
|
||||
}
|
||||
|
||||
const mult = (~~(args > 50) + 1) * 0.5;
|
||||
const r = ((color & 1) * mult) * 255;
|
||||
const g = (((color >> 1) & 1) * mult) * 255;
|
||||
const b = (((color >> 2) & 1) * mult) * 255;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
convert.ansi256.rgb = function (args) {
|
||||
// Handle greyscale
|
||||
if (args >= 232) {
|
||||
const c = (args - 232) * 10 + 8;
|
||||
return [c, c, c];
|
||||
}
|
||||
|
||||
args -= 16;
|
||||
|
||||
let rem;
|
||||
const r = Math.floor(args / 36) / 5 * 255;
|
||||
const g = Math.floor((rem = args % 36) / 6) / 5 * 255;
|
||||
const b = (rem % 6) / 5 * 255;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
convert.rgb.hex = function (args) {
|
||||
const integer = ((Math.round(args[0]) & 0xFF) << 16)
|
||||
+ ((Math.round(args[1]) & 0xFF) << 8)
|
||||
+ (Math.round(args[2]) & 0xFF);
|
||||
|
||||
const string = integer.toString(16).toUpperCase();
|
||||
return '000000'.substring(string.length) + string;
|
||||
};
|
||||
|
||||
convert.hex.rgb = function (args) {
|
||||
const match = args.toString(16).match(/[a-f0-9]{6}|[a-f0-9]{3}/i);
|
||||
if (!match) {
|
||||
return [0, 0, 0];
|
||||
}
|
||||
|
||||
let colorString = match[0];
|
||||
|
||||
if (match[0].length === 3) {
|
||||
colorString = colorString.split('').map(char => {
|
||||
return char + char;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
const integer = parseInt(colorString, 16);
|
||||
const r = (integer >> 16) & 0xFF;
|
||||
const g = (integer >> 8) & 0xFF;
|
||||
const b = integer & 0xFF;
|
||||
|
||||
return [r, g, b];
|
||||
};
|
||||
|
||||
convert.rgb.hcg = function (rgb) {
|
||||
const r = rgb[0] / 255;
|
||||
const g = rgb[1] / 255;
|
||||
const b = rgb[2] / 255;
|
||||
const max = Math.max(Math.max(r, g), b);
|
||||
const min = Math.min(Math.min(r, g), b);
|
||||
const chroma = (max - min);
|
||||
let grayscale;
|
||||
let hue;
|
||||
|
||||
if (chroma < 1) {
|
||||
grayscale = min / (1 - chroma);
|
||||
} else {
|
||||
grayscale = 0;
|
||||
}
|
||||
|
||||
if (chroma <= 0) {
|
||||
hue = 0;
|
||||
} else
|
||||
if (max === r) {
|
||||
hue = ((g - b) / chroma) % 6;
|
||||
} else
|
||||
if (max === g) {
|
||||
hue = 2 + (b - r) / chroma;
|
||||
} else {
|
||||
hue = 4 + (r - g) / chroma;
|
||||
}
|
||||
|
||||
hue /= 6;
|
||||
hue %= 1;
|
||||
|
||||
return [hue * 360, chroma * 100, grayscale * 100];
|
||||
};
|
||||
|
||||
convert.hsl.hcg = function (hsl) {
|
||||
const s = hsl[1] / 100;
|
||||
const l = hsl[2] / 100;
|
||||
|
||||
const c = l < 0.5 ? (2.0 * s * l) : (2.0 * s * (1.0 - l));
|
||||
|
||||
let f = 0;
|
||||
if (c < 1.0) {
|
||||
f = (l - 0.5 * c) / (1.0 - c);
|
||||
}
|
||||
|
||||
return [hsl[0], c * 100, f * 100];
|
||||
};
|
||||
|
||||
convert.hsv.hcg = function (hsv) {
|
||||
const s = hsv[1] / 100;
|
||||
const v = hsv[2] / 100;
|
||||
|
||||
const c = s * v;
|
||||
let f = 0;
|
||||
|
||||
if (c < 1.0) {
|
||||
f = (v - c) / (1 - c);
|
||||
}
|
||||
|
||||
return [hsv[0], c * 100, f * 100];
|
||||
};
|
||||
|
||||
convert.hcg.rgb = function (hcg) {
|
||||
const h = hcg[0] / 360;
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
|
||||
if (c === 0.0) {
|
||||
return [g * 255, g * 255, g * 255];
|
||||
}
|
||||
|
||||
const pure = [0, 0, 0];
|
||||
const hi = (h % 1) * 6;
|
||||
const v = hi % 1;
|
||||
const w = 1 - v;
|
||||
let mg = 0;
|
||||
|
||||
/* eslint-disable max-statements-per-line */
|
||||
switch (Math.floor(hi)) {
|
||||
case 0:
|
||||
pure[0] = 1; pure[1] = v; pure[2] = 0; break;
|
||||
case 1:
|
||||
pure[0] = w; pure[1] = 1; pure[2] = 0; break;
|
||||
case 2:
|
||||
pure[0] = 0; pure[1] = 1; pure[2] = v; break;
|
||||
case 3:
|
||||
pure[0] = 0; pure[1] = w; pure[2] = 1; break;
|
||||
case 4:
|
||||
pure[0] = v; pure[1] = 0; pure[2] = 1; break;
|
||||
default:
|
||||
pure[0] = 1; pure[1] = 0; pure[2] = w;
|
||||
}
|
||||
/* eslint-enable max-statements-per-line */
|
||||
|
||||
mg = (1.0 - c) * g;
|
||||
|
||||
return [
|
||||
(c * pure[0] + mg) * 255,
|
||||
(c * pure[1] + mg) * 255,
|
||||
(c * pure[2] + mg) * 255
|
||||
];
|
||||
};
|
||||
|
||||
convert.hcg.hsv = function (hcg) {
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
|
||||
const v = c + g * (1.0 - c);
|
||||
let f = 0;
|
||||
|
||||
if (v > 0.0) {
|
||||
f = c / v;
|
||||
}
|
||||
|
||||
return [hcg[0], f * 100, v * 100];
|
||||
};
|
||||
|
||||
convert.hcg.hsl = function (hcg) {
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
|
||||
const l = g * (1.0 - c) + 0.5 * c;
|
||||
let s = 0;
|
||||
|
||||
if (l > 0.0 && l < 0.5) {
|
||||
s = c / (2 * l);
|
||||
} else
|
||||
if (l >= 0.5 && l < 1.0) {
|
||||
s = c / (2 * (1 - l));
|
||||
}
|
||||
|
||||
return [hcg[0], s * 100, l * 100];
|
||||
};
|
||||
|
||||
convert.hcg.hwb = function (hcg) {
|
||||
const c = hcg[1] / 100;
|
||||
const g = hcg[2] / 100;
|
||||
const v = c + g * (1.0 - c);
|
||||
return [hcg[0], (v - c) * 100, (1 - v) * 100];
|
||||
};
|
||||
|
||||
convert.hwb.hcg = function (hwb) {
|
||||
const w = hwb[1] / 100;
|
||||
const b = hwb[2] / 100;
|
||||
const v = 1 - b;
|
||||
const c = v - w;
|
||||
let g = 0;
|
||||
|
||||
if (c < 1) {
|
||||
g = (v - c) / (1 - c);
|
||||
}
|
||||
|
||||
return [hwb[0], c * 100, g * 100];
|
||||
};
|
||||
|
||||
convert.apple.rgb = function (apple) {
|
||||
return [(apple[0] / 65535) * 255, (apple[1] / 65535) * 255, (apple[2] / 65535) * 255];
|
||||
};
|
||||
|
||||
convert.rgb.apple = function (rgb) {
|
||||
return [(rgb[0] / 255) * 65535, (rgb[1] / 255) * 65535, (rgb[2] / 255) * 65535];
|
||||
};
|
||||
|
||||
convert.gray.rgb = function (args) {
|
||||
return [args[0] / 100 * 255, args[0] / 100 * 255, args[0] / 100 * 255];
|
||||
};
|
||||
|
||||
convert.gray.hsl = function (args) {
|
||||
return [0, 0, args[0]];
|
||||
};
|
||||
|
||||
convert.gray.hsv = convert.gray.hsl;
|
||||
|
||||
convert.gray.hwb = function (gray) {
|
||||
return [0, 100, gray[0]];
|
||||
};
|
||||
|
||||
convert.gray.cmyk = function (gray) {
|
||||
return [0, 0, 0, gray[0]];
|
||||
};
|
||||
|
||||
convert.gray.lab = function (gray) {
|
||||
return [gray[0], 0, 0];
|
||||
};
|
||||
|
||||
convert.gray.hex = function (gray) {
|
||||
const val = Math.round(gray[0] / 100 * 255) & 0xFF;
|
||||
const integer = (val << 16) + (val << 8) + val;
|
||||
|
||||
const string = integer.toString(16).toUpperCase();
|
||||
return '000000'.substring(string.length) + string;
|
||||
};
|
||||
|
||||
convert.rgb.gray = function (rgb) {
|
||||
const val = (rgb[0] + rgb[1] + rgb[2]) / 3;
|
||||
return [val / 255 * 100];
|
||||
};
|
@@ -0,0 +1,81 @@
|
||||
import route from './route'
|
||||
import conversions from './conversions'
|
||||
|
||||
const convert = {};
|
||||
|
||||
const models = Object.keys(conversions);
|
||||
|
||||
function wrapRaw(fn) {
|
||||
const wrappedFn = function (...args) {
|
||||
const arg0 = args[0];
|
||||
if (arg0 === undefined || arg0 === null) {
|
||||
return arg0;
|
||||
}
|
||||
|
||||
if (arg0.length > 1) {
|
||||
args = arg0;
|
||||
}
|
||||
|
||||
return fn(args);
|
||||
};
|
||||
|
||||
// Preserve .conversion property if there is one
|
||||
if ('conversion' in fn) {
|
||||
wrappedFn.conversion = fn.conversion;
|
||||
}
|
||||
|
||||
return wrappedFn;
|
||||
}
|
||||
|
||||
function wrapRounded(fn) {
|
||||
const wrappedFn = function (...args) {
|
||||
const arg0 = args[0];
|
||||
|
||||
if (arg0 === undefined || arg0 === null) {
|
||||
return arg0;
|
||||
}
|
||||
|
||||
if (arg0.length > 1) {
|
||||
args = arg0;
|
||||
}
|
||||
|
||||
const result = fn(args);
|
||||
|
||||
// We're assuming the result is an array here.
|
||||
// see notice in conversions.js; don't use box types
|
||||
// in conversion functions.
|
||||
if (typeof result === 'object') {
|
||||
for (let len = result.length, i = 0; i < len; i++) {
|
||||
result[i] = Math.round(result[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
// Preserve .conversion property if there is one
|
||||
if ('conversion' in fn) {
|
||||
wrappedFn.conversion = fn.conversion;
|
||||
}
|
||||
|
||||
return wrappedFn;
|
||||
}
|
||||
|
||||
models.forEach(fromModel => {
|
||||
convert[fromModel] = {};
|
||||
|
||||
Object.defineProperty(convert[fromModel], 'channels', {value: conversions[fromModel].channels});
|
||||
Object.defineProperty(convert[fromModel], 'labels', {value: conversions[fromModel].labels});
|
||||
|
||||
const routes = route(fromModel);
|
||||
const routeModels = Object.keys(routes);
|
||||
|
||||
routeModels.forEach(toModel => {
|
||||
const fn = routes[toModel];
|
||||
|
||||
convert[fromModel][toModel] = wrapRounded(fn);
|
||||
convert[fromModel][toModel].raw = wrapRaw(fn);
|
||||
});
|
||||
});
|
||||
|
||||
export default convert;
|
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"name": "color-convert",
|
||||
"description": "Plain color conversion functions",
|
||||
"version": "2.0.1",
|
||||
"author": "Heather Arthur <fayearthur@gmail.com>",
|
||||
"license": "MIT",
|
||||
"repository": "Qix-/color-convert",
|
||||
"scripts": {
|
||||
"pretest": "xo",
|
||||
"test": "node test/basic.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
},
|
||||
"keywords": [
|
||||
"color",
|
||||
"colour",
|
||||
"convert",
|
||||
"converter",
|
||||
"conversion",
|
||||
"rgb",
|
||||
"hsl",
|
||||
"hsv",
|
||||
"hwb",
|
||||
"cmyk",
|
||||
"ansi",
|
||||
"ansi16"
|
||||
],
|
||||
"files": [
|
||||
"index.js",
|
||||
"conversions.js",
|
||||
"route.js"
|
||||
],
|
||||
"xo": {
|
||||
"rules": {
|
||||
"default-case": 0,
|
||||
"no-inline-comments": 0,
|
||||
"operator-linebreak": 0
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"chalk": "^2.4.2",
|
||||
"xo": "^0.24.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
}
|
@@ -0,0 +1,97 @@
|
||||
import conversions from './conversions'
|
||||
|
||||
/*
|
||||
This function routes a model to all other models.
|
||||
|
||||
all functions that are routed have a property `.conversion` attached
|
||||
to the returned synthetic function. This property is an array
|
||||
of strings, each with the steps in between the 'from' and 'to'
|
||||
color models (inclusive).
|
||||
|
||||
conversions that are not possible simply are not included.
|
||||
*/
|
||||
|
||||
function buildGraph() {
|
||||
const graph = {};
|
||||
// https://jsperf.com/object-keys-vs-for-in-with-closure/3
|
||||
const models = Object.keys(conversions);
|
||||
|
||||
for (let len = models.length, i = 0; i < len; i++) {
|
||||
graph[models[i]] = {
|
||||
// http://jsperf.com/1-vs-infinity
|
||||
// micro-opt, but this is simple.
|
||||
distance: -1,
|
||||
parent: null
|
||||
};
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
// https://en.wikipedia.org/wiki/Breadth-first_search
|
||||
function deriveBFS(fromModel) {
|
||||
const graph = buildGraph();
|
||||
const queue = [fromModel]; // Unshift -> queue -> pop
|
||||
|
||||
graph[fromModel].distance = 0;
|
||||
|
||||
while (queue.length) {
|
||||
const current = queue.pop();
|
||||
const adjacents = Object.keys(conversions[current]);
|
||||
|
||||
for (let len = adjacents.length, i = 0; i < len; i++) {
|
||||
const adjacent = adjacents[i];
|
||||
const node = graph[adjacent];
|
||||
|
||||
if (node.distance === -1) {
|
||||
node.distance = graph[current].distance + 1;
|
||||
node.parent = current;
|
||||
queue.unshift(adjacent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return graph;
|
||||
}
|
||||
|
||||
function link(from, to) {
|
||||
return function (args) {
|
||||
return to(from(args));
|
||||
};
|
||||
}
|
||||
|
||||
function wrapConversion(toModel, graph) {
|
||||
const path = [graph[toModel].parent, toModel];
|
||||
let fn = conversions[graph[toModel].parent][toModel];
|
||||
|
||||
let cur = graph[toModel].parent;
|
||||
while (graph[cur].parent) {
|
||||
path.unshift(graph[cur].parent);
|
||||
fn = link(conversions[graph[cur].parent][cur], fn);
|
||||
cur = graph[cur].parent;
|
||||
}
|
||||
|
||||
fn.conversion = path;
|
||||
return fn;
|
||||
}
|
||||
|
||||
export default function (fromModel) {
|
||||
const graph = deriveBFS(fromModel);
|
||||
const conversion = {};
|
||||
|
||||
const models = Object.keys(graph);
|
||||
for (let len = models.length, i = 0; i < len; i++) {
|
||||
const toModel = models[i];
|
||||
const node = graph[toModel];
|
||||
|
||||
if (node.parent === null) {
|
||||
// No possible conversion, or this node is the source model.
|
||||
continue;
|
||||
}
|
||||
|
||||
conversion[toModel] = wrapConversion(toModel, graph);
|
||||
}
|
||||
|
||||
return conversion;
|
||||
};
|
||||
|
@@ -0,0 +1,8 @@
|
||||
The MIT License (MIT)
|
||||
Copyright (c) 2015 Dmitry Ivanov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,11 @@
|
||||
A JSON with color names and its values. Based on http://dev.w3.org/csswg/css-color/#named-colors.
|
||||
|
||||
[](https://nodei.co/npm/color-name/)
|
||||
|
||||
|
||||
```js
|
||||
var colors = require('color-name');
|
||||
colors.red //[255,0,0]
|
||||
```
|
||||
|
||||
<a href="LICENSE"><img src="https://upload.wikimedia.org/wikipedia/commons/0/0c/MIT_logo.svg" width="120"/></a>
|
152
uni_modules/wu-ui-tools/libs/function/color/color-name/index.js
Normal file
152
uni_modules/wu-ui-tools/libs/function/color/color-name/index.js
Normal file
@@ -0,0 +1,152 @@
|
||||
'use strict'
|
||||
|
||||
export default {
|
||||
"aliceblue": [240, 248, 255],
|
||||
"antiquewhite": [250, 235, 215],
|
||||
"aqua": [0, 255, 255],
|
||||
"aquamarine": [127, 255, 212],
|
||||
"azure": [240, 255, 255],
|
||||
"beige": [245, 245, 220],
|
||||
"bisque": [255, 228, 196],
|
||||
"black": [0, 0, 0],
|
||||
"blanchedalmond": [255, 235, 205],
|
||||
"blue": [0, 0, 255],
|
||||
"blueviolet": [138, 43, 226],
|
||||
"brown": [165, 42, 42],
|
||||
"burlywood": [222, 184, 135],
|
||||
"cadetblue": [95, 158, 160],
|
||||
"chartreuse": [127, 255, 0],
|
||||
"chocolate": [210, 105, 30],
|
||||
"coral": [255, 127, 80],
|
||||
"cornflowerblue": [100, 149, 237],
|
||||
"cornsilk": [255, 248, 220],
|
||||
"crimson": [220, 20, 60],
|
||||
"cyan": [0, 255, 255],
|
||||
"darkblue": [0, 0, 139],
|
||||
"darkcyan": [0, 139, 139],
|
||||
"darkgoldenrod": [184, 134, 11],
|
||||
"darkgray": [169, 169, 169],
|
||||
"darkgreen": [0, 100, 0],
|
||||
"darkgrey": [169, 169, 169],
|
||||
"darkkhaki": [189, 183, 107],
|
||||
"darkmagenta": [139, 0, 139],
|
||||
"darkolivegreen": [85, 107, 47],
|
||||
"darkorange": [255, 140, 0],
|
||||
"darkorchid": [153, 50, 204],
|
||||
"darkred": [139, 0, 0],
|
||||
"darksalmon": [233, 150, 122],
|
||||
"darkseagreen": [143, 188, 143],
|
||||
"darkslateblue": [72, 61, 139],
|
||||
"darkslategray": [47, 79, 79],
|
||||
"darkslategrey": [47, 79, 79],
|
||||
"darkturquoise": [0, 206, 209],
|
||||
"darkviolet": [148, 0, 211],
|
||||
"deeppink": [255, 20, 147],
|
||||
"deepskyblue": [0, 191, 255],
|
||||
"dimgray": [105, 105, 105],
|
||||
"dimgrey": [105, 105, 105],
|
||||
"dodgerblue": [30, 144, 255],
|
||||
"firebrick": [178, 34, 34],
|
||||
"floralwhite": [255, 250, 240],
|
||||
"forestgreen": [34, 139, 34],
|
||||
"fuchsia": [255, 0, 255],
|
||||
"gainsboro": [220, 220, 220],
|
||||
"ghostwhite": [248, 248, 255],
|
||||
"gold": [255, 215, 0],
|
||||
"goldenrod": [218, 165, 32],
|
||||
"gray": [128, 128, 128],
|
||||
"green": [0, 128, 0],
|
||||
"greenyellow": [173, 255, 47],
|
||||
"grey": [128, 128, 128],
|
||||
"honeydew": [240, 255, 240],
|
||||
"hotpink": [255, 105, 180],
|
||||
"indianred": [205, 92, 92],
|
||||
"indigo": [75, 0, 130],
|
||||
"ivory": [255, 255, 240],
|
||||
"khaki": [240, 230, 140],
|
||||
"lavender": [230, 230, 250],
|
||||
"lavenderblush": [255, 240, 245],
|
||||
"lawngreen": [124, 252, 0],
|
||||
"lemonchiffon": [255, 250, 205],
|
||||
"lightblue": [173, 216, 230],
|
||||
"lightcoral": [240, 128, 128],
|
||||
"lightcyan": [224, 255, 255],
|
||||
"lightgoldenrodyellow": [250, 250, 210],
|
||||
"lightgray": [211, 211, 211],
|
||||
"lightgreen": [144, 238, 144],
|
||||
"lightgrey": [211, 211, 211],
|
||||
"lightpink": [255, 182, 193],
|
||||
"lightsalmon": [255, 160, 122],
|
||||
"lightseagreen": [32, 178, 170],
|
||||
"lightskyblue": [135, 206, 250],
|
||||
"lightslategray": [119, 136, 153],
|
||||
"lightslategrey": [119, 136, 153],
|
||||
"lightsteelblue": [176, 196, 222],
|
||||
"lightyellow": [255, 255, 224],
|
||||
"lime": [0, 255, 0],
|
||||
"limegreen": [50, 205, 50],
|
||||
"linen": [250, 240, 230],
|
||||
"magenta": [255, 0, 255],
|
||||
"maroon": [128, 0, 0],
|
||||
"mediumaquamarine": [102, 205, 170],
|
||||
"mediumblue": [0, 0, 205],
|
||||
"mediumorchid": [186, 85, 211],
|
||||
"mediumpurple": [147, 112, 219],
|
||||
"mediumseagreen": [60, 179, 113],
|
||||
"mediumslateblue": [123, 104, 238],
|
||||
"mediumspringgreen": [0, 250, 154],
|
||||
"mediumturquoise": [72, 209, 204],
|
||||
"mediumvioletred": [199, 21, 133],
|
||||
"midnightblue": [25, 25, 112],
|
||||
"mintcream": [245, 255, 250],
|
||||
"mistyrose": [255, 228, 225],
|
||||
"moccasin": [255, 228, 181],
|
||||
"navajowhite": [255, 222, 173],
|
||||
"navy": [0, 0, 128],
|
||||
"oldlace": [253, 245, 230],
|
||||
"olive": [128, 128, 0],
|
||||
"olivedrab": [107, 142, 35],
|
||||
"orange": [255, 165, 0],
|
||||
"orangered": [255, 69, 0],
|
||||
"orchid": [218, 112, 214],
|
||||
"palegoldenrod": [238, 232, 170],
|
||||
"palegreen": [152, 251, 152],
|
||||
"paleturquoise": [175, 238, 238],
|
||||
"palevioletred": [219, 112, 147],
|
||||
"papayawhip": [255, 239, 213],
|
||||
"peachpuff": [255, 218, 185],
|
||||
"peru": [205, 133, 63],
|
||||
"pink": [255, 192, 203],
|
||||
"plum": [221, 160, 221],
|
||||
"powderblue": [176, 224, 230],
|
||||
"purple": [128, 0, 128],
|
||||
"rebeccapurple": [102, 51, 153],
|
||||
"red": [255, 0, 0],
|
||||
"rosybrown": [188, 143, 143],
|
||||
"royalblue": [65, 105, 225],
|
||||
"saddlebrown": [139, 69, 19],
|
||||
"salmon": [250, 128, 114],
|
||||
"sandybrown": [244, 164, 96],
|
||||
"seagreen": [46, 139, 87],
|
||||
"seashell": [255, 245, 238],
|
||||
"sienna": [160, 82, 45],
|
||||
"silver": [192, 192, 192],
|
||||
"skyblue": [135, 206, 235],
|
||||
"slateblue": [106, 90, 205],
|
||||
"slategray": [112, 128, 144],
|
||||
"slategrey": [112, 128, 144],
|
||||
"snow": [255, 250, 250],
|
||||
"springgreen": [0, 255, 127],
|
||||
"steelblue": [70, 130, 180],
|
||||
"tan": [210, 180, 140],
|
||||
"teal": [0, 128, 128],
|
||||
"thistle": [216, 191, 216],
|
||||
"tomato": [255, 99, 71],
|
||||
"turquoise": [64, 224, 208],
|
||||
"violet": [238, 130, 238],
|
||||
"wheat": [245, 222, 179],
|
||||
"white": [255, 255, 255],
|
||||
"whitesmoke": [245, 245, 245],
|
||||
"yellow": [255, 255, 0],
|
||||
"yellowgreen": [154, 205, 50]
|
||||
};
|
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"name": "color-name",
|
||||
"version": "1.1.4",
|
||||
"description": "A list of color names and its values",
|
||||
"main": "index.js",
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"scripts": {
|
||||
"test": "node test.js"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@github.com:colorjs/color-name.git"
|
||||
},
|
||||
"keywords": [
|
||||
"color-name",
|
||||
"color",
|
||||
"color-keyword",
|
||||
"keyword"
|
||||
],
|
||||
"author": "DY <dfcreative@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/colorjs/color-name/issues"
|
||||
},
|
||||
"homepage": "https://github.com/colorjs/color-name"
|
||||
}
|
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2011 Heather Arthur <fayearthur@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
@@ -0,0 +1,62 @@
|
||||
# color-string
|
||||
|
||||
> library for parsing and generating CSS color strings.
|
||||
|
||||
## Install
|
||||
|
||||
With [npm](http://npmjs.org/):
|
||||
|
||||
```console
|
||||
$ npm install color-string
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Parsing
|
||||
|
||||
```js
|
||||
colorString.get('#FFF') // {model: 'rgb', value: [255, 255, 255, 1]}
|
||||
colorString.get('#FFFA') // {model: 'rgb', value: [255, 255, 255, 0.67]}
|
||||
colorString.get('#FFFFFFAA') // {model: 'rgb', value: [255, 255, 255, 0.67]}
|
||||
colorString.get('hsl(360, 100%, 50%)') // {model: 'hsl', value: [0, 100, 50, 1]}
|
||||
colorString.get('hsl(360 100% 50%)') // {model: 'hsl', value: [0, 100, 50, 1]}
|
||||
colorString.get('hwb(60, 3%, 60%)') // {model: 'hwb', value: [60, 3, 60, 1]}
|
||||
|
||||
colorString.get.rgb('#FFF') // [255, 255, 255, 1]
|
||||
colorString.get.rgb('blue') // [0, 0, 255, 1]
|
||||
colorString.get.rgb('rgba(200, 60, 60, 0.3)') // [200, 60, 60, 0.3]
|
||||
colorString.get.rgb('rgba(200 60 60 / 0.3)') // [200, 60, 60, 0.3]
|
||||
colorString.get.rgb('rgba(200 60 60 / 30%)') // [200, 60, 60, 0.3]
|
||||
colorString.get.rgb('rgb(200, 200, 200)') // [200, 200, 200, 1]
|
||||
colorString.get.rgb('rgb(200 200 200)') // [200, 200, 200, 1]
|
||||
|
||||
colorString.get.hsl('hsl(360, 100%, 50%)') // [0, 100, 50, 1]
|
||||
colorString.get.hsl('hsl(360 100% 50%)') // [0, 100, 50, 1]
|
||||
colorString.get.hsl('hsla(360, 60%, 50%, 0.4)') // [0, 60, 50, 0.4]
|
||||
colorString.get.hsl('hsl(360 60% 50% / 0.4)') // [0, 60, 50, 0.4]
|
||||
|
||||
colorString.get.hwb('hwb(60, 3%, 60%)') // [60, 3, 60, 1]
|
||||
colorString.get.hwb('hwb(60, 3%, 60%, 0.6)') // [60, 3, 60, 0.6]
|
||||
|
||||
colorString.get.rgb('invalid color string') // null
|
||||
```
|
||||
|
||||
### Generation
|
||||
|
||||
```js
|
||||
colorString.to.hex([255, 255, 255]) // "#FFFFFF"
|
||||
colorString.to.hex([0, 0, 255, 0.4]) // "#0000FF66"
|
||||
colorString.to.hex([0, 0, 255], 0.4) // "#0000FF66"
|
||||
colorString.to.rgb([255, 255, 255]) // "rgb(255, 255, 255)"
|
||||
colorString.to.rgb([0, 0, 255, 0.4]) // "rgba(0, 0, 255, 0.4)"
|
||||
colorString.to.rgb([0, 0, 255], 0.4) // "rgba(0, 0, 255, 0.4)"
|
||||
colorString.to.rgb.percent([0, 0, 255]) // "rgb(0%, 0%, 100%)"
|
||||
colorString.to.keyword([255, 255, 0]) // "yellow"
|
||||
colorString.to.hsl([360, 100, 100]) // "hsl(360, 100%, 100%)"
|
||||
colorString.to.hwb([50, 3, 15]) // "hwb(50, 3%, 15%)"
|
||||
|
||||
// all functions also support swizzling
|
||||
colorString.to.rgb(0, [0, 255], 0.4) // "rgba(0, 0, 255, 0.4)"
|
||||
colorString.to.rgb([0, 0], [255], 0.4) // "rgba(0, 0, 255, 0.4)"
|
||||
colorString.to.rgb([0], 0, [255, 0.4]) // "rgba(0, 0, 255, 0.4)"
|
||||
```
|
@@ -0,0 +1,244 @@
|
||||
/* MIT license */
|
||||
import colorNames from '../color-name'
|
||||
import swizzle from '../simple-swizzle'
|
||||
var hasOwnProperty = Object.hasOwnProperty;
|
||||
|
||||
var reverseNames = Object.create(null);
|
||||
|
||||
// create a list of reverse color names
|
||||
for (var name in colorNames) {
|
||||
if (hasOwnProperty.call(colorNames, name)) {
|
||||
reverseNames[colorNames[name]] = name;
|
||||
}
|
||||
}
|
||||
|
||||
var cs = {
|
||||
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*(?:,\s*)?([+-]?\d+)(?=[\s,])\s*(?:,\s*)?([+-]?\d+)\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/;
|
||||
var per = /^rgba?\(\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*,?\s*([+-]?[\d\.]+)\%\s*(?:[,|\/]\s*([+-]?[\d\.]+)(%?)\s*)?\)$/;
|
||||
var keyword = /^(\w+)$/;
|
||||
|
||||
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] = parseInt(hexAlpha, 16) / 255;
|
||||
}
|
||||
} 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] = parseInt(hexAlpha + hexAlpha, 16) / 255;
|
||||
}
|
||||
} else if (match = string.match(rgba)) {
|
||||
for (i = 0; i < 3; i++) {
|
||||
rgb[i] = parseInt(match[i + 1], 0);
|
||||
}
|
||||
|
||||
if (match[4]) {
|
||||
if (match[5]) {
|
||||
rgb[3] = parseFloat(match[4]) * 0.01;
|
||||
} else {
|
||||
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]) {
|
||||
if (match[5]) {
|
||||
rgb[3] = parseFloat(match[4]) * 0.01;
|
||||
} else {
|
||||
rgb[3] = parseFloat(match[4]);
|
||||
}
|
||||
}
|
||||
} else if (match = string.match(keyword)) {
|
||||
if (match[1] === 'transparent') {
|
||||
return [0, 0, 0, 0];
|
||||
}
|
||||
|
||||
if (!hasOwnProperty.call(colorNames, match[1])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
rgb = colorNames[match[1]];
|
||||
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{0,3}\.)?\d+)(?:deg)?\s*,?\s*([+-]?[\d\.]+)%\s*,?\s*([+-]?[\d\.]+)%\s*(?:[,|\/]\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\d+)?)\s*)?\)$/;
|
||||
var match = string.match(hsl);
|
||||
|
||||
if (match) {
|
||||
var alpha = parseFloat(match[4]);
|
||||
var h = ((parseFloat(match[1]) % 360) + 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{0,3}(?:\.\d+)?)(?:deg)?\s*,\s*([+-]?[\d\.]+)%\s*,\s*([+-]?[\d\.]+)%\s*(?:,\s*([+-]?(?=\.\d|\d)(?:0|[1-9]\d*)?(?:\.\d*)?(?:[eE][+-]?\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 = Math.round(num).toString(16).toUpperCase();
|
||||
return (str.length < 2) ? '0' + str : str;
|
||||
}
|
||||
|
||||
export default cs;
|
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "color-string",
|
||||
"description": "Parser and generator for CSS color strings",
|
||||
"version": "1.9.1",
|
||||
"author": "Heather Arthur <fayearthur@gmail.com>",
|
||||
"contributors": [
|
||||
"Maxime Thirouin",
|
||||
"Dyma Ywanov <dfcreative@gmail.com>",
|
||||
"Josh Junon"
|
||||
],
|
||||
"repository": "Qix-/color-string",
|
||||
"scripts": {
|
||||
"pretest": "xo",
|
||||
"test": "node test/basic.js"
|
||||
},
|
||||
"license": "MIT",
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"xo": {
|
||||
"rules": {
|
||||
"no-cond-assign": 0,
|
||||
"operator-linebreak": 0
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"xo": "^0.12.1"
|
||||
},
|
||||
"keywords": [
|
||||
"color",
|
||||
"colour",
|
||||
"rgb",
|
||||
"css"
|
||||
]
|
||||
}
|
496
uni_modules/wu-ui-tools/libs/function/color/color.js
Normal file
496
uni_modules/wu-ui-tools/libs/function/color/color.js
Normal file
@@ -0,0 +1,496 @@
|
||||
import colorString from './color-string'
|
||||
import convert from './color-convert'
|
||||
|
||||
const skippedModels = [
|
||||
// To be honest, I don't really feel like keyword belongs in color convert, but eh.
|
||||
'keyword',
|
||||
|
||||
// Gray conflicts with some method names, and has its own method defined.
|
||||
'gray',
|
||||
|
||||
// Shouldn't really be in color-convert either...
|
||||
'hex',
|
||||
];
|
||||
|
||||
const hashedModelKeys = {};
|
||||
for (const model of Object.keys(convert)) {
|
||||
hashedModelKeys[[...convert[model].labels].sort().join('')] = model;
|
||||
}
|
||||
|
||||
const limiters = {};
|
||||
|
||||
function Color(object, model) {
|
||||
if (!(this instanceof Color)) {
|
||||
return new Color(object, model);
|
||||
}
|
||||
|
||||
if (model && model in skippedModels) {
|
||||
model = null;
|
||||
}
|
||||
|
||||
if (model && !(model in convert)) {
|
||||
throw new Error('Unknown model: ' + model);
|
||||
}
|
||||
|
||||
let i;
|
||||
let channels;
|
||||
|
||||
if (object == null) { // eslint-disable-line no-eq-null,eqeqeq
|
||||
this.model = 'rgb';
|
||||
this.color = [0, 0, 0];
|
||||
this.valpha = 1;
|
||||
} else if (object instanceof Color) {
|
||||
this.model = object.model;
|
||||
this.color = [...object.color];
|
||||
this.valpha = object.valpha;
|
||||
} else if (typeof object === 'string') {
|
||||
const result = colorString.get(object);
|
||||
if (result === null) {
|
||||
throw new Error('Unable to parse color from string: ' + object);
|
||||
}
|
||||
|
||||
this.model = result.model;
|
||||
channels = convert[this.model].channels;
|
||||
this.color = result.value.slice(0, channels);
|
||||
this.valpha = typeof result.value[channels] === 'number' ? result.value[channels] : 1;
|
||||
} else if (object.length > 0) {
|
||||
this.model = model || 'rgb';
|
||||
channels = convert[this.model].channels;
|
||||
const newArray = Array.prototype.slice.call(object, 0, channels);
|
||||
this.color = zeroArray(newArray, channels);
|
||||
this.valpha = typeof object[channels] === 'number' ? object[channels] : 1;
|
||||
} else if (typeof object === 'number') {
|
||||
// This is always RGB - can be converted later on.
|
||||
this.model = 'rgb';
|
||||
this.color = [
|
||||
(object >> 16) & 0xFF,
|
||||
(object >> 8) & 0xFF,
|
||||
object & 0xFF,
|
||||
];
|
||||
this.valpha = 1;
|
||||
} else {
|
||||
this.valpha = 1;
|
||||
|
||||
const keys = Object.keys(object);
|
||||
if ('alpha' in object) {
|
||||
keys.splice(keys.indexOf('alpha'), 1);
|
||||
this.valpha = typeof object.alpha === 'number' ? object.alpha : 0;
|
||||
}
|
||||
|
||||
const hashedKeys = keys.sort().join('');
|
||||
if (!(hashedKeys in hashedModelKeys)) {
|
||||
throw new Error('Unable to parse color from object: ' + JSON.stringify(object));
|
||||
}
|
||||
|
||||
this.model = hashedModelKeys[hashedKeys];
|
||||
|
||||
const {labels} = convert[this.model];
|
||||
const color = [];
|
||||
for (i = 0; i < labels.length; i++) {
|
||||
color.push(object[labels[i]]);
|
||||
}
|
||||
|
||||
this.color = zeroArray(color);
|
||||
}
|
||||
|
||||
// Perform limitations (clamping, etc.)
|
||||
if (limiters[this.model]) {
|
||||
channels = convert[this.model].channels;
|
||||
for (i = 0; i < channels; i++) {
|
||||
const limit = limiters[this.model][i];
|
||||
if (limit) {
|
||||
this.color[i] = limit(this.color[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.valpha = Math.max(0, Math.min(1, this.valpha));
|
||||
|
||||
if (Object.freeze) {
|
||||
Object.freeze(this);
|
||||
}
|
||||
}
|
||||
|
||||
Color.prototype = {
|
||||
toString() {
|
||||
return this.string();
|
||||
},
|
||||
|
||||
toJSON() {
|
||||
return this[this.model]();
|
||||
},
|
||||
|
||||
string(places) {
|
||||
let self = this.model in colorString.to ? this : this.rgb();
|
||||
self = self.round(typeof places === 'number' ? places : 1);
|
||||
const args = self.valpha === 1 ? self.color : [...self.color, this.valpha];
|
||||
return colorString.to[self.model](args);
|
||||
},
|
||||
|
||||
percentString(places) {
|
||||
const self = this.rgb().round(typeof places === 'number' ? places : 1);
|
||||
const args = self.valpha === 1 ? self.color : [...self.color, this.valpha];
|
||||
return colorString.to.rgb.percent(args);
|
||||
},
|
||||
|
||||
array() {
|
||||
return this.valpha === 1 ? [...this.color] : [...this.color, this.valpha];
|
||||
},
|
||||
|
||||
object() {
|
||||
const result = {};
|
||||
const {channels} = convert[this.model];
|
||||
const {labels} = convert[this.model];
|
||||
|
||||
for (let i = 0; i < channels; i++) {
|
||||
result[labels[i]] = this.color[i];
|
||||
}
|
||||
|
||||
if (this.valpha !== 1) {
|
||||
result.alpha = this.valpha;
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
unitArray() {
|
||||
const rgb = this.rgb().color;
|
||||
rgb[0] /= 255;
|
||||
rgb[1] /= 255;
|
||||
rgb[2] /= 255;
|
||||
|
||||
if (this.valpha !== 1) {
|
||||
rgb.push(this.valpha);
|
||||
}
|
||||
|
||||
return rgb;
|
||||
},
|
||||
|
||||
unitObject() {
|
||||
const rgb = this.rgb().object();
|
||||
rgb.r /= 255;
|
||||
rgb.g /= 255;
|
||||
rgb.b /= 255;
|
||||
|
||||
if (this.valpha !== 1) {
|
||||
rgb.alpha = this.valpha;
|
||||
}
|
||||
|
||||
return rgb;
|
||||
},
|
||||
|
||||
round(places) {
|
||||
places = Math.max(places || 0, 0);
|
||||
return new Color([...this.color.map(roundToPlace(places)), this.valpha], this.model);
|
||||
},
|
||||
|
||||
alpha(value) {
|
||||
if (value !== undefined) {
|
||||
return new Color([...this.color, Math.max(0, Math.min(1, value))], this.model);
|
||||
}
|
||||
|
||||
return this.valpha;
|
||||
},
|
||||
|
||||
// Rgb
|
||||
red: getset('rgb', 0, maxfn(255)),
|
||||
green: getset('rgb', 1, maxfn(255)),
|
||||
blue: getset('rgb', 2, maxfn(255)),
|
||||
|
||||
hue: getset(['hsl', 'hsv', 'hsl', 'hwb', 'hcg'], 0, value => ((value % 360) + 360) % 360),
|
||||
|
||||
saturationl: getset('hsl', 1, maxfn(100)),
|
||||
lightness: getset('hsl', 2, maxfn(100)),
|
||||
|
||||
saturationv: getset('hsv', 1, maxfn(100)),
|
||||
value: getset('hsv', 2, maxfn(100)),
|
||||
|
||||
chroma: getset('hcg', 1, maxfn(100)),
|
||||
gray: getset('hcg', 2, maxfn(100)),
|
||||
|
||||
white: getset('hwb', 1, maxfn(100)),
|
||||
wblack: getset('hwb', 2, maxfn(100)),
|
||||
|
||||
cyan: getset('cmyk', 0, maxfn(100)),
|
||||
magenta: getset('cmyk', 1, maxfn(100)),
|
||||
yellow: getset('cmyk', 2, maxfn(100)),
|
||||
black: getset('cmyk', 3, maxfn(100)),
|
||||
|
||||
x: getset('xyz', 0, maxfn(95.047)),
|
||||
y: getset('xyz', 1, maxfn(100)),
|
||||
z: getset('xyz', 2, maxfn(108.833)),
|
||||
|
||||
l: getset('lab', 0, maxfn(100)),
|
||||
a: getset('lab', 1),
|
||||
b: getset('lab', 2),
|
||||
|
||||
keyword(value) {
|
||||
if (value !== undefined) {
|
||||
return new Color(value);
|
||||
}
|
||||
|
||||
return convert[this.model].keyword(this.color);
|
||||
},
|
||||
|
||||
hex(value) {
|
||||
if (value !== undefined) {
|
||||
return new Color(value);
|
||||
}
|
||||
|
||||
return colorString.to.hex(this.rgb().round().color);
|
||||
},
|
||||
|
||||
hexa(value) {
|
||||
if (value !== undefined) {
|
||||
return new Color(value);
|
||||
}
|
||||
|
||||
const rgbArray = this.rgb().round().color;
|
||||
|
||||
let alphaHex = Math.round(this.valpha * 255).toString(16).toUpperCase();
|
||||
if (alphaHex.length === 1) {
|
||||
alphaHex = '0' + alphaHex;
|
||||
}
|
||||
|
||||
return colorString.to.hex(rgbArray) + alphaHex;
|
||||
},
|
||||
|
||||
rgbNumber() {
|
||||
const rgb = this.rgb().color;
|
||||
return ((rgb[0] & 0xFF) << 16) | ((rgb[1] & 0xFF) << 8) | (rgb[2] & 0xFF);
|
||||
},
|
||||
|
||||
luminosity() {
|
||||
// http://www.w3.org/TR/WCAG20/#relativeluminancedef
|
||||
const rgb = this.rgb().color;
|
||||
|
||||
const lum = [];
|
||||
for (const [i, element] of rgb.entries()) {
|
||||
const chan = element / 255;
|
||||
lum[i] = (chan <= 0.04045) ? chan / 12.92 : ((chan + 0.055) / 1.055) ** 2.4;
|
||||
}
|
||||
|
||||
return 0.2126 * lum[0] + 0.7152 * lum[1] + 0.0722 * lum[2];
|
||||
},
|
||||
|
||||
contrast(color2) {
|
||||
// http://www.w3.org/TR/WCAG20/#contrast-ratiodef
|
||||
const lum1 = this.luminosity();
|
||||
const lum2 = color2.luminosity();
|
||||
|
||||
if (lum1 > lum2) {
|
||||
return (lum1 + 0.05) / (lum2 + 0.05);
|
||||
}
|
||||
|
||||
return (lum2 + 0.05) / (lum1 + 0.05);
|
||||
},
|
||||
|
||||
level(color2) {
|
||||
// https://www.w3.org/TR/WCAG/#contrast-enhanced
|
||||
const contrastRatio = this.contrast(color2);
|
||||
if (contrastRatio >= 7) {
|
||||
return 'AAA';
|
||||
}
|
||||
|
||||
return (contrastRatio >= 4.5) ? 'AA' : '';
|
||||
},
|
||||
|
||||
isDark() {
|
||||
// YIQ equation from http://24ways.org/2010/calculating-color-contrast
|
||||
const rgb = this.rgb().color;
|
||||
const yiq = (rgb[0] * 2126 + rgb[1] * 7152 + rgb[2] * 722) / 10000;
|
||||
return yiq < 128;
|
||||
},
|
||||
|
||||
isLight() {
|
||||
return !this.isDark();
|
||||
},
|
||||
|
||||
negate() {
|
||||
const rgb = this.rgb();
|
||||
for (let i = 0; i < 3; i++) {
|
||||
rgb.color[i] = 255 - rgb.color[i];
|
||||
}
|
||||
|
||||
return rgb;
|
||||
},
|
||||
|
||||
lighten(ratio) {
|
||||
const hsl = this.hsl();
|
||||
hsl.color[2] += hsl.color[2] * ratio;
|
||||
return hsl;
|
||||
},
|
||||
|
||||
darken(ratio) {
|
||||
const hsl = this.hsl();
|
||||
hsl.color[2] -= hsl.color[2] * ratio;
|
||||
return hsl;
|
||||
},
|
||||
|
||||
saturate(ratio) {
|
||||
const hsl = this.hsl();
|
||||
hsl.color[1] += hsl.color[1] * ratio;
|
||||
return hsl;
|
||||
},
|
||||
|
||||
desaturate(ratio) {
|
||||
const hsl = this.hsl();
|
||||
hsl.color[1] -= hsl.color[1] * ratio;
|
||||
return hsl;
|
||||
},
|
||||
|
||||
whiten(ratio) {
|
||||
const hwb = this.hwb();
|
||||
hwb.color[1] += hwb.color[1] * ratio;
|
||||
return hwb;
|
||||
},
|
||||
|
||||
blacken(ratio) {
|
||||
const hwb = this.hwb();
|
||||
hwb.color[2] += hwb.color[2] * ratio;
|
||||
return hwb;
|
||||
},
|
||||
|
||||
grayscale() {
|
||||
// http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale
|
||||
const rgb = this.rgb().color;
|
||||
const value = rgb[0] * 0.3 + rgb[1] * 0.59 + rgb[2] * 0.11;
|
||||
return Color.rgb(value, value, value);
|
||||
},
|
||||
|
||||
fade(ratio) {
|
||||
return this.alpha(this.valpha - (this.valpha * ratio));
|
||||
},
|
||||
|
||||
opaquer(ratio) {
|
||||
return this.alpha(this.valpha + (this.valpha * ratio));
|
||||
},
|
||||
|
||||
rotate(degrees) {
|
||||
const hsl = this.hsl();
|
||||
let hue = hsl.color[0];
|
||||
hue = (hue + degrees) % 360;
|
||||
hue = hue < 0 ? 360 + hue : hue;
|
||||
hsl.color[0] = hue;
|
||||
return hsl;
|
||||
},
|
||||
|
||||
mix(mixinColor, weight) {
|
||||
// Ported from sass implementation in C
|
||||
// https://github.com/sass/libsass/blob/0e6b4a2850092356aa3ece07c6b249f0221caced/functions.cpp#L209
|
||||
if (!mixinColor || !mixinColor.rgb) {
|
||||
throw new Error('Argument to "mix" was not a Color instance, but rather an instance of ' + typeof mixinColor);
|
||||
}
|
||||
|
||||
const color1 = mixinColor.rgb();
|
||||
const color2 = this.rgb();
|
||||
const p = weight === undefined ? 0.5 : weight;
|
||||
|
||||
const w = 2 * p - 1;
|
||||
const a = color1.alpha() - color2.alpha();
|
||||
|
||||
const w1 = (((w * a === -1) ? w : (w + a) / (1 + w * a)) + 1) / 2;
|
||||
const w2 = 1 - w1;
|
||||
|
||||
return Color.rgb(
|
||||
w1 * color1.red() + w2 * color2.red(),
|
||||
w1 * color1.green() + w2 * color2.green(),
|
||||
w1 * color1.blue() + w2 * color2.blue(),
|
||||
color1.alpha() * p + color2.alpha() * (1 - p));
|
||||
},
|
||||
};
|
||||
|
||||
// Model conversion methods and static constructors
|
||||
for (const model of Object.keys(convert)) {
|
||||
if (skippedModels.includes(model)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const {channels} = convert[model];
|
||||
|
||||
// Conversion methods
|
||||
Color.prototype[model] = function (...args) {
|
||||
if (this.model === model) {
|
||||
return new Color(this);
|
||||
}
|
||||
|
||||
if (args.length > 0) {
|
||||
return new Color(args, model);
|
||||
}
|
||||
|
||||
return new Color([...assertArray(convert[this.model][model].raw(this.color)), this.valpha], model);
|
||||
};
|
||||
|
||||
// 'static' construction methods
|
||||
Color[model] = function (...args) {
|
||||
let color = args[0];
|
||||
if (typeof color === 'number') {
|
||||
color = zeroArray(args, channels);
|
||||
}
|
||||
|
||||
return new Color(color, model);
|
||||
};
|
||||
}
|
||||
|
||||
function roundTo(number, places) {
|
||||
return Number(number.toFixed(places));
|
||||
}
|
||||
|
||||
function roundToPlace(places) {
|
||||
return function (number) {
|
||||
return roundTo(number, places);
|
||||
};
|
||||
}
|
||||
|
||||
function getset(model, channel, modifier) {
|
||||
model = Array.isArray(model) ? model : [model];
|
||||
|
||||
for (const m of model) {
|
||||
(limiters[m] || (limiters[m] = []))[channel] = modifier;
|
||||
}
|
||||
|
||||
model = model[0];
|
||||
|
||||
return function (value) {
|
||||
let result;
|
||||
|
||||
if (value !== undefined) {
|
||||
if (modifier) {
|
||||
value = modifier(value);
|
||||
}
|
||||
|
||||
result = this[model]();
|
||||
result.color[channel] = value;
|
||||
return result;
|
||||
}
|
||||
|
||||
result = this[model]().color[channel];
|
||||
if (modifier) {
|
||||
result = modifier(result);
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
function maxfn(max) {
|
||||
return function (v) {
|
||||
return Math.max(0, Math.min(max, v));
|
||||
};
|
||||
}
|
||||
|
||||
function assertArray(value) {
|
||||
return Array.isArray(value) ? value : [value];
|
||||
}
|
||||
|
||||
function zeroArray(array, length) {
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (typeof array[i] !== 'number') {
|
||||
array[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
export default Color;
|
158
uni_modules/wu-ui-tools/libs/function/color/index.js
Normal file
158
uni_modules/wu-ui-tools/libs/function/color/index.js
Normal file
@@ -0,0 +1,158 @@
|
||||
import Color from './color';
|
||||
|
||||
/**
|
||||
* 转换颜色格式。
|
||||
* @param {Object} params - 参数对象。
|
||||
* @param {string} color - 输入的颜色,默认为 '#fff'。
|
||||
* @param {string} format - 需要转换的格式(支持 'rgb', 'hex', 'hsl', 'hsv', 'hwb')。
|
||||
* @param {string} type - 转换后的类型(支持 'string', 'object', 'array', 'round')。
|
||||
* @returns {string|Object|Array} 转换后的颜色表示。
|
||||
*/
|
||||
function convertFormat(color = '#fff', format = 'rgb', type = 'string') {
|
||||
let colorObj = Color(color);
|
||||
// 如果格式存在
|
||||
if (colorObj[format]) {
|
||||
// hex 无法直接转换为 除string类型外的任何类型
|
||||
// 所以转为rgb 后 获取其他类型
|
||||
if(format == 'hex' && type != 'string') format = 'rgb';
|
||||
// 类型名称
|
||||
let typeName = '';
|
||||
switch (type) {
|
||||
case 'string':
|
||||
typeName = 'toString';
|
||||
break;
|
||||
case 'object':
|
||||
typeName = 'object';
|
||||
break;
|
||||
case 'array':
|
||||
typeName = 'array';
|
||||
break;
|
||||
case 'round':
|
||||
typeName = 'round';
|
||||
break;
|
||||
default:
|
||||
throw Error('Unsupported target type:' + type)
|
||||
}
|
||||
return colorObj[format]()[typeName]();
|
||||
} else {
|
||||
throw Error('Unsupported target format: ' + format);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算两个颜色之间的渐变值。
|
||||
* @param {string} startColor - 开始的颜色,默认为黑色。
|
||||
* @param {string} endColor - 结束的颜色,默认为白色。
|
||||
* @param {number} step - 渐变的步数,默认为10。
|
||||
* @returns {Array<string>} 两个颜色之间的渐变颜色数组。
|
||||
*/
|
||||
function gradient(startColor = 'rgb(0, 0, 0)', endColor = 'rgb(255, 255, 255)', step = 10) {
|
||||
const startRGB = convertFormat(startColor, 'rgb', 'array') // 转换为rgb数组模式
|
||||
const startR = startRGB[0]
|
||||
const startG = startRGB[1]
|
||||
const startB = startRGB[2]
|
||||
|
||||
const endRGB = convertFormat(endColor, 'rgb', 'array')
|
||||
const endR = endRGB[0]
|
||||
const endG = endRGB[1]
|
||||
const endB = endRGB[2]
|
||||
|
||||
const sR = (endR - startR) / step // 总差值
|
||||
const sG = (endG - startG) / step
|
||||
const sB = (endB - startB) / step
|
||||
const colorArr = []
|
||||
for (let i = 0; i < step; i++) {
|
||||
// 计算每一步的hex值
|
||||
let hex = convertFormat(`rgb(${Math.round((sR * i + startR))},${Math.round((sG * i + startG))},${Math.round((sB
|
||||
* i + startB))})`, 'hex')
|
||||
// 确保第一个颜色值为startColor的值
|
||||
if (i === 0) hex = convertFormat(startColor, 'hex')
|
||||
// 确保最后一个颜色值为endColor的值
|
||||
if (i === step - 1) hex = convertFormat(endColor, 'hex')
|
||||
colorArr.push(hex)
|
||||
}
|
||||
return colorArr
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default {
|
||||
/**
|
||||
* 格式转换。
|
||||
*/
|
||||
convertFormat,
|
||||
|
||||
/**
|
||||
* 计算两个颜色之间的渐变值。
|
||||
*/
|
||||
gradient,
|
||||
|
||||
/**
|
||||
* 增加颜色的亮度。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @param {number} value - 增加的亮度值(0-1)。
|
||||
* @returns {string} 调整后的颜色。
|
||||
*/
|
||||
lighten: (color, value, format = 'rgb', type = 'string') => convertFormat(Color(color).lighten(value), format, type),
|
||||
|
||||
/**
|
||||
* 减少颜色的亮度。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @param {number} value - 减少的亮度值(0-1)。
|
||||
* @returns {string} 调整后的颜色。
|
||||
*/
|
||||
darken: (color, value, format = 'rgb', type = 'string') => convertFormat(Color(color).darken(value), format, type),
|
||||
|
||||
/**
|
||||
* 增加颜色的饱和度。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @param {number} value - 增加的饱和度值(0-1)。
|
||||
* @returns {string} 调整后的颜色。
|
||||
*/
|
||||
saturate: (color, value, format = 'rgb', type = 'string') => convertFormat(Color(color).saturate(value), format, type),
|
||||
|
||||
/**
|
||||
* 减少颜色的饱和度。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @param {number} value - 减少的饱和度值(0-1)。
|
||||
* @returns {string} 调整后的颜色。
|
||||
*/
|
||||
desaturate: (color, value, format = 'rgb', type = 'string') => convertFormat(Color(color).desaturate(value), format, type),
|
||||
|
||||
/**
|
||||
* 旋转颜色的色相。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @param {number} degrees - 旋转的度数。
|
||||
* @returns {string} 调整后的颜色。
|
||||
*/
|
||||
rotate: (color, degrees, format = 'rgb', type = 'string') => convertFormat(Color(color).rotate(degrees), format, type),
|
||||
|
||||
/**
|
||||
* 调整颜色的透明度。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @param {number} value - 透明度值(0-1,其中 1 是不透明)。
|
||||
* @returns {string} 调整后的颜色。
|
||||
*/
|
||||
adjustAlpha: (color, value, format = 'rgb', type = 'string') => convertFormat(Color(color).alpha(value), format, type),
|
||||
|
||||
/**
|
||||
* 获取颜色的亮度。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @returns {number} 颜色的亮度值(0-1)。
|
||||
*/
|
||||
luminosity: (color, format) => Color(color).luminosity(),
|
||||
|
||||
/**
|
||||
* 判断颜色是否为暗色。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @returns {boolean} 如果是暗色则返回 true,否则返回 false。
|
||||
*/
|
||||
isDark: (color, format) => Color(color).isDark(),
|
||||
|
||||
/**
|
||||
* 判断颜色是否为亮色。
|
||||
* @param {string} color - 输入的颜色。
|
||||
* @returns {boolean} 如果是亮色则返回 true,否则返回 false。
|
||||
*/
|
||||
isLight: (color, format) => Color(color).isLight()
|
||||
};
|
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 JD Ballard
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@@ -0,0 +1,16 @@
|
||||
# node-is-arrayish [](https://travis-ci.org/Qix-/node-is-arrayish) [](https://coveralls.io/r/Qix-/node-is-arrayish)
|
||||
> Determines if an object can be used like an Array
|
||||
|
||||
## Example
|
||||
```javascript
|
||||
var isArrayish = require('is-arrayish');
|
||||
|
||||
isArrayish([]); // true
|
||||
isArrayish({__proto__: []}); // true
|
||||
isArrayish({}); // false
|
||||
isArrayish({length:10}); // false
|
||||
```
|
||||
|
||||
## License
|
||||
Licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
You can find a copy of it in [LICENSE](LICENSE).
|
@@ -0,0 +1,9 @@
|
||||
export default function isArrayish(obj) {
|
||||
if (!obj || typeof obj === 'string') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return obj instanceof Array || Array.isArray(obj) ||
|
||||
(obj.length >= 0 && (obj.splice instanceof Function ||
|
||||
(Object.getOwnPropertyDescriptor(obj, (obj.length - 1)) && obj.constructor.name !== 'String')));
|
||||
};
|
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"name": "is-arrayish",
|
||||
"description": "Determines if an object can be used as an array",
|
||||
"version": "0.3.2",
|
||||
"author": "Qix (http://github.com/qix-)",
|
||||
"keywords": [
|
||||
"is",
|
||||
"array",
|
||||
"duck",
|
||||
"type",
|
||||
"arrayish",
|
||||
"similar",
|
||||
"proto",
|
||||
"prototype",
|
||||
"type"
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"test": "mocha --require coffeescript/register ./test/**/*.coffee",
|
||||
"lint": "zeit-eslint --ext .jsx,.js .",
|
||||
"lint-staged": "git diff --diff-filter=ACMRT --cached --name-only '*.js' '*.jsx' | xargs zeit-eslint"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/qix-/node-is-arrayish.git"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@zeit/eslint-config-node": "^0.3.0",
|
||||
"@zeit/git-hooks": "^0.1.4",
|
||||
"coffeescript": "^2.3.1",
|
||||
"coveralls": "^3.0.1",
|
||||
"eslint": "^4.19.1",
|
||||
"istanbul": "^0.4.5",
|
||||
"mocha": "^5.2.0",
|
||||
"should": "^13.2.1"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
"@zeit/eslint-config-node"
|
||||
]
|
||||
},
|
||||
"git": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,21 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 Josh Junon
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
@@ -0,0 +1,39 @@
|
||||
# simple-swizzle [](https://travis-ci.org/Qix-/node-simple-swizzle) [](https://coveralls.io/r/Qix-/node-simple-swizzle)
|
||||
|
||||
> [Swizzle](https://en.wikipedia.org/wiki/Swizzling_(computer_graphics)) your function arguments; pass in mixed arrays/values and get a clean array
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
var swizzle = require('simple-swizzle');
|
||||
|
||||
function myFunc() {
|
||||
var args = swizzle(arguments);
|
||||
// ...
|
||||
return args;
|
||||
}
|
||||
|
||||
myFunc(1, [2, 3], 4); // [1, 2, 3, 4]
|
||||
myFunc(1, 2, 3, 4); // [1, 2, 3, 4]
|
||||
myFunc([1, 2, 3, 4]); // [1, 2, 3, 4]
|
||||
```
|
||||
|
||||
Functions can also be wrapped to automatically swizzle arguments and be passed
|
||||
the resulting array.
|
||||
|
||||
```js
|
||||
var swizzle = require('simple-swizzle');
|
||||
|
||||
var swizzledFn = swizzle.wrap(function (args) {
|
||||
// ...
|
||||
return args;
|
||||
});
|
||||
|
||||
swizzledFn(1, [2, 3], 4); // [1, 2, 3, 4]
|
||||
swizzledFn(1, 2, 3, 4); // [1, 2, 3, 4]
|
||||
swizzledFn([1, 2, 3, 4]); // [1, 2, 3, 4]
|
||||
```
|
||||
|
||||
## License
|
||||
Licensed under the [MIT License](http://opensource.org/licenses/MIT).
|
||||
You can find a copy of it in [LICENSE](LICENSE).
|
@@ -0,0 +1,29 @@
|
||||
'use strict';
|
||||
|
||||
import isArrayish from '../is-arrayish';
|
||||
|
||||
var concat = Array.prototype.concat;
|
||||
var slice = Array.prototype.slice;
|
||||
|
||||
export default function swizzle(args) {
|
||||
var results = [];
|
||||
|
||||
for (var i = 0, len = args.length; i < len; i++) {
|
||||
var arg = args[i];
|
||||
|
||||
if (isArrayish(arg)) {
|
||||
// http://jsperf.com/javascript-array-concat-vs-push/98
|
||||
results = concat.call(results, slice.call(arg));
|
||||
} else {
|
||||
results.push(arg);
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
};
|
||||
|
||||
swizzle.wrap = function (fn) {
|
||||
return function () {
|
||||
return fn(swizzle(arguments));
|
||||
};
|
||||
};
|
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"name": "simple-swizzle",
|
||||
"description": "Simply swizzle your arguments",
|
||||
"version": "0.2.2",
|
||||
"author": "Qix (http://github.com/qix-)",
|
||||
"keywords": [
|
||||
"argument",
|
||||
"arguments",
|
||||
"swizzle",
|
||||
"swizzling",
|
||||
"parameter",
|
||||
"parameters",
|
||||
"mixed",
|
||||
"array"
|
||||
],
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"pretest": "xo",
|
||||
"test": "mocha --compilers coffee:coffee-script/register"
|
||||
},
|
||||
"files": [
|
||||
"index.js"
|
||||
],
|
||||
"repository": "qix-/node-simple-swizzle",
|
||||
"devDependencies": {
|
||||
"coffee-script": "^1.9.3",
|
||||
"coveralls": "^2.11.2",
|
||||
"istanbul": "^0.3.17",
|
||||
"mocha": "^2.2.5",
|
||||
"should": "^7.0.1",
|
||||
"xo": "^0.7.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"is-arrayish": "^0.3.1"
|
||||
}
|
||||
}
|
29
uni_modules/wu-ui-tools/libs/function/debounce.js
Normal file
29
uni_modules/wu-ui-tools/libs/function/debounce.js
Normal file
@@ -0,0 +1,29 @@
|
||||
let timeout = null
|
||||
|
||||
/**
|
||||
* 防抖原理:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
|
||||
*
|
||||
* @param {Function} func 要执行的回调函数
|
||||
* @param {Number} wait 延时的时间
|
||||
* @param {Boolean} immediate 是否立即执行
|
||||
* @return null
|
||||
*/
|
||||
function debounce(func, wait = 500, immediate = false) {
|
||||
// 清除定时器
|
||||
if (timeout !== null) clearTimeout(timeout)
|
||||
// 立即执行,此类情况一般用不到
|
||||
if (immediate) {
|
||||
const callNow = !timeout
|
||||
timeout = setTimeout(() => {
|
||||
timeout = null
|
||||
}, wait)
|
||||
if (callNow) typeof func === 'function' && func()
|
||||
} else {
|
||||
// 设置定时器,当最后一次操作后,timeout不会再被清除,所以在延时wait毫秒后执行func回调方法
|
||||
timeout = setTimeout(() => {
|
||||
typeof func === 'function' && func()
|
||||
}, wait)
|
||||
}
|
||||
}
|
||||
|
||||
export default debounce
|
167
uni_modules/wu-ui-tools/libs/function/digit.js
Normal file
167
uni_modules/wu-ui-tools/libs/function/digit.js
Normal file
@@ -0,0 +1,167 @@
|
||||
let _boundaryCheckingState = true; // 是否进行越界检查的全局开关
|
||||
|
||||
/**
|
||||
* 把错误的数据转正
|
||||
* @private
|
||||
* @example strip(0.09999999999999998)=0.1
|
||||
*/
|
||||
function strip(num, precision = 15) {
|
||||
return +parseFloat(Number(num).toPrecision(precision));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return digits length of a number
|
||||
* @private
|
||||
* @param {*number} num Input number
|
||||
*/
|
||||
function digitLength(num) {
|
||||
// Get digit length of e
|
||||
const eSplit = num.toString().split(/[eE]/);
|
||||
const len = (eSplit[0].split('.')[1] || '').length - +(eSplit[1] || 0);
|
||||
return len > 0 ? len : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* 把小数转成整数,如果是小数则放大成整数
|
||||
* @private
|
||||
* @param {*number} num 输入数
|
||||
*/
|
||||
function float2Fixed(num) {
|
||||
if (num.toString().indexOf('e') === -1) {
|
||||
return Number(num.toString().replace('.', ''));
|
||||
}
|
||||
const dLen = digitLength(num);
|
||||
return dLen > 0 ? strip(Number(num) * Math.pow(10, dLen)) : Number(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检测数字是否越界,如果越界给出提示
|
||||
* @private
|
||||
* @param {*number} num 输入数
|
||||
*/
|
||||
function checkBoundary(num) {
|
||||
if (_boundaryCheckingState) {
|
||||
if (num > Number.MAX_SAFE_INTEGER || num < Number.MIN_SAFE_INTEGER) {
|
||||
console.warn(`${num} 超出了精度限制,结果可能不正确`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 把递归操作扁平迭代化
|
||||
* @param {number[]} arr 要操作的数字数组
|
||||
* @param {function} operation 迭代操作
|
||||
* @private
|
||||
*/
|
||||
function iteratorOperation(arr, operation) {
|
||||
const [num1, num2, ...others] = arr;
|
||||
let res = operation(num1, num2);
|
||||
|
||||
others.forEach((num) => {
|
||||
res = operation(res, num);
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 高精度乘法
|
||||
* @export
|
||||
*/
|
||||
export function times(...nums) {
|
||||
if (nums.length > 2) {
|
||||
return iteratorOperation(nums, times);
|
||||
}
|
||||
|
||||
const [num1, num2] = nums;
|
||||
const num1Changed = float2Fixed(num1);
|
||||
const num2Changed = float2Fixed(num2);
|
||||
const baseNum = digitLength(num1) + digitLength(num2);
|
||||
const leftValue = num1Changed * num2Changed;
|
||||
|
||||
checkBoundary(leftValue);
|
||||
|
||||
return leftValue / Math.pow(10, baseNum);
|
||||
}
|
||||
|
||||
/**
|
||||
* 高精度加法
|
||||
* @export
|
||||
*/
|
||||
export function plus(...nums) {
|
||||
if (nums.length > 2) {
|
||||
return iteratorOperation(nums, plus);
|
||||
}
|
||||
|
||||
const [num1, num2] = nums;
|
||||
// 取最大的小数位
|
||||
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
|
||||
// 把小数都转为整数然后再计算
|
||||
return (times(num1, baseNum) + times(num2, baseNum)) / baseNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 高精度减法
|
||||
* @export
|
||||
*/
|
||||
export function minus(...nums) {
|
||||
if (nums.length > 2) {
|
||||
return iteratorOperation(nums, minus);
|
||||
}
|
||||
|
||||
const [num1, num2] = nums;
|
||||
const baseNum = Math.pow(10, Math.max(digitLength(num1), digitLength(num2)));
|
||||
return (times(num1, baseNum) - times(num2, baseNum)) / baseNum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 高精度除法
|
||||
* @export
|
||||
*/
|
||||
export function divide(...nums) {
|
||||
if (nums.length > 2) {
|
||||
return iteratorOperation(nums, divide);
|
||||
}
|
||||
|
||||
const [num1, num2] = nums;
|
||||
const num1Changed = float2Fixed(num1);
|
||||
const num2Changed = float2Fixed(num2);
|
||||
checkBoundary(num1Changed);
|
||||
checkBoundary(num2Changed);
|
||||
// 重要,这里必须用strip进行修正
|
||||
return times(num1Changed / num2Changed, strip(Math.pow(10, digitLength(num2) - digitLength(num1))));
|
||||
}
|
||||
|
||||
/**
|
||||
* 四舍五入
|
||||
* @export
|
||||
*/
|
||||
export function round(num, ratio) {
|
||||
const base = Math.pow(10, ratio);
|
||||
let result = divide(Math.round(Math.abs(times(num, base))), base);
|
||||
if (num < 0 && result !== 0) {
|
||||
result = times(result, -1);
|
||||
}
|
||||
// 位数不足则补0
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否进行边界检查,默认开启
|
||||
* @param flag 标记开关,true 为开启,false 为关闭,默认为 true
|
||||
* @export
|
||||
*/
|
||||
export function enableBoundaryChecking(flag = true) {
|
||||
_boundaryCheckingState = flag;
|
||||
}
|
||||
|
||||
|
||||
export default {
|
||||
times,
|
||||
plus,
|
||||
minus,
|
||||
divide,
|
||||
round,
|
||||
enableBoundaryChecking,
|
||||
};
|
||||
|
738
uni_modules/wu-ui-tools/libs/function/index.js
Normal file
738
uni_modules/wu-ui-tools/libs/function/index.js
Normal file
@@ -0,0 +1,738 @@
|
||||
import { number, empty } from './test.js'
|
||||
import { round } from './digit.js'
|
||||
// 颜色操作方法
|
||||
import Color from './color'
|
||||
|
||||
/**
|
||||
* @description 如果value小于min,取min;如果value大于max,取max
|
||||
* @param {number} min
|
||||
* @param {number} max
|
||||
* @param {number} value
|
||||
*/
|
||||
function range(min = 0, max = 0, value = 0) {
|
||||
return Math.max(min, Math.min(max, Number(value)))
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 用于获取用户传递值的px值 如果用户传递了"xxpx"或者"xxrpx",取出其数值部分,如果是"xxxrpx"还需要用过uni.upx2px进行转换
|
||||
* @param {number|string} value 用户传递值的px值
|
||||
* @param {boolean} unit
|
||||
* @returns {number|string}
|
||||
*/
|
||||
function getPx(value, unit = false) {
|
||||
if (number(value)) {
|
||||
return unit ? `${value}px` : Number(value)
|
||||
}
|
||||
// 如果带有rpx,先取出其数值部分,再转为px值
|
||||
if (/(rpx|upx)$/.test(value)) {
|
||||
return unit ? `${uni.upx2px(parseInt(value))}px` : Number(uni.upx2px(parseInt(value)))
|
||||
}
|
||||
return unit ? `${parseInt(value)}px` : parseInt(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 进行延时,以达到可以简写代码的目的 比如: await uni.$w.sleep(20)将会阻塞20ms
|
||||
* @param {number} value 堵塞时间 单位ms 毫秒
|
||||
* @returns {Promise} 返回promise
|
||||
*/
|
||||
function sleep(value = 30) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve()
|
||||
}, value)
|
||||
})
|
||||
}
|
||||
/**
|
||||
* @description 运行期判断平台
|
||||
* @returns {string} 返回所在平台(小写)
|
||||
* @link 运行期判断平台 https://uniapp.dcloud.io/frame?id=判断平台
|
||||
*/
|
||||
function os() {
|
||||
return uni.getSystemInfoSync().platform.toLowerCase()
|
||||
}
|
||||
/**
|
||||
* @description 获取系统信息同步接口
|
||||
* @link 获取系统信息同步接口 https://uniapp.dcloud.io/api/system/info?id=getsysteminfosync
|
||||
*/
|
||||
function sys() {
|
||||
return uni.getSystemInfoSync()
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 取一个区间数
|
||||
* @param {Number} min 最小值
|
||||
* @param {Number} max 最大值
|
||||
*/
|
||||
function random(min, max) {
|
||||
if (min >= 0 && max > 0 && max >= min) {
|
||||
const gab = max - min + 1
|
||||
return Math.floor(Math.random() * gab + min)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Number} len uuid的长度
|
||||
* @param {Boolean} firstU 将返回的首字母置为"u"
|
||||
* @param {Nubmer} radix 生成uuid的基数(意味着返回的字符串都是这个基数),2-二进制,8-八进制,10-十进制,16-十六进制
|
||||
*/
|
||||
function guid(len = 32, firstU = true, radix = null) {
|
||||
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('')
|
||||
const uuid = []
|
||||
radix = radix || chars.length
|
||||
|
||||
if (len) {
|
||||
// 如果指定uuid长度,只是取随机的字符,0|x为位运算,能去掉x的小数位,返回整数位
|
||||
for (let i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix]
|
||||
} else {
|
||||
let r
|
||||
// rfc4122标准要求返回的uuid中,某些位为固定的字符
|
||||
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'
|
||||
uuid[14] = '4'
|
||||
|
||||
for (let i = 0; i < 36; i++) {
|
||||
if (!uuid[i]) {
|
||||
r = 0 | Math.random() * 16
|
||||
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]
|
||||
}
|
||||
}
|
||||
}
|
||||
// 移除第一个字符,并用u替代,因为第一个字符为数值时,该guuid不能用作id或者class
|
||||
if (firstU) {
|
||||
uuid.shift()
|
||||
return `u${uuid.join('')}`
|
||||
}
|
||||
return uuid.join('')
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取父组件的参数,因为支付宝小程序不支持provide/inject的写法
|
||||
this.$parent在非H5中,可以准确获取到父组件,但是在H5中,需要多次this.$parent.$parent.xxx
|
||||
这里默认值等于undefined有它的含义,因为最顶层元素(组件)的$parent就是undefined,意味着不传name
|
||||
值(默认为undefined),就是查找最顶层的$parent
|
||||
* @param {string|undefined} name 父组件的参数名
|
||||
*/
|
||||
function $parent(name = undefined) {
|
||||
let parent = this.$parent
|
||||
// 通过while历遍,这里主要是为了H5需要多层解析的问题
|
||||
while (parent) {
|
||||
// 父组件
|
||||
if (parent.$options && parent.$options.name !== name) {
|
||||
// 如果组件的name不相等,继续上一级寻找
|
||||
parent = parent.$parent
|
||||
} else {
|
||||
return parent
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 样式转换
|
||||
* 对象转字符串,或者字符串转对象
|
||||
* @param {object | string} customStyle 需要转换的目标
|
||||
* @param {String} target 转换的目的,object-转为对象,string-转为字符串
|
||||
* @returns {object|string}
|
||||
*/
|
||||
function addStyle(customStyle, target = 'object') {
|
||||
// 字符串转字符串,对象转对象情形,直接返回
|
||||
if (empty(customStyle) || typeof(customStyle) === 'object' && target === 'object' || target === 'string' &&
|
||||
typeof(customStyle) === 'string') {
|
||||
return customStyle
|
||||
}
|
||||
// 字符串转对象
|
||||
if (target === 'object') {
|
||||
// 去除字符串样式中的两端空格(中间的空格不能去掉,比如padding: 20px 0如果去掉了就错了),空格是无用的
|
||||
customStyle = trim(customStyle)
|
||||
// 根据";"将字符串转为数组形式
|
||||
const styleArray = customStyle.split(';')
|
||||
const style = {}
|
||||
// 历遍数组,拼接成对象
|
||||
for (let i = 0; i < styleArray.length; i++) {
|
||||
// 'font-size:20px;color:red;',如此最后字符串有";"的话,会导致styleArray最后一个元素为空字符串,这里需要过滤
|
||||
if (styleArray[i]) {
|
||||
const item = styleArray[i].split(':')
|
||||
style[trim(item[0])] = trim(item[1])
|
||||
}
|
||||
}
|
||||
return style
|
||||
}
|
||||
// 这里为对象转字符串形式
|
||||
let string = ''
|
||||
for (const i in customStyle) {
|
||||
// 驼峰转为中划线的形式,否则css内联样式,无法识别驼峰样式属性名
|
||||
const key = i.replace(/([A-Z])/g, '-$1').toLowerCase()
|
||||
string += `${key}:${customStyle[i]};`
|
||||
}
|
||||
// 去除两端空格
|
||||
return trim(string)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 添加单位,如果有rpx,upx,%,px等单位结尾或者值为auto,直接返回,否则加上px单位结尾
|
||||
* @param {string|number} value 需要添加单位的值
|
||||
* @param {string} unit 添加的单位名 比如px
|
||||
*/
|
||||
function addUnit(value = 'auto', unit = uni?.$w?.config?.unit ? uni?.$w?.config?.unit : 'px') {
|
||||
value = String(value)
|
||||
// 用wuui内置验证规则中的number判断是否为数值
|
||||
return number(value) ? `${value}${unit}` : value
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 深度克隆
|
||||
* @param {object} obj 需要深度克隆的对象
|
||||
* @param cache 缓存
|
||||
* @returns {*} 克隆后的对象或者原值(不是对象)
|
||||
*/
|
||||
function deepClone(obj, cache = new WeakMap()) {
|
||||
if (obj === null || typeof obj !== 'object') return obj;
|
||||
if (cache.has(obj)) return cache.get(obj);
|
||||
let clone;
|
||||
if (obj instanceof Date) {
|
||||
clone = new Date(obj.getTime());
|
||||
} else if (obj instanceof RegExp) {
|
||||
clone = new RegExp(obj);
|
||||
} else if (obj instanceof Map) {
|
||||
clone = new Map(Array.from(obj, ([key, value]) => [key, deepClone(value, cache)]));
|
||||
} else if (obj instanceof Set) {
|
||||
clone = new Set(Array.from(obj, value => deepClone(value, cache)));
|
||||
} else if (Array.isArray(obj)) {
|
||||
clone = obj.map(value => deepClone(value, cache));
|
||||
} else if (Object.prototype.toString.call(obj) === '[object Object]') {
|
||||
clone = Object.create(Object.getPrototypeOf(obj));
|
||||
cache.set(obj, clone);
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
clone[key] = deepClone(value, cache);
|
||||
}
|
||||
} else {
|
||||
clone = Object.assign({}, obj);
|
||||
}
|
||||
cache.set(obj, clone);
|
||||
return clone;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description JS对象深度合并
|
||||
* @param {object} target 需要拷贝的对象
|
||||
* @param {object} source 拷贝的来源对象
|
||||
* @returns {object|boolean} 深度合并后的对象或者false(入参有不是对象)
|
||||
*/
|
||||
function deepMerge(target = {}, source = {}) {
|
||||
target = deepClone(target)
|
||||
if (typeof target !== 'object' || target === null || typeof source !== 'object' || source === null) return target;
|
||||
const merged = Array.isArray(target) ? target.slice() : Object.assign({}, target);
|
||||
for (const prop in source) {
|
||||
if (!source.hasOwnProperty(prop)) continue;
|
||||
const sourceValue = source[prop];
|
||||
const targetValue = merged[prop];
|
||||
if (sourceValue instanceof Date) {
|
||||
merged[prop] = new Date(sourceValue);
|
||||
} else if (sourceValue instanceof RegExp) {
|
||||
merged[prop] = new RegExp(sourceValue);
|
||||
} else if (sourceValue instanceof Map) {
|
||||
merged[prop] = new Map(sourceValue);
|
||||
} else if (sourceValue instanceof Set) {
|
||||
merged[prop] = new Set(sourceValue);
|
||||
} else if (typeof sourceValue === 'object' && sourceValue !== null) {
|
||||
merged[prop] = deepMerge(targetValue, sourceValue);
|
||||
} else {
|
||||
merged[prop] = sourceValue;
|
||||
}
|
||||
}
|
||||
return merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description error提示
|
||||
* @param {*} err 错误内容
|
||||
*/
|
||||
function error(err) {
|
||||
// 开发环境才提示,生产环境不会提示
|
||||
if (process.env.NODE_ENV === 'development') {
|
||||
console.error(`wuui提示:${err}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 打乱数组
|
||||
* @param {array} array 需要打乱的数组
|
||||
* @returns {array} 打乱后的数组
|
||||
*/
|
||||
function randomArray(array = []) {
|
||||
// 原理是sort排序,Math.random()产生0<= x < 1之间的数,会导致x-0.05大于或者小于0
|
||||
return array.sort(() => Math.random() - 0.5)
|
||||
}
|
||||
|
||||
// padStart 的 polyfill,因为某些机型或情况,还无法支持es7的padStart,比如电脑版的微信小程序
|
||||
// 所以这里做一个兼容polyfill的兼容处理
|
||||
if (!String.prototype.padStart) {
|
||||
// 为了方便表示这里 fillString 用了ES6 的默认参数,不影响理解
|
||||
String.prototype.padStart = function(maxLength, fillString = ' ') {
|
||||
if (Object.prototype.toString.call(fillString) !== '[object String]') {
|
||||
throw new TypeError(
|
||||
'fillString must be String'
|
||||
)
|
||||
}
|
||||
const str = this
|
||||
// 返回 String(str) 这里是为了使返回的值是字符串字面量,在控制台中更符合直觉
|
||||
if (str.length >= maxLength) return String(str)
|
||||
|
||||
const fillLength = maxLength - str.length
|
||||
let times = Math.ceil(fillLength / fillString.length)
|
||||
while (times >>= 1) {
|
||||
fillString += fillString
|
||||
if (times === 1) {
|
||||
fillString += fillString
|
||||
}
|
||||
}
|
||||
return fillString.slice(0, fillLength) + str
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 格式化时间
|
||||
* @param {String|Number} dateTime 需要格式化的时间戳
|
||||
* @param {String} fmt 格式化规则 yyyy:mm:dd|yyyy:mm|yyyy年mm月dd日|yyyy年mm月dd日 hh时MM分等,可自定义组合 默认yyyy-mm-dd
|
||||
* @returns {string} 返回格式化后的字符串
|
||||
*/
|
||||
function timeFormat(dateTime = null, formatStr = 'yyyy-mm-dd') {
|
||||
let date
|
||||
// 若传入时间为假值,则取当前时间
|
||||
if (!dateTime) {
|
||||
date = new Date()
|
||||
}
|
||||
// 若为unix秒时间戳,则转为毫秒时间戳(逻辑有点奇怪,但不敢改,以保证历史兼容)
|
||||
else if (/^\d{10}$/.test(dateTime?.toString().trim())) {
|
||||
date = new Date(dateTime * 1000)
|
||||
}
|
||||
// 若用户传入字符串格式时间戳,new Date无法解析,需做兼容
|
||||
else if (typeof dateTime === 'string' && /^\d+$/.test(dateTime.trim())) {
|
||||
date = new Date(Number(dateTime))
|
||||
}
|
||||
// 处理平台性差异,在Safari/Webkit中,new Date仅支持/作为分割符的字符串时间
|
||||
// 处理 '2022-07-10 01:02:03',跳过 '2022-07-10T01:02:03'
|
||||
else if (typeof dateTime === 'string' && dateTime.includes('-') && !dateTime.includes('T')) {
|
||||
date = new Date(dateTime.replace(/-/g, '/'))
|
||||
}
|
||||
// 其他都认为符合 RFC 2822 规范
|
||||
else {
|
||||
date = new Date(dateTime)
|
||||
}
|
||||
|
||||
const timeSource = {
|
||||
'y': date.getFullYear().toString(), // 年
|
||||
'm': (date.getMonth() + 1).toString().padStart(2, '0'), // 月
|
||||
'd': date.getDate().toString().padStart(2, '0'), // 日
|
||||
'h': date.getHours().toString().padStart(2, '0'), // 时
|
||||
'M': date.getMinutes().toString().padStart(2, '0'), // 分
|
||||
's': date.getSeconds().toString().padStart(2, '0') // 秒
|
||||
// 有其他格式化字符需求可以继续添加,必须转化成字符串
|
||||
}
|
||||
|
||||
for (const key in timeSource) {
|
||||
const [ret] = new RegExp(`${key}+`).exec(formatStr) || []
|
||||
if (ret) {
|
||||
// 年可能只需展示两位
|
||||
const beginIndex = key === 'y' && ret.length === 2 ? 2 : 0
|
||||
formatStr = formatStr.replace(ret, timeSource[key].slice(beginIndex))
|
||||
}
|
||||
}
|
||||
|
||||
return formatStr
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 时间戳转为多久之前
|
||||
* @param {String|Number} timestamp 时间戳
|
||||
* @param {String|Boolean} format
|
||||
* 格式化规则如果为时间格式字符串,超出一定时间范围,返回固定的时间格式;
|
||||
* 如果为布尔值false,无论什么时间,都返回多久以前的格式
|
||||
* @returns {string} 转化后的内容
|
||||
*/
|
||||
function timeFrom(timestamp = null, format = 'yyyy-mm-dd') {
|
||||
if (timestamp == null) timestamp = Number(new Date())
|
||||
timestamp = parseInt(timestamp)
|
||||
// 判断用户输入的时间戳是秒还是毫秒,一般前端js获取的时间戳是毫秒(13位),后端传过来的为秒(10位)
|
||||
if (timestamp.toString().length == 10) timestamp *= 1000
|
||||
let timer = (new Date()).getTime() - timestamp
|
||||
timer = parseInt(timer / 1000)
|
||||
// 如果小于5分钟,则返回"刚刚",其他以此类推
|
||||
let tips = ''
|
||||
switch (true) {
|
||||
case timer < 300:
|
||||
tips = '刚刚'
|
||||
break
|
||||
case timer >= 300 && timer < 3600:
|
||||
tips = `${parseInt(timer / 60)}分钟前`
|
||||
break
|
||||
case timer >= 3600 && timer < 86400:
|
||||
tips = `${parseInt(timer / 3600)}小时前`
|
||||
break
|
||||
case timer >= 86400 && timer < 2592000:
|
||||
tips = `${parseInt(timer / 86400)}天前`
|
||||
break
|
||||
default:
|
||||
// 如果format为false,则无论什么时间戳,都显示xx之前
|
||||
if (format === false) {
|
||||
if (timer >= 2592000 && timer < 365 * 86400) {
|
||||
tips = `${parseInt(timer / (86400 * 30))}个月前`
|
||||
} else {
|
||||
tips = `${parseInt(timer / (86400 * 365))}年前`
|
||||
}
|
||||
} else {
|
||||
tips = timeFormat(timestamp, format)
|
||||
}
|
||||
}
|
||||
return tips
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 去除空格
|
||||
* @param String str 需要去除空格的字符串
|
||||
* @param String pos both(左右)|left|right|all 默认both
|
||||
*/
|
||||
function trim(str, pos = 'both') {
|
||||
str = String(str)
|
||||
if (pos == 'both') {
|
||||
return str.replace(/^\s+|\s+$/g, '')
|
||||
}
|
||||
if (pos == 'left') {
|
||||
return str.replace(/^\s*/, '')
|
||||
}
|
||||
if (pos == 'right') {
|
||||
return str.replace(/(\s*$)/g, '')
|
||||
}
|
||||
if (pos == 'all') {
|
||||
return str.replace(/\s+/g, '')
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 对象转url参数
|
||||
* @param {object} data,对象
|
||||
* @param {Boolean} isPrefix,是否自动加上"?"
|
||||
* @param {string} arrayFormat 规则 indices|brackets|repeat|comma
|
||||
*/
|
||||
function queryParams(data = {}, isPrefix = true, arrayFormat = 'brackets') {
|
||||
const prefix = isPrefix ? '?' : ''
|
||||
const _result = []
|
||||
if (['indices', 'brackets', 'repeat', 'comma'].indexOf(arrayFormat) == -1) arrayFormat = 'brackets'
|
||||
for (const key in data) {
|
||||
const value = data[key]
|
||||
// 去掉为空的参数
|
||||
if (['', undefined, null].indexOf(value) >= 0) {
|
||||
continue
|
||||
}
|
||||
// 如果值为数组,另行处理
|
||||
if (value.constructor === Array) {
|
||||
// e.g. {ids: [1, 2, 3]}
|
||||
switch (arrayFormat) {
|
||||
case 'indices':
|
||||
// 结果: ids[0]=1&ids[1]=2&ids[2]=3
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
_result.push(`${key}[${i}]=${value[i]}`)
|
||||
}
|
||||
break
|
||||
case 'brackets':
|
||||
// 结果: ids[]=1&ids[]=2&ids[]=3
|
||||
value.forEach((_value) => {
|
||||
_result.push(`${key}[]=${_value}`)
|
||||
})
|
||||
break
|
||||
case 'repeat':
|
||||
// 结果: ids=1&ids=2&ids=3
|
||||
value.forEach((_value) => {
|
||||
_result.push(`${key}=${_value}`)
|
||||
})
|
||||
break
|
||||
case 'comma':
|
||||
// 结果: ids=1,2,3
|
||||
let commaStr = ''
|
||||
value.forEach((_value) => {
|
||||
commaStr += (commaStr ? ',' : '') + _value
|
||||
})
|
||||
_result.push(`${key}=${commaStr}`)
|
||||
break
|
||||
default:
|
||||
value.forEach((_value) => {
|
||||
_result.push(`${key}[]=${_value}`)
|
||||
})
|
||||
}
|
||||
} else {
|
||||
_result.push(`${key}=${value}`)
|
||||
}
|
||||
}
|
||||
return _result.length ? prefix + _result.join('&') : ''
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示消息提示框
|
||||
* @param {String} title 提示的内容,长度与 icon 取值有关。
|
||||
* @param {Number} duration 提示的延迟时间,单位毫秒,默认:2000
|
||||
*/
|
||||
function toast(title, duration = 2000) {
|
||||
uni.showToast({
|
||||
title: String(title),
|
||||
icon: 'none',
|
||||
duration
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据主题type值,获取对应的图标
|
||||
* @param {String} type 主题名称,primary|info|error|warning|success
|
||||
* @param {boolean} fill 是否使用fill填充实体的图标
|
||||
*/
|
||||
function type2icon(type = 'success', fill = false) {
|
||||
// 如果非预置值,默认为success
|
||||
if (['primary', 'info', 'error', 'warning', 'success'].indexOf(type) == -1) type = 'success'
|
||||
let iconName = ''
|
||||
// 目前(2019-12-12),info和primary使用同一个图标
|
||||
switch (type) {
|
||||
case 'primary':
|
||||
iconName = 'info-circle'
|
||||
break
|
||||
case 'info':
|
||||
iconName = 'info-circle'
|
||||
break
|
||||
case 'error':
|
||||
iconName = 'close-circle'
|
||||
break
|
||||
case 'warning':
|
||||
iconName = 'error-circle'
|
||||
break
|
||||
case 'success':
|
||||
iconName = 'checkmark-circle'
|
||||
break
|
||||
default:
|
||||
iconName = 'checkmark-circle'
|
||||
}
|
||||
// 是否是实体类型,加上-fill,在icon组件库中,实体的类名是后面加-fill的
|
||||
if (fill) iconName += '-fill'
|
||||
return iconName
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 数字格式化
|
||||
* @param {number|string} number 要格式化的数字
|
||||
* @param {number} decimals 保留几位小数
|
||||
* @param {string} decimalPoint 小数点符号
|
||||
* @param {string} thousandsSeparator 千分位符号
|
||||
* @returns {string} 格式化后的数字
|
||||
*/
|
||||
function priceFormat(number, decimals = 0, decimalPoint = '.', thousandsSeparator = ',') {
|
||||
number = (`${number}`).replace(/[^0-9+-Ee.]/g, '')
|
||||
const n = !isFinite(+number) ? 0 : +number
|
||||
const prec = !isFinite(+decimals) ? 0 : Math.abs(decimals)
|
||||
const sep = (typeof thousandsSeparator === 'undefined') ? ',' : thousandsSeparator
|
||||
const dec = (typeof decimalPoint === 'undefined') ? '.' : decimalPoint
|
||||
let s = ''
|
||||
|
||||
s = (prec ? round(n, prec) + '' : `${Math.round(n)}`).split('.')
|
||||
const re = /(-?\d+)(\d{3})/
|
||||
while (re.test(s[0])) {
|
||||
s[0] = s[0].replace(re, `$1${sep}$2`)
|
||||
}
|
||||
|
||||
if ((s[1] || '').length < prec) {
|
||||
s[1] = s[1] || ''
|
||||
s[1] += new Array(prec - s[1].length + 1).join('0')
|
||||
}
|
||||
return s.join(dec)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取duration值
|
||||
* 如果带有ms或者s直接返回,如果大于一定值,认为是ms单位,小于一定值,认为是s单位
|
||||
* 比如以30位阈值,那么300大于30,可以理解为用户想要的是300ms,而不是想花300s去执行一个动画
|
||||
* @param {String|number} value 比如: "1s"|"100ms"|1|100
|
||||
* @param {boolean} unit 提示: 如果是false 默认返回number
|
||||
* @return {string|number}
|
||||
*/
|
||||
function getDuration(value, unit = true) {
|
||||
const valueNum = parseInt(value)
|
||||
if (unit) {
|
||||
if (/s$/.test(value)) return value
|
||||
return value > 30 ? `${value}ms` : `${value}s`
|
||||
}
|
||||
if (/ms$/.test(value)) return valueNum
|
||||
if (/s$/.test(value)) return valueNum > 30 ? valueNum : valueNum * 1000
|
||||
return valueNum
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 日期的月或日补零操作
|
||||
* @param {String} value 需要补零的值
|
||||
*/
|
||||
function padZero(value) {
|
||||
return `00${value}`.slice(-2)
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 在wu-form的子组件内容发生变化,或者失去焦点时,尝试通知wu-form执行校验方法
|
||||
* @param {*} instance
|
||||
* @param {*} event
|
||||
*/
|
||||
function formValidate(instance, event) {
|
||||
const formItem = $parent.call(instance, 'wu-form-item')
|
||||
const form = $parent.call(instance, 'wu-form')
|
||||
// 如果发生变化的input或者textarea等,其父组件中有wu-form-item或者wu-form等,就执行form的validate方法
|
||||
// 同时将form-item的pros传递给form,让其进行精确对象验证
|
||||
if (formItem && form) {
|
||||
form.validateField(formItem.prop, () => {}, event)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取某个对象下的属性,用于通过类似'a.b.c'的形式去获取一个对象的的属性的形式
|
||||
* @param {object} obj 对象
|
||||
* @param {string} key 需要获取的属性字段
|
||||
* @returns {*}
|
||||
*/
|
||||
function getProperty(obj, key) {
|
||||
if (!obj) {
|
||||
return
|
||||
}
|
||||
if (typeof key !== 'string' || key === '') {
|
||||
return ''
|
||||
}
|
||||
if (key.indexOf('.') !== -1) {
|
||||
const keys = key.split('.')
|
||||
let firstObj = obj[keys[0]] || {}
|
||||
|
||||
for (let i = 1; i < keys.length; i++) {
|
||||
if (firstObj) {
|
||||
firstObj = firstObj[keys[i]]
|
||||
}
|
||||
}
|
||||
return firstObj
|
||||
}
|
||||
return obj[key]
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 设置对象的属性值,如果'a.b.c'的形式进行设置
|
||||
* @param {object} obj 对象
|
||||
* @param {string} key 需要设置的属性
|
||||
* @param {string} value 设置的值
|
||||
*/
|
||||
function setProperty(obj, key, value) {
|
||||
if (!obj) {
|
||||
return
|
||||
}
|
||||
// 递归赋值
|
||||
const inFn = function(_obj, keys, v) {
|
||||
// 最后一个属性key
|
||||
if (keys.length === 1) {
|
||||
_obj[keys[0]] = v
|
||||
return
|
||||
}
|
||||
// 0~length-1个key
|
||||
while (keys.length > 1) {
|
||||
const k = keys[0]
|
||||
if (!_obj[k] || (typeof _obj[k] !== 'object')) {
|
||||
_obj[k] = {}
|
||||
}
|
||||
const key = keys.shift()
|
||||
// 自调用判断是否存在属性,不存在则自动创建对象
|
||||
inFn(_obj[k], keys, v)
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof key !== 'string' || key === '') {
|
||||
|
||||
} else if (key.indexOf('.') !== -1) { // 支持多层级赋值操作
|
||||
const keys = key.split('.')
|
||||
inFn(obj, keys, value)
|
||||
} else {
|
||||
obj[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取当前页面路径
|
||||
*/
|
||||
function page() {
|
||||
const pages = getCurrentPages();
|
||||
const route = pages[pages.length - 1]?.route;
|
||||
// 某些特殊情况下(比如页面进行redirectTo时的一些时机),pages可能为空数组
|
||||
return `/${route ? route : ''}`
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 获取当前路由栈实例数组
|
||||
*/
|
||||
function pages() {
|
||||
const pages = getCurrentPages()
|
||||
return pages
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取页面历史栈指定层实例
|
||||
* @param back {number} [0] - 0或者负数,表示获取历史栈的哪一层,0表示获取当前页面实例,-1 表示获取上一个页面实例。默认0。
|
||||
*/
|
||||
function getHistoryPage(back = 0) {
|
||||
const pages = getCurrentPages()
|
||||
const len = pages.length
|
||||
return pages[len - 1 + back]
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @description 修改wuui内置属性值
|
||||
* @param {object} props 修改内置props属性
|
||||
* @param {object} config 修改内置config属性
|
||||
* @param {object} color 修改内置color属性
|
||||
* @param {object} zIndex 修改内置zIndex属性
|
||||
*/
|
||||
function setConfig({
|
||||
props = {},
|
||||
config = {},
|
||||
color = {},
|
||||
zIndex = {}
|
||||
}) {
|
||||
const {
|
||||
deepMerge,
|
||||
} = uni.$w
|
||||
uni.$w.config = deepMerge(uni.$w.config, config)
|
||||
uni.$w.props = deepMerge(uni.$w.props, props)
|
||||
uni.$w.color = deepMerge(uni.$w.color, color)
|
||||
uni.$w.zIndex = deepMerge(uni.$w.zIndex, zIndex)
|
||||
}
|
||||
|
||||
export {
|
||||
range,
|
||||
getPx,
|
||||
sleep,
|
||||
os,
|
||||
sys,
|
||||
random,
|
||||
guid,
|
||||
$parent,
|
||||
addStyle,
|
||||
addUnit,
|
||||
deepClone,
|
||||
deepMerge,
|
||||
error,
|
||||
randomArray,
|
||||
timeFormat,
|
||||
timeFrom,
|
||||
trim,
|
||||
queryParams,
|
||||
toast,
|
||||
type2icon,
|
||||
priceFormat,
|
||||
getDuration,
|
||||
padZero,
|
||||
formValidate,
|
||||
getProperty,
|
||||
setProperty,
|
||||
page,
|
||||
pages,
|
||||
getHistoryPage,
|
||||
setConfig,
|
||||
Color
|
||||
}
|
75
uni_modules/wu-ui-tools/libs/function/platform.js
Normal file
75
uni_modules/wu-ui-tools/libs/function/platform.js
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 注意:
|
||||
* 此部分内容,在vue-cli模式下,需要在vue.config.js加入如下内容才有效:
|
||||
* module.exports = {
|
||||
* transpileDependencies: ['uview-v2']
|
||||
* }
|
||||
*/
|
||||
|
||||
let platform = 'none'
|
||||
|
||||
// #ifdef VUE3
|
||||
platform = 'vue3'
|
||||
// #endif
|
||||
|
||||
// #ifdef VUE2
|
||||
platform = 'vue2'
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-PLUS
|
||||
platform = 'plus'
|
||||
// #endif
|
||||
|
||||
// #ifdef APP-NVUE
|
||||
platform = 'nvue'
|
||||
// #endif
|
||||
|
||||
// #ifdef H5
|
||||
platform = 'h5'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-WEIXIN
|
||||
platform = 'weixin'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-ALIPAY
|
||||
platform = 'alipay'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-BAIDU
|
||||
platform = 'baidu'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-TOUTIAO
|
||||
platform = 'toutiao'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-QQ
|
||||
platform = 'qq'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-KUAISHOU
|
||||
platform = 'kuaishou'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP-360
|
||||
platform = '360'
|
||||
// #endif
|
||||
|
||||
// #ifdef MP
|
||||
platform = 'mp'
|
||||
// #endif
|
||||
|
||||
// #ifdef QUICKAPP-WEBVIEW
|
||||
platform = 'quickapp-webview'
|
||||
// #endif
|
||||
|
||||
// #ifdef QUICKAPP-WEBVIEW-HUAWEI
|
||||
platform = 'quickapp-webview-huawei'
|
||||
// #endif
|
||||
|
||||
// #ifdef QUICKAPP-WEBVIEW-UNION
|
||||
platform = 'quckapp-webview-union'
|
||||
// #endif
|
||||
|
||||
export default platform
|
287
uni_modules/wu-ui-tools/libs/function/test.js
Normal file
287
uni_modules/wu-ui-tools/libs/function/test.js
Normal file
@@ -0,0 +1,287 @@
|
||||
/**
|
||||
* 验证电子邮箱格式
|
||||
*/
|
||||
function email(value) {
|
||||
return /^\w+((-\w+)|(\.\w+))*\@[A-Za-z0-9]+((\.|-)[A-Za-z0-9]+)*\.[A-Za-z0-9]+$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证手机格式
|
||||
*/
|
||||
function mobile(value) {
|
||||
return /^1([3589]\d|4[5-9]|6[1-2,4-7]|7[0-8])\d{8}$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证URL格式
|
||||
*/
|
||||
function url(value) {
|
||||
return /^((https|http|ftp|rtsp|mms):\/\/)(([0-9a-zA-Z_!~*'().&=+$%-]+: )?[0-9a-zA-Z_!~*'().&=+$%-]+@)?(([0-9]{1,3}.){3}[0-9]{1,3}|([0-9a-zA-Z_!~*'()-]+.)*([0-9a-zA-Z][0-9a-zA-Z-]{0,61})?[0-9a-zA-Z].[a-zA-Z]{2,6})(:[0-9]{1,4})?((\/?)|(\/[0-9a-zA-Z_!~*'().;?:@&=+$,%#-]+)+\/?)$/
|
||||
.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证日期格式
|
||||
*/
|
||||
function date(value) {
|
||||
if (!value) return false
|
||||
// 判断是否数值或者字符串数值(意味着为时间戳),转为数值,否则new Date无法识别字符串时间戳
|
||||
if (number(value)) value = +value
|
||||
return !/Invalid|NaN/.test(new Date(value).toString())
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证ISO类型的日期格式
|
||||
*/
|
||||
function dateISO(value) {
|
||||
return /^\d{4}[\/\-](0?[1-9]|1[012])[\/\-](0?[1-9]|[12][0-9]|3[01])$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证十进制数字
|
||||
*/
|
||||
function number(value) {
|
||||
return /^[\+-]?(\d+\.?\d*|\.\d+|\d\.\d+e\+\d+)$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证字符串
|
||||
*/
|
||||
function string(value) {
|
||||
return typeof value === 'string'
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证整数
|
||||
*/
|
||||
function digits(value) {
|
||||
return /^\d+$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证身份证号码
|
||||
*/
|
||||
function idCard(value) {
|
||||
return /^[1-9]\d{5}[1-9]\d{3}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}([0-9]|X)$/.test(
|
||||
value
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否车牌号
|
||||
*/
|
||||
function carNo(value) {
|
||||
// 新能源车牌
|
||||
const xreg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}(([0-9]{5}[DF]$)|([DF][A-HJ-NP-Z0-9][0-9]{4}$))/
|
||||
// 旧车牌
|
||||
const creg = /^[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领A-Z]{1}[A-Z]{1}[A-HJ-NP-Z0-9]{4}[A-HJ-NP-Z0-9挂学警港澳]{1}$/
|
||||
if (value.length === 7) {
|
||||
return creg.test(value)
|
||||
} if (value.length === 8) {
|
||||
return xreg.test(value)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 金额,只允许2位小数
|
||||
*/
|
||||
function amount(value) {
|
||||
// 金额,只允许保留两位小数
|
||||
return /^[1-9]\d*(,\d{3})*(\.\d{1,2})?$|^0\.\d{1,2}$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 中文
|
||||
*/
|
||||
function chinese(value) {
|
||||
const reg = /^[\u4e00-\u9fa5]+$/gi
|
||||
return reg.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 只能输入字母
|
||||
*/
|
||||
function letter(value) {
|
||||
return /^[a-zA-Z]*$/.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 只能是字母或者数字
|
||||
*/
|
||||
function enOrNum(value) {
|
||||
// 英文或者数字
|
||||
const reg = /^[0-9a-zA-Z]*$/g
|
||||
return reg.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证是否包含某个值
|
||||
*/
|
||||
function contains(value, param) {
|
||||
return value.indexOf(param) >= 0
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证一个值范围[min, max]
|
||||
*/
|
||||
function range(value, param) {
|
||||
return value >= param[0] && value <= param[1]
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证一个长度范围[min, max]
|
||||
*/
|
||||
function rangeLength(value, param) {
|
||||
return value.length >= param[0] && value.length <= param[1]
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否固定电话
|
||||
*/
|
||||
function landline(value) {
|
||||
const reg = /^\d{3,4}-\d{7,8}(-\d{3,4})?$/
|
||||
return reg.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断是否为空
|
||||
*/
|
||||
function empty(value) {
|
||||
switch (typeof value) {
|
||||
case 'undefined':
|
||||
return true
|
||||
case 'string':
|
||||
if (value.replace(/(^[ \t\n\r]*)|([ \t\n\r]*$)/g, '').length == 0) return true
|
||||
break
|
||||
case 'boolean':
|
||||
if (!value) return true
|
||||
break
|
||||
case 'number':
|
||||
if (value === 0 || isNaN(value)) return true
|
||||
break
|
||||
case 'object':
|
||||
if (value === null || value.length === 0) return true
|
||||
for (const i in value) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否json字符串
|
||||
*/
|
||||
function jsonString(value) {
|
||||
if (typeof value === 'string') {
|
||||
try {
|
||||
const obj = JSON.parse(value)
|
||||
if (typeof obj === 'object' && obj) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否数组
|
||||
*/
|
||||
function array(value) {
|
||||
if (typeof Array.isArray === 'function') {
|
||||
return Array.isArray(value)
|
||||
}
|
||||
return Object.prototype.toString.call(value) === '[object Array]'
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否对象
|
||||
*/
|
||||
function object(value) {
|
||||
return Object.prototype.toString.call(value) === '[object Object]'
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否短信验证码
|
||||
*/
|
||||
function code(value, len = 6) {
|
||||
return new RegExp(`^\\d{${len}}$`).test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否函数方法
|
||||
* @param {Object} value
|
||||
*/
|
||||
function func(value) {
|
||||
return typeof value === 'function'
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否promise对象
|
||||
* @param {Object} value
|
||||
*/
|
||||
function promise(value) {
|
||||
return object(value) && func(value.then) && func(value.catch)
|
||||
}
|
||||
|
||||
/** 是否图片格式
|
||||
* @param {Object} value
|
||||
*/
|
||||
function image(value) {
|
||||
const newValue = value.split('?')[0]
|
||||
const IMAGE_REGEXP = /\.(jpeg|jpg|gif|png|svg|webp|jfif|bmp|dpg)/i
|
||||
return IMAGE_REGEXP.test(newValue)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否视频格式
|
||||
* @param {Object} value
|
||||
*/
|
||||
function video(value) {
|
||||
const VIDEO_REGEXP = /\.(mp4|mpg|mpeg|dat|asf|avi|rm|rmvb|mov|wmv|flv|mkv|m3u8)/i
|
||||
return VIDEO_REGEXP.test(value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为正则对象
|
||||
* @param {Object}
|
||||
* @return {Boolean}
|
||||
*/
|
||||
function regExp(o) {
|
||||
return o && Object.prototype.toString.call(o) === '[object RegExp]'
|
||||
}
|
||||
|
||||
export {
|
||||
email,
|
||||
mobile,
|
||||
url,
|
||||
date,
|
||||
dateISO,
|
||||
number,
|
||||
digits,
|
||||
idCard,
|
||||
carNo,
|
||||
amount,
|
||||
chinese,
|
||||
letter,
|
||||
enOrNum,
|
||||
contains,
|
||||
range,
|
||||
rangeLength,
|
||||
empty,
|
||||
jsonString,
|
||||
landline,
|
||||
object,
|
||||
array,
|
||||
code,
|
||||
func,
|
||||
promise,
|
||||
video,
|
||||
image,
|
||||
regExp,
|
||||
string
|
||||
}
|
30
uni_modules/wu-ui-tools/libs/function/throttle.js
Normal file
30
uni_modules/wu-ui-tools/libs/function/throttle.js
Normal file
@@ -0,0 +1,30 @@
|
||||
let timer; let
|
||||
flag
|
||||
/**
|
||||
* 节流原理:在一定时间内,只能触发一次
|
||||
*
|
||||
* @param {Function} func 要执行的回调函数
|
||||
* @param {Number} wait 延时的时间
|
||||
* @param {Boolean} immediate 是否立即执行
|
||||
* @return null
|
||||
*/
|
||||
function throttle(func, wait = 500, immediate = true) {
|
||||
if (immediate) {
|
||||
if (!flag) {
|
||||
flag = true
|
||||
// 如果是立即执行,则在wait毫秒内开始时执行
|
||||
typeof func === 'function' && func()
|
||||
timer = setTimeout(() => {
|
||||
flag = false
|
||||
}, wait)
|
||||
}
|
||||
} else if (!flag) {
|
||||
flag = true
|
||||
// 如果是非立即执行,则在wait毫秒内的结束处执行
|
||||
timer = setTimeout(() => {
|
||||
flag = false
|
||||
typeof func === 'function' && func()
|
||||
}, wait)
|
||||
}
|
||||
}
|
||||
export default throttle
|
Reference in New Issue
Block a user