gradient-color
Advanced tools
Comparing version 1.1.0 to 2.0.0
@@ -1,70 +0,212 @@ | ||
'use strict'; | ||
const Color = require('color'); | ||
const { | ||
NO_EDN_FRAC, | ||
MIN_ARRAY_LENGTH, | ||
FRAC_SUM_ERROR, | ||
COLOR_NUMBER_ERROR | ||
} = require('./errors'); | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
/** | ||
* Generate n colors with given color stops | ||
* | ||
* @param {Array} colorArray | ||
* @param {Number} n number of colors that need to generate | ||
* @returns {Array} array of generated colors in rgb mode | ||
*/ | ||
exports.getGradient = function (n, startColor, endColor) { | ||
// add semicolon cause `[` is the at starting char of a line | ||
var Rx = void 0, | ||
Gx = void 0, | ||
Bx = void 0, | ||
Ry = void 0, | ||
Gy = void 0, | ||
By = void 0; | ||
function gradient(colorArray, n) { | ||
const isFullOption = checkParam(colorArray, n); | ||
var _hexToRgb = hexToRgb(startColor); | ||
// init 2 arrays for algorithm | ||
let colorList = []; | ||
let fracList = []; | ||
// result array for storing data | ||
let resultArray = []; | ||
var _hexToRgb2 = _slicedToArray(_hexToRgb, 3); | ||
// simple array of color string | ||
if (!isFullOption) { | ||
const frac = 1 / (colorArray.length - 1); | ||
Rx = _hexToRgb2[0]; | ||
Gx = _hexToRgb2[1]; | ||
Bx = _hexToRgb2[2]; | ||
colorArray.forEach((colorString, index) => { | ||
if (index !== colorArray.length - 1) { | ||
colorList.push(Color(colorString)); | ||
fracList.push(frac); | ||
} else { | ||
colorList.push(Color(colorString)); | ||
} | ||
}); | ||
} else { | ||
colorArray.forEach((obj, index) => { | ||
if (index !== colorArray.length - 1) { | ||
colorList.push(Color(obj.color)); | ||
fracList.push(obj.frac); | ||
} else { | ||
if (obj.color) { | ||
// the last item could be like { color: #ffffff } | ||
colorList.push(Color(obj.color)); | ||
} else { | ||
// and it could also be like '#ffffff' | ||
colorList.push(Color(obj)); | ||
} | ||
} | ||
}); | ||
} | ||
var _hexToRgb3 = hexToRgb(endColor); | ||
const assignList = assignNumbers(fracList, n); | ||
resultArray = createGradient(colorList, assignList); | ||
var _hexToRgb4 = _slicedToArray(_hexToRgb3, 3); | ||
// convert colors to string version | ||
resultArray = resultArray.map(c => c.rgb().toString()); | ||
Ry = _hexToRgb4[0]; | ||
Gy = _hexToRgb4[1]; | ||
By = _hexToRgb4[2]; | ||
return resultArray; | ||
} | ||
/** | ||
* Explainations: | ||
* o -> stop color for gradient | ||
* * -> generated color | ||
* | ||
* o * * * | o * * * * | o * * o -> generated color list in char version | ||
* 4 5 4 -> assigned number of colors need to be generated | ||
* | ||
* The last section, the end color should be considered in the generated colors | ||
* | ||
* @returns {Array} array of colors in Color(pkg) format, need toString() call | ||
*/ | ||
var newColors = []; | ||
for (var i = 0; i <= n; i++) { | ||
var r = void 0, | ||
g = void 0, | ||
b = void 0; | ||
var percent = i / n; | ||
var _ref = [calcColor(Rx, Ry, percent), calcColor(Gx, Gy, percent), calcColor(Bx, By, percent)]; | ||
r = _ref[0]; | ||
g = _ref[1]; | ||
b = _ref[2]; | ||
function createGradient(colorList, assignList) { | ||
let result = []; | ||
assignList.forEach((num, index) => { | ||
const isLastElement = index === assignList.length - 1; | ||
const list = []; | ||
newColors.push('rgb(' + r + ',' + g + ',' + b + ')'); | ||
} | ||
// get end point color | ||
const start = colorList[index]; | ||
const end = colorList[index + 1]; | ||
return newColors; | ||
}; | ||
// function linearGradient(n, ...args) { | ||
// args.forEach(color => { | ||
// if last element, end color should be in the list, | ||
// so the num = num - 1 | ||
if (isLastElement) { | ||
num = num - 1; | ||
} | ||
// }) | ||
// } | ||
const deltaR = (end.red() - start.red()) / num; | ||
const deltaG = (end.green() - start.green()) / num; | ||
const deltaB = (end.blue() - start.blue()) / num; | ||
function calcColor(x, y, percent) { | ||
return x + Math.floor((y - x) * percent); | ||
// generate num colors | ||
for (let i = 0; i < num; i++) { | ||
const R = start.red() + i * deltaR; | ||
const G = start.green() + i * deltaG; | ||
const B = start.blue() + i * deltaB; | ||
list.push(Color.rgb(R, G, B)); | ||
} | ||
// if last element, end this list with the last color | ||
if (isLastElement) { | ||
list.push(end); | ||
} | ||
result = result.concat(list); | ||
}); | ||
return result; | ||
} | ||
function hexToRgb(hex) { | ||
var rgb = []; | ||
hex = hex.substr(1); | ||
// "#abc" -> "#aabbcc" | ||
if (hex.length === 3) { | ||
hex = hex.replace(/(.)/g, '$1$1'); | ||
} | ||
hex.replace(/../g, function (color) { | ||
return rgb.push(parseInt(color, 0x10)); | ||
/** | ||
* Calculate and optimize the number of each color period | ||
* | ||
* Sometimes frac * N might be a fraction | ||
* So we use this algorithm: | ||
* | ||
* 1. Split the number into 2 parts, each part fits in an array: | ||
* [2, 4, 1, 5] -> int array | ||
* [0.2, 0.5, 0.9, 0.3] -> decimal array | ||
* | ||
* The left number should be: | ||
* left = N - sum(intArray) | ||
* | ||
* 2. Sort the decimal array from large to small, assign left to | ||
* the corresponding element in intArray one by one | ||
* until left === 0 | ||
* | ||
* 3. There goes your final array! | ||
* | ||
* @returns {Array} array of optimized color numbers | ||
*/ | ||
function assignNumbers(fracList, n) { | ||
const intArray = []; | ||
const decimalArray = []; | ||
// assign int part | ||
fracList.forEach((frac, index) => { | ||
const real = frac * n; | ||
const intPart = Math.floor(real); | ||
const decimalPart = real - intPart; | ||
intArray.push(intPart); | ||
decimalArray.push({ | ||
value: decimalPart, | ||
index: index | ||
}); | ||
}); | ||
return rgb; | ||
} | ||
// how many left ? | ||
const left = n - intArray.reduce((a, b) => a + b, 0); | ||
// sort O -> o | ||
decimalArray.sort((a, b) => b.value - a.value); | ||
// assign the left number regard to the decimal part's value | ||
// until nothing left | ||
for (let i = 0; i < left; i++) { | ||
const targetIndex = decimalArray[i].index; | ||
intArray[targetIndex] = intArray[targetIndex] + 1; | ||
} | ||
return intArray; | ||
} | ||
/** | ||
* Check param format and throw some errors | ||
*/ | ||
function checkParam(array, n) { | ||
// Seriously? Anyone this dumb? | ||
if (array.length < 2) { | ||
throw MIN_ARRAY_LENGTH; | ||
} | ||
// Read the documentation OMG! Of course no frac at the end! | ||
if (array[array.length - 1].frac) { | ||
throw NO_EDN_FRAC; | ||
} | ||
// You need to see a doctor, like, right now | ||
if (n <= array.length) { | ||
throw COLOR_NUMBER_ERROR; | ||
} | ||
// if full option mode, sum should be 1 | ||
if (typeof array[0] !== 'string') { | ||
const fracSum = array.slice(0, array.length - 1).reduce((a, b) => a + b.frac, 0); | ||
if (fracSum < 0.99) { | ||
throw FRAC_SUM_ERROR; | ||
} | ||
} | ||
let result; | ||
if (typeof array[0] === 'string') { | ||
result = false; | ||
} else { | ||
result = true; | ||
} | ||
return result; | ||
} | ||
module.exports = gradient; |
{ | ||
"name": "gradient-color", | ||
"version": "1.1.0", | ||
"description": "Make beautiful gradient color", | ||
"version": "2.0.0", | ||
"description": "Gradient color generator that lives in 21st", | ||
"main": "./build/index.js", | ||
@@ -10,3 +10,4 @@ "engines": { | ||
"scripts": { | ||
"test": "node ./test/test.js", | ||
"test": "tape test/*.js | tap-notify | tap-diff", | ||
"dev": "babel -w ./src --out-dir ./build", | ||
"build": "babel ./src --out-dir ./build" | ||
@@ -20,2 +21,3 @@ }, | ||
"color", | ||
"colors", | ||
"gradient" | ||
@@ -30,6 +32,10 @@ ], | ||
"devDependencies": { | ||
"babel-cli": "^6.18.0", | ||
"babel-preset-es2015": "^6.18.0", | ||
"babel-preset-stage-0": "^6.16.0" | ||
"babel-cli": "^6.24.1", | ||
"babel-plugin-transform-object-rest-spread": "^6.23.0", | ||
"blue-tape": "^1.0.0", | ||
"tape": "^4.6.3" | ||
}, | ||
"dependencies": { | ||
"color": "^1.0.3" | ||
} | ||
} |
# Gradient color | ||
Make beautiful gradient color | ||
Gradient color generator | ||
## USAGE | ||
**Attention**: This doc is for `v2.0`, `v1.x` usage is at the end of the doc, and it's deprecated | ||
## Installation | ||
`npm install gradient-color -S` | ||
## Usage | ||
```js | ||
// commonjs style | ||
const gradient = require('gradient-color') | ||
// module import style | ||
// import gradient from 'gradient-color' | ||
const colors = gradient([ | ||
'#E5404C', | ||
'#FD743C', | ||
'#FD9C3C' | ||
], 20) | ||
// array of 20 colors in `rgb(x, x, x)` format | ||
console.log(colors) | ||
``` | ||
## API | ||
```js | ||
gradient(colorArray, n) | ||
``` | ||
where | ||
- **colorArray** is either | ||
- An array of color strings. This way, each gradient's step is the same | ||
```js | ||
// hex string is supported | ||
['#fff', '#ddd', '#eee'] | ||
// rgb string is also ok | ||
['rgb(23, 23, 23)', 'rgb(33, 33, 33)'] | ||
``` | ||
- An array of color object. You can specify each gradient's step value by `frac` field. | ||
```js | ||
[ | ||
{ | ||
color: '#fff', | ||
frac: 0.4 | ||
}, | ||
{ | ||
color: '#eee', | ||
frac: 0.4 | ||
}, | ||
{ | ||
color: '#aaa', | ||
frac: 0.2 | ||
}, | ||
// the last color could either be an object | ||
{ | ||
color: '#fefefe' | ||
} | ||
// or a string value | ||
// '#fefefe' | ||
] | ||
``` | ||
If you are using this method, there're several things you should remember: | ||
1. **The last color should not have a `frac` field**, so it can be either an `Object` with only `color` field or a `String` value | ||
2. **The sum of all the `frac`s should equal to 1** | ||
- **n** is the number of color that will be generated. **It should be greater than the length of your `colorArray`**, i.e. `n > colorArray.length` | ||
## Upcoming features | ||
- [ ] Alpha channel support | ||
## Nasty old v1.x usage (deprecated) | ||
```js | ||
var getGradient = require('gradient-color').getGradient | ||
@@ -9,0 +84,0 @@ |
231
src/index.js
@@ -1,43 +0,214 @@ | ||
exports.getGradient = function(n, startColor, endColor) { | ||
// add semicolon cause `[` is the at starting char of a line | ||
let Rx, Gx, Bx, Ry, Gy, By; | ||
[Rx, Gx, Bx] = hexToRgb(startColor); | ||
[Ry, Gy, By] = hexToRgb(endColor); | ||
const Color = require('color') | ||
const { | ||
NO_EDN_FRAC, | ||
MIN_ARRAY_LENGTH, | ||
FRAC_SUM_ERROR, | ||
COLOR_NUMBER_ERROR | ||
} = require('./errors') | ||
let newColors = [] | ||
for (var i = 0; i <= n; i++) { | ||
let r, g, b | ||
let percent = i / n; | ||
[r, g, b] = [ | ||
calcColor(Rx, Ry, percent), | ||
calcColor(Gx, Gy, percent), | ||
calcColor(Bx, By, percent) | ||
] | ||
/** | ||
* Generate n colors with given color stops | ||
* | ||
* @param {Array} colorArray | ||
* @param {Number} n number of colors that need to generate | ||
* @returns {Array} array of generated colors in rgb mode | ||
*/ | ||
newColors.push(`rgb(${r},${g},${b})`) | ||
function gradient(colorArray, n) { | ||
const isFullOption = checkParam(colorArray, n) | ||
// init 2 arrays for algorithm | ||
let colorList = [] | ||
let fracList = [] | ||
// result array for storing data | ||
let resultArray = [] | ||
// simple array of color string | ||
if (!isFullOption) { | ||
const frac = 1 / (colorArray.length - 1) | ||
colorArray.forEach((colorString, index) => { | ||
if (index !== (colorArray.length - 1)) { | ||
colorList.push(Color(colorString)) | ||
fracList.push(frac) | ||
} else { | ||
colorList.push(Color(colorString)) | ||
} | ||
}) | ||
} else { | ||
colorArray.forEach((obj, index) => { | ||
if (index !== (colorArray.length - 1)) { | ||
colorList.push(Color(obj.color)) | ||
fracList.push(obj.frac) | ||
} else { | ||
if (obj.color) { | ||
// the last item could be like { color: #ffffff } | ||
colorList.push(Color(obj.color)) | ||
} else { | ||
// and it could also be like '#ffffff' | ||
colorList.push(Color(obj)) | ||
} | ||
} | ||
}) | ||
} | ||
return newColors | ||
const assignList = assignNumbers(fracList, n) | ||
resultArray = createGradient(colorList, assignList) | ||
// convert colors to string version | ||
resultArray = resultArray.map(c => c.rgb().toString()) | ||
return resultArray | ||
} | ||
// function linearGradient(n, ...args) { | ||
// args.forEach(color => { | ||
// }) | ||
// } | ||
/** | ||
* Explainations: | ||
* o -> stop color for gradient | ||
* * -> generated color | ||
* | ||
* o * * * | o * * * * | o * * o -> generated color list in char version | ||
* 4 5 4 -> assigned number of colors need to be generated | ||
* | ||
* The last section, the end color should be considered in the generated colors | ||
* | ||
* @returns {Array} array of colors in Color(pkg) format, need toString() call | ||
*/ | ||
function calcColor(x, y, percent) { | ||
return x + Math.floor((y - x) * percent) | ||
function createGradient(colorList, assignList) { | ||
let result = [] | ||
assignList.forEach((num, index) => { | ||
const isLastElement = index === assignList.length - 1 | ||
const list = [] | ||
// get end point color | ||
const start = colorList[index] | ||
const end = colorList[index + 1] | ||
// if last element, end color should be in the list, | ||
// so the num = num - 1 | ||
if (isLastElement) { | ||
num = num - 1 | ||
} | ||
const deltaR = (end.red() - start.red()) / num | ||
const deltaG = (end.green() - start.green()) / num | ||
const deltaB = (end.blue() - start.blue()) / num | ||
// generate num colors | ||
for (let i = 0; i < num; i++) { | ||
const R = start.red() + i * deltaR | ||
const G = start.green() + i * deltaG | ||
const B = start.blue() + i * deltaB | ||
list.push(Color.rgb(R, G, B)) | ||
} | ||
// if last element, end this list with the last color | ||
if (isLastElement) { | ||
list.push(end) | ||
} | ||
result = result.concat(list) | ||
}) | ||
return result | ||
} | ||
function hexToRgb(hex) { | ||
let rgb = [] | ||
hex = hex.substr(1) | ||
// "#abc" -> "#aabbcc" | ||
if (hex.length === 3) { | ||
hex = hex.replace(/(.)/g, '$1$1') | ||
/** | ||
* Calculate and optimize the number of each color period | ||
* | ||
* Sometimes frac * N might be a fraction | ||
* So we use this algorithm: | ||
* | ||
* 1. Split the number into 2 parts, each part fits in an array: | ||
* [2, 4, 1, 5] -> int array | ||
* [0.2, 0.5, 0.9, 0.3] -> decimal array | ||
* | ||
* The left number should be: | ||
* left = N - sum(intArray) | ||
* | ||
* 2. Sort the decimal array from large to small, assign left to | ||
* the corresponding element in intArray one by one | ||
* until left === 0 | ||
* | ||
* 3. There goes your final array! | ||
* | ||
* @returns {Array} array of optimized color numbers | ||
*/ | ||
function assignNumbers(fracList, n) { | ||
const intArray = [] | ||
const decimalArray = [] | ||
// assign int part | ||
fracList.forEach((frac, index) => { | ||
const real = frac * n | ||
const intPart = Math.floor(real) | ||
const decimalPart = real - intPart | ||
intArray.push(intPart) | ||
decimalArray.push({ | ||
value: decimalPart, | ||
index: index | ||
}) | ||
}) | ||
// how many left ? | ||
const left = n - intArray.reduce((a, b) => a + b, 0) | ||
// sort O -> o | ||
decimalArray.sort((a, b) => b.value - a.value) | ||
// assign the left number regard to the decimal part's value | ||
// until nothing left | ||
for (let i = 0; i < left; i++) { | ||
const targetIndex = decimalArray[i].index | ||
intArray[targetIndex] = intArray[targetIndex] + 1 | ||
} | ||
hex.replace(/../g, color => rgb.push(parseInt(color, 0x10))) | ||
return rgb | ||
return intArray | ||
} | ||
/** | ||
* Check param format and throw some errors | ||
*/ | ||
function checkParam(array, n) { | ||
// Seriously? Anyone this dumb? | ||
if (array.length < 2) { | ||
throw MIN_ARRAY_LENGTH | ||
} | ||
// Read the documentation OMG! Of course no frac at the end! | ||
if (array[array.length - 1].frac) { | ||
throw NO_EDN_FRAC | ||
} | ||
// You need to see a doctor, like, right now | ||
if (n <= array.length) { | ||
throw COLOR_NUMBER_ERROR | ||
} | ||
// if full option mode, sum should be 1 | ||
if (typeof array[0] !== 'string') { | ||
const fracSum = array | ||
.slice(0, array.length - 1) | ||
.reduce((a, b) => a + b.frac, 0) | ||
if (fracSum < 0.99) { | ||
throw FRAC_SUM_ERROR | ||
} | ||
} | ||
let result | ||
if (typeof array[0] === 'string') { | ||
result = false | ||
} else { | ||
result = true | ||
} | ||
return result | ||
} | ||
module.exports = gradient |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15648
9
409
92
1
4
1
+ Addedcolor@^1.0.3
+ Addedcolor@1.0.3(transitive)
+ Addedcolor-convert@1.9.3(transitive)
+ Addedcolor-name@1.1.3(transitive)
+ Addedcolor-string@1.9.1(transitive)
+ Addedis-arrayish@0.3.2(transitive)
+ Addedsimple-swizzle@0.2.2(transitive)