From 7e7fa97b85daa12064cd5e920841c3e54f769d4f Mon Sep 17 00:00:00 2001 From: EDM115 Date: Thu, 15 Feb 2024 15:31:47 +0100 Subject: [PATCH] feat: v1.0 - renamed generateComplementaries to generateComplementary - added Doucmentation and a complete README - fixed few errors in the JSDoc --- README.md | 308 +++++++++++++++++++++++++++++++++++++++++++++++-- dist/palex.cjs | 47 ++++---- dist/palex.js | 47 ++++---- package.json | 2 +- src/index.js | 17 +-- 5 files changed, 356 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index 46252d3..f86ad9d 100644 --- a/README.md +++ b/README.md @@ -1,27 +1,315 @@ # palex -A javascript package to help you create color palettes +**A javascript package to help you create and manage color palettes** ![NPM Version](https://img.shields.io/npm/v/palex) ![NPM Downloads](https://img.shields.io/npm/dt/palex) ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/palex) ![npm bundle size](https://img.shields.io/bundlephobia/min/palex) ![npm bundle size (gzip)](https://img.shields.io/bundlephobia/minzip/palex) ![Libraries.io SourceRank](https://img.shields.io/librariesio/sourcerank/npm/palex) ![Dependent repos (via libraries.io)](https://img.shields.io/librariesio/dependent-repos/npm/palex) ![Dependents (via libraries.io)](https://img.shields.io/librariesio/dependents/npm/palex) ![Libraries.io dependency status for latest release](https://img.shields.io/librariesio/release/npm/palex) [![DeepSource](https://app.deepsource.com/gh/EDM115/palex.svg/?label=active+issues&show_trend=true&token=xJS8bnp9wldi4n1Se07fkY5S)](https://app.deepsource.com/gh/EDM115/palex/) -The CommonJS way : +Did you ever wanted to create a *color palette* for your website or your app but you didn't knew how to do it ? Did you had the idea to create a whole palette from a *single* color but thought it was too hard ? Or maybe you were wondering how to make a color palette *colorblind friendly* ? +Well today is your lucky day because `palex` is here to help you with all of that ! + +> [!NOTE] +> `palex` was created when I was working on [@data-fair/app-charts](https://github.com/data-fair/app-charts) and I needed to create color palettes for the charts. During this time I created several functions to help me with that, and some didn't make it to the final version, so I decided to release `palex` as a standalone library to help anyone struggling with color palettes ! + +## Installation + +You can install `palex` using your favorite package manager, here are some examples : + +```bash +npm install palex + +yarn add palex +``` + +Find the package on : [NPM](https://www.npmjs.com/package/palex) | [jsDelivr](https://www.jsdelivr.com/package/npm/palex) + +## Usage + +You can instanciate `palex` the CommonJS way : + ```js const palex = require('palex') -console.log(palex.generatePaletteFromBrewer('Set1', 10)) +console.log(palex.palex('#FFB86C', 'color', 10, cbf = true, golden = true)) +``` + +Or the ESM way (used in the following documentation) : + +```js +import { palex } from 'palex' + +console.log(palex('#FFB86C', 'color', 10, cbf = true, golden = true)) +``` + +> [!IMPORTANT] +> If you're using the ESM way, you'll need to either use the `.mjs` extension or have a `"type": "module"` in your `package.json` file. + +## Documentation + +The following documentation will explain how to use `palex` and its functions. It tries to be as comprehensive as possible, but if you have any question, feel free to open an issue ! Pull requests are also welcome if you want to add a feature or fix a bug ! + +### `palex(input, type, numColors = 10, cbf = false, golden = false, grey = false)` + +The main entrypoint of `palex`. It generates a color palette based on a given input and type. +- `input` : The input color(s). It can be a palette string (brewer), a color(s) string (hex, rgb, or named color) or an array containing any of these. +- `type` : The type of the input. It can be `brewer`, `hues`, `complementary`, `color` or `greyscale`. +- `numColors` : The number of colors to generate. It defaults to 10. +- `cbf` : If `true`, the palette will be colorblind friendly. It defaults to `false`. Have no effect if the type is `brewer` or `greyscale`. +- `golden` : If `true`, the palette will be based on the golden ratio. It defaults to `false`. Not recommended to use along with `cbf`. +- `grey` : If `true`, a greyscale will be added to the generated palette if the number of colors is less than numColors. It defaults to `false`. + +Returns an array of colors in hexadecimal format. + +```js +import { palex } from 'palex' + +console.log(palex('#FFB86C', 'color', 10, cbf = true, golden = true)) +// ["#df9220", "#2520df", "#dfb220", "#df3720", "#c6df20", "#df20a7", "#dfde20", "#2c20df", "#ccdf20", "#205fdf"] +``` + +### `sanitizeInput(input)` + +Did you ever wanted to know how every function in `palex` can accept such a wide range of inputs ? Well, it's because of `sanitizeInput` ! I wanted to create something easy to use so *you* don't have to worry about changing the input to fit the function. +- `input` : The input to sanitize. It can be a palette string (brewer), a color(s) string (hex, rgb, or named color) or an array containing any of these. + +Returns the sanitized input. + +```js +import { sanitizeInput } from 'palex' + +console.log(sanitizeInput('#FFB86C')) +// "#ffb86c" +console.log(sanitizeInput('Set3')) +// "Set3" +console.log(sanitizeInput('rgb(255, 184, 108)')) +// "#ffb86c" +console.log(sanitizeInput('ff0, #abc, FFB86C, , ,, ,,, rgb(100, 200, 81)')) +// ["#ffff00", "#aabbcc", "#ffb86c", "#64c851"] +``` + +### `generatePaletteFromBrewer(input, numColors)` + +Generates a color palette from a brewer palette string. + +> [!TIP] +> You can find strings to use here : https://loading.io/color/feature/ +> All strings in the Diverging section are valid, all from Qualitative except HCL, and most from Gradient too :\) + +- `input` : The brewer palette string. +- `numColors` : The number of colors to generate. If not provided, it defaults to 2 and will return the 2 base colors of the palette. + +Returns an array of colors in hexadecimal format. + +```js +import { generatePaletteFromBrewer } from 'palex' + +console.log(generatePaletteFromBrewer('Set3', 10)) +// ["#8dd3c7", "#ffe3b1", "#e19ec9", "#aaa1df", "#ffa778", "#d4d766", "#f1d1e1", "#caa8ca", "#dbd29f", "#ffed6f"] +``` + +### `getGoldenColor(color)` + +Returns a color based on the golden ratio from a given color. The idea behind it stems from the very good [PleaseJS](https://github.com/Fooidge/PleaseJS?tab=readme-ov-file#make_color-options) library. +- `color` : The color to base the new color on. + +Returns a color in hexadecimal format. + +```js +import { getGoldenColor } from 'palex' + +console.log(getGoldenColor('#FFB86C')) +// "#df8320" +``` + +### `generateGreyscale(start, end, steps)` + +Generates a greyscale palette from a start point to an end point with a given number of steps. +- `start` : The start point of the greyscale, from 0 to 255. +- `end` : The end point of the greyscale, from 0 to 255. +- `steps` : The number of steps to generate. + +Returns an array of colors in hexadecimal format. + +```js +import { generateGreyscale } from 'palex' + +console.log(generateGreyscale(0, 10, 5)) +// generates 11 colors, from black at 0 to white at 5, and values above steps and below end are white +// ["#000000", "#333333", "#666666", "#999999", "#cccccc", "#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff"] + +console.log(generateGreyscale(6, 10, 6)) +// generates 5 colors. they are all pure white +// ["#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff", "#ffffff"] + +console.log(generateGreyscale(1, 5, 10)) +// generates 5 colors. since steps is bigger than end - start, we will have a greyscale that avoids black and white +// ["#1a1a1a", "#333333", "#4d4d4d", "#666666", "#808080"] +``` + +### `generateHues(palette, numColors, cbf = false)` + +Generates a hue palette from a given color palette and a number of colors. It can also make the palette colorblind friendly. +- `palette` : The palette to base the hue on. +- `numColors` : The number of colors to generate. +- `cbf` : If `true`, the palette will be colorblind friendly. It defaults to `false`. + +Returns an array of colors in hexadecimal format. + +```js +import { generateHues } from 'palex' + +console.log(generateHues(['#BD93F9', '#F1FA8C', '#6272A4'], 10)) +// ["#bd93f9", "#f1fa8c", "#6272a4", "#fdecff", "#faffc8", "#7997db", "#fff3ff", "#a6bcf5", "#cee3ff"] + +import { generatePaletteFromBrewer } from 'palex' + +console.log(generateHues(generatePaletteFromBrewer('Set3', 10), 10)) +// ["#8dd3c7", "#ffe3b1", "#e19ec9", "#aaa1df", "#ffa778", "#d4d766", "#f1d1e1", "#caa8ca", "#dbd29f", "#ffed6f"] +``` + +### `generateHuesFromColor(color, numColors, cbf = false)` + +Generates a color palette hue from a given color and a number of colors. It can also make the palette colorblind friendly. +- `color` : The color to base the hue on. +- `numColors` : The number of colors to generate. +- `cbf` : If `true`, the palette will be colorblind friendly. It defaults to `false`. + +Returns an array of colors in hexadecimal format. + +```js +import { generateHuesFromColor } from 'palex' + +console.log(generateHuesFromColor('#FFB86C', 10)) +// ["#ffb86c", "#ffc56e", "#ffd794", "#ffe9b7", "#fffadb", "#fff3ff", "#fff3ff", "#fff3ff", "#fff3ff", "#fff3ff"] ``` -The ESM way (have a type: module in your package.json or use .mjs files) : +### `generateComplementary(palette, numColors, cbf = false)` + +Generates a complementary palette from a given color palette and a number of colors. It can also make the palette colorblind friendly. +- `palette` : The palette to base the complementary on. +- `numColors` : The number of colors to generate. +- `cbf` : If `true`, the palette will be colorblind friendly. It defaults to `false`. + +Returns an array of colors in hexadecimal format. + ```js +import { generateComplementary } from 'palex' + +console.log(generateComplementary(['#BD93F9', '#F1FA8C', '#6272A4'], 10)) +// ["#bd93f9", "#f1fa8c", "#6272a4", "#cff993", "#958cfa", "#a49462", "#f093f9", "#bafa8c", "#7362a4", "#939cf9"] + import { generatePaletteFromBrewer } from 'palex' -console.log(generatePaletteFromBrewer('Set1', 10)) +console.log(generateComplementary(generatePaletteFromBrewer('Set3', 10), 10)) +// ["#8dd3c7", "#ffe3b1", "#e19ec9", "#aaa1df", "#ffa778", "#d4d766", "#f1d1e1", "#caa8ca", "#dbd29f", "#ffed6f"] ``` -sources : -- https://loading.io/color/feature/ -- https://github.com/Fooidge/PleaseJS?tab=readme-ov-file#make_color-options -- https://gka.github.io/palettes/#/10|d|00429d,96ffea,ffffe0|ffffe0,ff005e,93003a|1|1 -- https://gka.github.io/chroma.js/ +### `generatePaletteFromColor(color, numColors, cbf = false)` + +Generates a color palette from a given color and a number of colors. Starts by generating a complementary color, then generates a number of analogous colors. If the number of colors is not reached, it generates a number of triadic colors. It can also make the palette colorblind friendly. +- `color` : The color to base the palette on. +- `numColors` : The number of colors to generate. +- `cbf` : If `true`, the palette will be colorblind friendly. It defaults to `false`. + +Returns an array of colors in hexadecimal format. + +```js +import { generatePaletteFromColor } from 'palex' + +console.log(generatePaletteFromColor('#FFB86C', 10)) +// ["#ffb86c", "#6cb3ff", "#fcff6c", "#ff6f6c", "#b3ff6c", "#ff6cb3", "#6cff6f", "#ff6cfc", "#6cffb8", "#b86cff"] +``` + +### `adjustForColorBlindness(palette)` + +Adjusts a given palette to make it colorblind friendly. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the `color-blind` library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. +- `palette` : The palette to adjust. + +Returns an array of colors in hexadecimal format. + +```js +import { adjustForColorBlindness } from 'palex' + +console.log(adjustForColorBlindness(['#FFB86C', '#6CB3FF', '#FCFF6C', '#FF6F6C', '#B3FF6C', '#FF6CB3', '#6CFF6F', '#FF6CFC', '#6CFFB8', '#B86CFF'])) +// ["#f3bc6a", "#8e8bff", "#fff7dd", "#ff8170", "#f1ff93", "#ab9aa6", "#fbfa68", "#9690ec", "#eef5af", "#548cff"] +``` + +### `simulateColorBlindness(color)` + +Simulates color blindness on a given color using the `color-blind` library. It works by simulating the 4 types of color blindness (protanopia, deuteranopia, tritanopia, and achromatopsia) and returns the base color + the simulated colors. +- `color` : The color to simulate color blindness on. + +Returns an array containing the base color and the simulated colors in hexadecimal format. + +```js +import { simulateColorBlindness } from 'palex' + +console.log(simulateColorBlindness('#FFB86C')) +// ["#ffb86c", "#d9c570", "#f3bc6a", "#ffb0bb", "#c2c2c2"] +``` + +### Re-exposure + +> [!TIP] +> Since this package uses the libraries `chroma.js` and `color-blind`, you can use them directly to create your own color palettes or to simulate color blindness. +> `palex` re-expose their object so you can directly use them without adding a line to your `package.json` file :\) +> Find their documentation here : [chroma.js](https://www.vis4.net/chromajs) and [color-blind](https://github.com/skratchdot/color-blind) + +```js +import { chroma, blinder } from 'palex' + +console.log(chroma.bezier(['#FFB86C', '#6CB3FF']).scale().colors(5)) +// ["#ffb86c", "#e8b693", "#ccb5b7", "#a7b4db", "#6cb3ff"] + +console.log(blinder.protanopia('#FFB86C')) +// "#d9c570" +``` + +## Contributing + +Here's a quick guide to contributing to `palex` : + +1. Fork the repository (and star it) +2. Clone your fork +```bash +git clone https://github.com/your-username/palex.git +cd palex +``` +3. Do your changes +4. Test your changes + Import the function you wanna test in `test/App.vue` and instanciate it like the others are +```bash +npm run test +``` +5. Commit your changes +```bash +git add -A +git commit -m "Your changes" +git push +``` +6. Open a pull request + +## Donate + +I'm a small developer from France, and as I write this I'm still pursuing my studies. If you want to support me, here's how you can do it : +- Star this repository +- Follow me on [GitHub](https://github.com/EDM115) +- Donate : + - [PayPal](https://paypal.me/8EDM115) + - [GitHub Sponsors](https://github.com/sponsors/EDM115) + - [BuyMeACoffee](https://www.buymeacoffee.com/EDM115) + - [Donate on Telegram](https://t.me/EDM115bots/698) + +## License + +- `palex` is licensed under the [MIT License](https://github.com/EDM115/palex/blob/master/LICENSE) +- `chroma.js` is licensed under the [BSD License](https://github.com/gka/chroma.js/blob/main/LICENSE) +- `color-blind` is licensed under the [MIT License + CC-BY-SA-4.0](https://github.com/skratchdot/color-blind?tab=readme-ov-file#license) + +> [!NOTE] +> Sources that helped during development : +> - [vis4/chroma.js](https://www.vis4.net/chromajs) +> - [vis4/palettes](https://www.vis4.net/palettes/#/10|d|00429d,96ffea,ffffe0|ffffe0,ff005e,93003a|1|1) +> - [Fooidge/PleaseJS#make_color-options](https://github.com/Fooidge/PleaseJS?tab=readme-ov-file#make_color-options) +> - [loading.io/color/feature](https://loading.io/color/feature/) diff --git a/dist/palex.cjs b/dist/palex.cjs index 03c3cc6..f056f0a 100644 --- a/dist/palex.cjs +++ b/dist/palex.cjs @@ -48,7 +48,7 @@ function sanitizeInput(input) { // Case 3 : A colors string. ex : 'fff, 000', '#F00, rgb(0,255,0), blue, #00F', ... if (typeof input === 'string' && input.includes(',')) { - var _colors = []; + var colors = []; var buffer = ''; var inParentheses = false; for (var i = 0; i < input.length; i++) { @@ -61,7 +61,7 @@ function sanitizeInput(input) { if (trimmedBuffer.startsWith('"') && trimmedBuffer.endsWith('"')) { trimmedBuffer = trimmedBuffer.substring(1, trimmedBuffer.length - 1); } - _colors.push(trimmedBuffer); + colors.push(trimmedBuffer); buffer = ''; } } else { @@ -73,9 +73,9 @@ function sanitizeInput(input) { if (_trimmedBuffer.startsWith('"') && _trimmedBuffer.endsWith('"')) { _trimmedBuffer = _trimmedBuffer.substring(1, _trimmedBuffer.length - 1); } - _colors.push(_trimmedBuffer); + colors.push(_trimmedBuffer); } - var validColors = _colors.filter(function (color) { + var validColors = colors.filter(function (color) { return color && chroma.valid(color); }); return validColors.map(function (color) { @@ -102,7 +102,7 @@ function sanitizeInput(input) { /** * Generates a palette of colors from a Brewer palette. * - * @param {string} input - The input Brewer palette. + * @param {string} input - The input Brewer palette. See https://loading.io/color/feature/ * @param {number} numColors - The number of colors to generate. * @returns {Array} - The generated palette of colors. */ @@ -114,7 +114,7 @@ function generatePaletteFromBrewer(input, numColors) { } /** - * Adjusts a palette of colors for color blindness. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the 'blinder' library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. + * Adjusts a palette of colors for color blindness. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the 'color-blind' library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. * * @param {Array} palette - The palette of colors to adjust. * @returns {Array} - The adjusted palette of colors. @@ -122,7 +122,7 @@ function generatePaletteFromBrewer(input, numColors) { function adjustForColorBlindness(palette) { // How it works : // 1. Grab the palette (array of hex values) - // 2. Make 3 new arrays, each of them mapping the original palette to a new one, simulating the 3 types of color blindness (uses blinder) + // 2. Make 3 new arrays, each of them mapping the original palette to a new one, simulating the 3 types of color blindness (uses color-blind) // 3. For each array, compare all the colors to each other. If 2 colors are too similar, shift one of them to a the closer but not similar color. Repeat the process for each array until the said array is "fixed" // 4. Return 1 array that computes the 3 other ones into a single one, by taking the best color for each index // 5. Eventually recurse the process until the palette is fixed @@ -165,12 +165,12 @@ function adjustForColorBlindness(palette) { } return bestMatch; }; - var fixedPalettes = adjustedPalettes.map(function (palette, paletteIndex) { - return palette.map(function (color, index) { - if (palette.some(function (otherColor, otherIndex) { + var fixedPalettes = adjustedPalettes.map(function (adjustedPalette) { + return adjustedPalette.map(function (color, index) { + if (adjustedPalette.some(function (otherColor, otherIndex) { return index !== otherIndex && isColorTooSimilar(color, otherColor); })) { - return adjustColor(color, palette); + return adjustColor(color, adjustedPalette); } return color; // Return original if not too similar }); @@ -178,8 +178,8 @@ function adjustForColorBlindness(palette) { // Combine the fixed palettes into a single palette by choosing the best color for each index var finalPalette = palette.map(function (originalColor, index) { - var colorOptions = fixedPalettes.map(function (palette) { - return palette[index]; + var colorOptions = fixedPalettes.map(function (fixedPalette) { + return fixedPalette[index]; }); var distances = colorOptions.map(function (color) { return chroma.deltaE(originalColor, color); @@ -298,7 +298,7 @@ function generateHuesFromColor(color, numColors) { var cbf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (numColors < 1) return []; color = sanitizeInput(color); - var baseColor; + var baseColor = ''; if (typeof color === 'string') { baseColor = chroma(color); } else if (Array.isArray(color)) { @@ -306,8 +306,8 @@ function generateHuesFromColor(color, numColors) { } var colors = [baseColor.hex()]; for (var i = 1; i < numColors; i++) { - var _color = baseColor.set('hsl.l', '*' + (1 + i / numColors)).saturate(1); - colors.push(_color.hex()); + var colorHue = baseColor.set('hsl.l', "*".concat(1 + i / numColors)).saturate(1); + colors.push(colorHue.hex()); } if (cbf) { colors = adjustForColorBlindness(colors); @@ -323,7 +323,7 @@ function generateHuesFromColor(color, numColors) { * @param {boolean} [cbf=false] - Whether to adjust the colors for color blindness. * @returns {string[]} The generated palette of complementary colors. */ -function generateComplementaries(palette, numColors) { +function generateComplementary(palette, numColors) { var cbf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (numColors < 1) return []; palette = sanitizeInput(palette); @@ -363,7 +363,7 @@ function generatePaletteFromColor(color, numColors) { var cbf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (numColors < 1) return []; color = sanitizeInput(color); - var baseColor; + var baseColor = ''; if (typeof color === 'string') { baseColor = chroma(color); } else if (Array.isArray(color)) { @@ -393,12 +393,12 @@ function generatePaletteFromColor(color, numColors) { * Generates a color palette based on the given input and type. * * @param {string} input - The input for generating the color palette. - * @param {string} type - The type of color palette to generate. Can be one of: 'brewer', 'hues', 'complementary', 'color', 'greyscale'. Returns an empty array if the type is not recognized. + * @param {string} type - The type of color palette to generate. Can be one of: 'brewer', 'hues', 'complementary', 'color', 'greyscale'. * @param {number} [numColors=10] - The number of colors to generate in the palette. Default is 10. * @param {boolean} [cbf=false] - Whether to adjust the colors for color blindness. Default is false. * @param {boolean} [golden=false] - Whether to apply the golden ratio to the colors. Default is false. * @param {boolean} [grey=false] - Whether to add greyscale colors to the palette if it has less colors than numColors once generated. Default is false. - * @returns {Array} - The generated color palette. + * @returns {Array} - The generated color palette, or an empty array if the type is not recognized. */ function palex(input, type) { var numColors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; @@ -408,6 +408,7 @@ function palex(input, type) { if (numColors < 1) { return []; } + input = sanitizeInput(input); var palette = []; switch (type) { case 'brewer': @@ -417,7 +418,7 @@ function palex(input, type) { palette = generateHues(input, numColors, cbf); break; case 'complementary': - palette = generateComplementaries(input, numColors, cbf); + palette = generateComplementary(input, numColors, cbf); break; case 'color': palette = generatePaletteFromColor(input, numColors, cbf); @@ -435,7 +436,7 @@ function palex(input, type) { } if (grey) { if (palette.length < numColors) { - var numGreyscaleColors = numColors - colors.length; + var numGreyscaleColors = numColors - palette.length; var start = 0; var end = numGreyscaleColors - 1; var steps = numGreyscaleColors; @@ -449,7 +450,7 @@ function palex(input, type) { exports.blinder = blinder; exports.chroma = chroma; exports.adjustForColorBlindness = adjustForColorBlindness; -exports.generateComplementaries = generateComplementaries; +exports.generateComplementary = generateComplementary; exports.generateGreyscale = generateGreyscale; exports.generateHues = generateHues; exports.generateHuesFromColor = generateHuesFromColor; diff --git a/dist/palex.js b/dist/palex.js index b627dac..8399baa 100644 --- a/dist/palex.js +++ b/dist/palex.js @@ -48,7 +48,7 @@ function sanitizeInput(input) { // Case 3 : A colors string. ex : 'fff, 000', '#F00, rgb(0,255,0), blue, #00F', ... if (typeof input === 'string' && input.includes(',')) { - var _colors = []; + var colors = []; var buffer = ''; var inParentheses = false; for (var i = 0; i < input.length; i++) { @@ -61,7 +61,7 @@ function sanitizeInput(input) { if (trimmedBuffer.startsWith('"') && trimmedBuffer.endsWith('"')) { trimmedBuffer = trimmedBuffer.substring(1, trimmedBuffer.length - 1); } - _colors.push(trimmedBuffer); + colors.push(trimmedBuffer); buffer = ''; } } else { @@ -73,9 +73,9 @@ function sanitizeInput(input) { if (_trimmedBuffer.startsWith('"') && _trimmedBuffer.endsWith('"')) { _trimmedBuffer = _trimmedBuffer.substring(1, _trimmedBuffer.length - 1); } - _colors.push(_trimmedBuffer); + colors.push(_trimmedBuffer); } - var validColors = _colors.filter(function (color) { + var validColors = colors.filter(function (color) { return color && chroma.valid(color); }); return validColors.map(function (color) { @@ -102,7 +102,7 @@ function sanitizeInput(input) { /** * Generates a palette of colors from a Brewer palette. * - * @param {string} input - The input Brewer palette. + * @param {string} input - The input Brewer palette. See https://loading.io/color/feature/ * @param {number} numColors - The number of colors to generate. * @returns {Array} - The generated palette of colors. */ @@ -114,7 +114,7 @@ function generatePaletteFromBrewer(input, numColors) { } /** - * Adjusts a palette of colors for color blindness. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the 'blinder' library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. + * Adjusts a palette of colors for color blindness. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the 'color-blind' library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. * * @param {Array} palette - The palette of colors to adjust. * @returns {Array} - The adjusted palette of colors. @@ -122,7 +122,7 @@ function generatePaletteFromBrewer(input, numColors) { function adjustForColorBlindness(palette) { // How it works : // 1. Grab the palette (array of hex values) - // 2. Make 3 new arrays, each of them mapping the original palette to a new one, simulating the 3 types of color blindness (uses blinder) + // 2. Make 3 new arrays, each of them mapping the original palette to a new one, simulating the 3 types of color blindness (uses color-blind) // 3. For each array, compare all the colors to each other. If 2 colors are too similar, shift one of them to a the closer but not similar color. Repeat the process for each array until the said array is "fixed" // 4. Return 1 array that computes the 3 other ones into a single one, by taking the best color for each index // 5. Eventually recurse the process until the palette is fixed @@ -165,12 +165,12 @@ function adjustForColorBlindness(palette) { } return bestMatch; }; - var fixedPalettes = adjustedPalettes.map(function (palette, paletteIndex) { - return palette.map(function (color, index) { - if (palette.some(function (otherColor, otherIndex) { + var fixedPalettes = adjustedPalettes.map(function (adjustedPalette) { + return adjustedPalette.map(function (color, index) { + if (adjustedPalette.some(function (otherColor, otherIndex) { return index !== otherIndex && isColorTooSimilar(color, otherColor); })) { - return adjustColor(color, palette); + return adjustColor(color, adjustedPalette); } return color; // Return original if not too similar }); @@ -178,8 +178,8 @@ function adjustForColorBlindness(palette) { // Combine the fixed palettes into a single palette by choosing the best color for each index var finalPalette = palette.map(function (originalColor, index) { - var colorOptions = fixedPalettes.map(function (palette) { - return palette[index]; + var colorOptions = fixedPalettes.map(function (fixedPalette) { + return fixedPalette[index]; }); var distances = colorOptions.map(function (color) { return chroma.deltaE(originalColor, color); @@ -298,7 +298,7 @@ function generateHuesFromColor(color, numColors) { var cbf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (numColors < 1) return []; color = sanitizeInput(color); - var baseColor; + var baseColor = ''; if (typeof color === 'string') { baseColor = chroma(color); } else if (Array.isArray(color)) { @@ -306,8 +306,8 @@ function generateHuesFromColor(color, numColors) { } var colors = [baseColor.hex()]; for (var i = 1; i < numColors; i++) { - var _color = baseColor.set('hsl.l', '*' + (1 + i / numColors)).saturate(1); - colors.push(_color.hex()); + var colorHue = baseColor.set('hsl.l', "*".concat(1 + i / numColors)).saturate(1); + colors.push(colorHue.hex()); } if (cbf) { colors = adjustForColorBlindness(colors); @@ -323,7 +323,7 @@ function generateHuesFromColor(color, numColors) { * @param {boolean} [cbf=false] - Whether to adjust the colors for color blindness. * @returns {string[]} The generated palette of complementary colors. */ -function generateComplementaries(palette, numColors) { +function generateComplementary(palette, numColors) { var cbf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (numColors < 1) return []; palette = sanitizeInput(palette); @@ -363,7 +363,7 @@ function generatePaletteFromColor(color, numColors) { var cbf = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false; if (numColors < 1) return []; color = sanitizeInput(color); - var baseColor; + var baseColor = ''; if (typeof color === 'string') { baseColor = chroma(color); } else if (Array.isArray(color)) { @@ -393,12 +393,12 @@ function generatePaletteFromColor(color, numColors) { * Generates a color palette based on the given input and type. * * @param {string} input - The input for generating the color palette. - * @param {string} type - The type of color palette to generate. Can be one of: 'brewer', 'hues', 'complementary', 'color', 'greyscale'. Returns an empty array if the type is not recognized. + * @param {string} type - The type of color palette to generate. Can be one of: 'brewer', 'hues', 'complementary', 'color', 'greyscale'. * @param {number} [numColors=10] - The number of colors to generate in the palette. Default is 10. * @param {boolean} [cbf=false] - Whether to adjust the colors for color blindness. Default is false. * @param {boolean} [golden=false] - Whether to apply the golden ratio to the colors. Default is false. * @param {boolean} [grey=false] - Whether to add greyscale colors to the palette if it has less colors than numColors once generated. Default is false. - * @returns {Array} - The generated color palette. + * @returns {Array} - The generated color palette, or an empty array if the type is not recognized. */ function palex(input, type) { var numColors = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 10; @@ -408,6 +408,7 @@ function palex(input, type) { if (numColors < 1) { return []; } + input = sanitizeInput(input); var palette = []; switch (type) { case 'brewer': @@ -417,7 +418,7 @@ function palex(input, type) { palette = generateHues(input, numColors, cbf); break; case 'complementary': - palette = generateComplementaries(input, numColors, cbf); + palette = generateComplementary(input, numColors, cbf); break; case 'color': palette = generatePaletteFromColor(input, numColors, cbf); @@ -435,7 +436,7 @@ function palex(input, type) { } if (grey) { if (palette.length < numColors) { - var numGreyscaleColors = numColors - colors.length; + var numGreyscaleColors = numColors - palette.length; var start = 0; var end = numGreyscaleColors - 1; var steps = numGreyscaleColors; @@ -446,4 +447,4 @@ function palex(input, type) { return palette; } -export { adjustForColorBlindness, generateComplementaries, generateGreyscale, generateHues, generateHuesFromColor, generatePaletteFromBrewer, generatePaletteFromColor, getGoldenColor, palex, sanitizeInput, simulateColorBlindness }; +export { adjustForColorBlindness, generateComplementary, generateGreyscale, generateHues, generateHuesFromColor, generatePaletteFromBrewer, generatePaletteFromColor, getGoldenColor, palex, sanitizeInput, simulateColorBlindness }; diff --git a/package.json b/package.json index 04392a9..212b945 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "palex", - "version": "0.2.1", + "version": "1.0.0", "description": "Simple package to help you create color palettes", "author": "EDM115 (https://edm115.dev)", "homepage": "https://github.com/EDM115/palex", diff --git a/src/index.js b/src/index.js index 60a3a52..0ed985a 100644 --- a/src/index.js +++ b/src/index.js @@ -85,7 +85,7 @@ function sanitizeInput(input) { /** * Generates a palette of colors from a Brewer palette. * - * @param {string} input - The input Brewer palette. + * @param {string} input - The input Brewer palette. See https://loading.io/color/feature/ * @param {number} numColors - The number of colors to generate. * @returns {Array} - The generated palette of colors. */ @@ -100,7 +100,7 @@ function generatePaletteFromBrewer(input, numColors) { } /** - * Adjusts a palette of colors for color blindness. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the 'blinder' library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. + * Adjusts a palette of colors for color blindness. It works by simulating the three types of color blindness (protanopia, deuteranopia, and tritanopia) using the 'color-blind' library. The function compares all the colors in each simulated palette and shifts one of them to a closer but not similar color if they are too similar. This process is repeated for each simulated palette until they are "fixed". The function then computes the three fixed palettes into a single palette by selecting the best color for each index. This process can be recursively applied until the palette is fully adjusted. * * @param {Array} palette - The palette of colors to adjust. * @returns {Array} - The adjusted palette of colors. @@ -108,7 +108,7 @@ function generatePaletteFromBrewer(input, numColors) { function adjustForColorBlindness(palette) { // How it works : // 1. Grab the palette (array of hex values) - // 2. Make 3 new arrays, each of them mapping the original palette to a new one, simulating the 3 types of color blindness (uses blinder) + // 2. Make 3 new arrays, each of them mapping the original palette to a new one, simulating the 3 types of color blindness (uses color-blind) // 3. For each array, compare all the colors to each other. If 2 colors are too similar, shift one of them to a the closer but not similar color. Repeat the process for each array until the said array is "fixed" // 4. Return 1 array that computes the 3 other ones into a single one, by taking the best color for each index // 5. Eventually recurse the process until the palette is fixed @@ -310,7 +310,7 @@ function generateHuesFromColor(color, numColors, cbf = false) { * @param {boolean} [cbf=false] - Whether to adjust the colors for color blindness. * @returns {string[]} The generated palette of complementary colors. */ -function generateComplementaries(palette, numColors, cbf = false) { +function generateComplementary(palette, numColors, cbf = false) { if (numColors < 1) return [] palette = sanitizeInput(palette) @@ -388,18 +388,19 @@ function generatePaletteFromColor(color, numColors, cbf = false) { * Generates a color palette based on the given input and type. * * @param {string} input - The input for generating the color palette. - * @param {string} type - The type of color palette to generate. Can be one of: 'brewer', 'hues', 'complementary', 'color', 'greyscale'. Returns an empty array if the type is not recognized. + * @param {string} type - The type of color palette to generate. Can be one of: 'brewer', 'hues', 'complementary', 'color', 'greyscale'. * @param {number} [numColors=10] - The number of colors to generate in the palette. Default is 10. * @param {boolean} [cbf=false] - Whether to adjust the colors for color blindness. Default is false. * @param {boolean} [golden=false] - Whether to apply the golden ratio to the colors. Default is false. * @param {boolean} [grey=false] - Whether to add greyscale colors to the palette if it has less colors than numColors once generated. Default is false. - * @returns {Array} - The generated color palette. + * @returns {Array} - The generated color palette, or an empty array if the type is not recognized. */ function palex(input, type, numColors = 10, cbf = false, golden = false, grey = false) { if (numColors < 1) { return [] } + input = sanitizeInput(input) let palette = [] switch (type) { @@ -410,7 +411,7 @@ function palex(input, type, numColors = 10, cbf = false, golden = false, grey = palette = generateHues(input, numColors, cbf) break case 'complementary': - palette = generateComplementaries(input, numColors, cbf) + palette = generateComplementary(input, numColors, cbf) break case 'color': palette = generatePaletteFromColor(input, numColors, cbf) @@ -451,7 +452,7 @@ export { generateGreyscale, generateHues, generateHuesFromColor, - generateComplementaries, + generateComplementary, generatePaletteFromColor, palex }