Skip to content

Commit

Permalink
Merge pull request #9 from arvindcheenu/matercolors-next
Browse files Browse the repository at this point in the history
✨ Implemented Complementary palette generation
  • Loading branch information
arvindcheenu authored Jul 19, 2020
2 parents 6c2c82d + 689726f commit 6a84c9d
Show file tree
Hide file tree
Showing 5 changed files with 150 additions and 14 deletions.
23 changes: 19 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@ The following methods are available as of version **1.0.0**.
| Method | Type | What it returns |
|-|-|-|
| `.palette()` | `Getter` | A Material Palette Object with Text Contrast Values for the given color |
| `.shades()` | `Getter` | Light, Main and Dark shades for the given color |
| `.accents()` | `Getter` | Accent Color Palette for the given color |
| `.shades(paletteType)` | `Getter` | Light, Main and Dark shades for a selected palette type |
| `.accents(paletteType)` | `Getter` | Accent Color Palette for a selected palette type |

#### 🏗️ Palette Object Structure
Logging the palette output for the `PurplePalette` color by
Expand Down Expand Up @@ -100,7 +100,20 @@ we get an output that follows the following structure.
A200 : [Object],
A400 : [Object],
A700 : [Object],
} // ...More coming soon
}
secondary : { // type of palette
50 : [Object]
100 : [Object],
200 : [Object],
...
900 : [Object], // darkest color in palette
// Accents
A100 : [Object],
A200 : [Object],
A400 : [Object],
A700 : [Object],
}
// ...More coming soon
}
```
> All the other functions are simply helpers to access specific parts of the complete palette.
Expand Down Expand Up @@ -287,6 +300,8 @@ which, for the given color, generates the output:
}
}
```
Similar outputs are generated for the **secondary** palette type.

These outputs can also be used in conjunction with [Material UI's](https://material-ui.com/)
[**createMuiTheme**](https://material-ui.com/customization/theming/#createmuitheme-options-args-theme) to configure custom palettes. For a better understanding on how to use, you can checkout the demo.

Expand All @@ -300,7 +315,7 @@ These outputs can also be used in conjunction with [Material UI's](https://mater

#### Next Possible Stable Release

- [ ] Generate Complementary Palette
- [x] Generate Complementary Palette
- [ ] Generate Analogous Palette
- [ ] Generate Triadic Palette

Expand Down
22 changes: 22 additions & 0 deletions examples/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ console.log (JSON.stringify (PurplePalette.palette (), null, 2));
A200: Object
A400: Object
A700: Object
secondary : Object
50: Object
100: Object
200: Object
300: Object
400: Object
500: Object
600: Object
700: Object
800: Object
900: Object
A100: Object
A200: Object
A400: Object
A700: Object
*/

console.log ('\n\nPRIMARY PALETTE SHADES\n\n');
Expand All @@ -31,3 +46,10 @@ console.log (JSON.stringify (PurplePalette.shades ('primary'), null, 2));
console.log ('\n\nPRIMARY PALETTE ACCENTS\n\n');
console.log (JSON.stringify (PurplePalette.accents ('primary'), null, 2));
// Object {A100: Object, A200: Object, A400: Object, A700: Object}

console.log ('\n\nSECONDARY PALETTE SHADES\n\n');
console.log (JSON.stringify (PurplePalette.shades ('secondary'), null, 2));
// Object {light: Object, main: Object, dark: Object}
console.log ('\n\nSECONDARY PALETTE ACCENTS\n\n');
console.log (JSON.stringify (PurplePalette.accents ('secondary'), null, 2));
// Object {A100: Object, A200: Object, A400: Object, A700: Object}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "matercolors" ,
"version": "1.0.4",
"version": "1.1.0",
"description": "A tiny, zero-dependency libary for building harmonious material palettes for any color.",
"main": "./src/index.js",
"type": "module",
Expand Down
73 changes: 70 additions & 3 deletions src/color.utils.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-bitwise */
export function RGBToHSL(rgb) {
const r = rgb.r / 255;
const g = rgb.g / 255;
Expand All @@ -15,11 +16,14 @@ export function RGBToHSL(rgb) {
h = Math.round(h * 60);
if (h < 0) h += 360;
l = (cmax + cmin) / 2;
s = (delta === 0) ? 0 : (delta / (1 - Math.abs(2 * l - 1)));
s = delta === 0 ? 0 : delta / (1 - Math.abs(2 * l - 1));
s = +(s * 100).toFixed(1);
l = +(l * 100).toFixed(1);
return {
h, s, l, string: `hsl(${h},${s}%,${l}%)`
h,
s,
l,
string: `hsl(${h},${s}%,${l}%)`,
};
}
export function RGBToCYMK(rgb) {
Expand All @@ -33,7 +37,11 @@ export function RGBToCYMK(rgb) {
k *= 100;
k = parseFloat(k.toFixed(4));
return {
c, y, m, k, string: `cymk(${c}%,${y}%,${m}%,${k}%)`
c,
y,
m,
k,
string: `cymk(${c}%,${y}%,${m}%,${k}%)`,
};
}
export function hexToRgba(hex) {
Expand Down Expand Up @@ -65,3 +73,62 @@ export function getContrastText({ r, g, b }, threshold) {
const contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000;
return contrast >= threshold ? 'black' : 'white';
}

export function getComplementary(hex) {
const rgb = hexToRgba(hex);
let r = rgb.r / 255.0;
let g = rgb.g / 255.0;
let b = rgb.b / 255.0;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h;
let s;
const l = (max + min) / 2.0;
if (max === min) {
h = 0; s = 0; // achromatic
} else {
const d = max - min;
s = l > 0.5 ? d / (2.0 - max - min) : d / (max + min);
if (max === r && g >= b) {
h = 1.0472 * (g - b) / d;
} else if (max === r && g < b) {
h = 1.0472 * (g - b) / d + 6.2832;
} else if (max === g) {
h = 1.0472 * (b - r) / d + 2.0944;
} else if (max === b) {
h = 1.0472 * (r - g) / d + 4.1888;
}
}
h = h / 6.2832 * 360.0 + 0;
// Shift hue to opposite side of wheel and convert to [0-1] value
h += 180;
if (h > 360) {
h -= 360;
}
h /= 360;
if (s === 0) {
r = l; g = l; b = l; // achromatic
} else {
const hue2rgb = function hue2rgb(p, q, T) {
let t = T;
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
};
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;

r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
r = Math.round(r * 255);
g = Math.round(g * 255);
b = Math.round(b * 255);
// Convert r b and g values to hex
const final = b | (g << 8) | (r << 16);
return `#${(0x1000000 | final).toString(16).substring(1)}`;
}
44 changes: 38 additions & 6 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { keys, defaultOptions } from './global.constants.js';
import {
normalizeRGB, rgbToHex, hexToRgba, RGBToCYMK, RGBToHSL, getContrastText
normalizeRGB, rgbToHex, hexToRgba, RGBToCYMK, RGBToHSL, getContrastText, getComplementary
} from './color.utils.js';
import { createPallete } from './goldenPalettes.js';

export default class Matercolor {
constructor(color, options) {
this.color = color;
const complementary = getComplementary(color);
this.complementary = () => complementary;
this.options = options
? Object.assign(defaultOptions, options)
: defaultOptions;
Expand Down Expand Up @@ -34,26 +36,42 @@ export default class Matercolor {

getPalette() {
this.palette().primary = {};
const palette = createPallete(
this.palette().secondary = {};
const primaryPalette = createPallete(
normalizeRGB(hexToRgba(this.color))
).map(u => rgbToHex(
Math.round(u.red * 255),
Math.round(u.green * 255),
Math.round(u.blue * 255)
));
const accents = createPallete(
const primaryAccents = createPallete(
normalizeRGB(hexToRgba(this.color)),
true
).map(u => rgbToHex(
Math.round(u.red * 255),
Math.round(u.green * 255),
Math.round(u.blue * 255)
));
palette.push(...accents);
const secondaryPalette = createPallete(
normalizeRGB(hexToRgba(this.complementary()))
).map(u => rgbToHex(
Math.round(u.red * 255),
Math.round(u.green * 255),
Math.round(u.blue * 255)
));
const secondaryAccents = createPallete(
normalizeRGB(hexToRgba(this.complementary())),
true
).map(u => rgbToHex(
Math.round(u.red * 255),
Math.round(u.green * 255),
Math.round(u.blue * 255)
));
primaryPalette.push(...primaryAccents);
for (let i = 0; i < keys.length; i += 1) {
const colorObject = {};
colorObject.hex = palette[i];
colorObject.rgb = hexToRgba(palette[i]);
colorObject.hex = primaryPalette[i];
colorObject.rgb = hexToRgba(primaryPalette[i]);
colorObject.rgb.string = `rgb(${colorObject.rgb.r},${colorObject.rgb.g},${colorObject.rgb.b})`;
colorObject.hsl = RGBToHSL(colorObject.rgb);
colorObject.cymk = RGBToCYMK(colorObject.rgb);
Expand All @@ -63,5 +81,19 @@ export default class Matercolor {
);
this.palette().primary[keys[i]] = colorObject;
}
secondaryPalette.push(...secondaryAccents);
for (let i = 0; i < keys.length; i += 1) {
const colorObject = {};
colorObject.hex = secondaryPalette[i];
colorObject.rgb = hexToRgba(secondaryPalette[i]);
colorObject.rgb.string = `rgb(${colorObject.rgb.r},${colorObject.rgb.g},${colorObject.rgb.b})`;
colorObject.hsl = RGBToHSL(colorObject.rgb);
colorObject.cymk = RGBToCYMK(colorObject.rgb);
colorObject.contrastText = getContrastText(
colorObject.rgb,
this.options.threshold
);
this.palette().secondary[keys[i]] = colorObject;
}
}
}

0 comments on commit 6a84c9d

Please sign in to comment.