Create color palette from color - javascript

I have elements that should be colored by some color. However the bigger index of the element the 'lighter' shade of said color it should be, but never gray or white.
What is some function to achieve this? The only thing i have found is
const adjust = (color, amount) => {
return '#' + color.replace(/^#/, '').replace(/../g, color => ('0' + Math.min(255, Math.max(0, parseInt(color, 16) + amount)).toString(16)).substr(-2));
}
function, but it always results in grey and even white color.
e.g:
let elements = fetchElements(); // approx 300 elements
for( let i = 0 ; i < elements.length ;i++ ){
let color = adjust(#000000,i);
buildElement( elements[i]; color );
}

I don't realy undrestand what you are doing here(!) but maybe you could use RGBA format, lower the alpha number on each loop then convert it back to hex.

Related

Obtain 50% of a color hex value without using transparency

I need to obtain the color value of a 50% lighter version of an existing color hex. However it has to be 100% opaque, I cannot use opacity, rgba, hexa or hsla.
The scenario:
I draw routes on a map, each one with a different color, based on a hardcoded array of 48 possible hex values.
When one of these routes is being edited it should be shown as "disabled" (50% of the original color).
In the screen design, the reference values were #9775fa for the route color (one of the colors in the array) and #d5c7fd for the disabled color. This second color was obtained by the designer drawing a white layer with 50% opacity on top of the base color.
I tried to obtain this same value via JS, first using a lighten function, then an HSL one and finally lightening manually each of the RGB values of the base color. None of them really worked.
Using lighten, adding 62 of light I got a near value, but not the exact one.
Using HSL and lightening manually with 50% didn't work either.
These are the values I've got:
Base color: #9775fa
"Disabled color": #d5c7fd
Lighten by 62: #d5b3ff
HSL 50%: #e3b0ff
Ligheting 50% by hand: #e3b0ff
So, by the end, the real question is, Is it possible to be achieved?
Here is a "playground" and the full code of my experiments (the second column is the reference "disabled" color.
Thanks a lot!
I managed to get more accurate results by mixing the color with white at your given percentage.
I changed lightenByPercentage as follows:
let p = percentage / 100;
var r = "0x" + hex[0] + hex[1];
var g = "0x" + hex[2] + hex[3];
var b = "0x" + hex[4] + hex[5];
r = Math.ceil(256 * (1-p) + (r * p));
g = Math.ceil(256 * (1-p) + (g * p));
b = Math.ceil(256 * (1-p) + (b * p));
r = r <= 255 ? r : 255;
g = g <= 255 ? g : 255;
b = b <= 255 ? b : 255;
I'm not sure if your percentage was supposed to be how light it is or how dark it is, so if I got it the wrong way around swap p with 1-p here.

How for entered color calculate background color?

In my #vue/cli 4.1.1 app user enter color and I have to output
color value with entered color and I wonder how can I calculate and set background color
to be sure that entered color value is good visible. I mean if user entered white color(or near)
background must be dark?
Thanks
You can give an invert color - 255-color for each of rgb
function bg(r, g, b) {return [255-r, 255-g, 255-b]}
if you get it in hex format, you can convert it to rgb, then get the invert. like so:
function invert(hex){
hex = parseInt(hex.substring(1), 16);
var r = hex >> 16;
hex -= r << 16;
var g = hex >> 8;
hex -= g << 8;
var b = hex;
return `rgb(${255-r},${255-g},${255-b})`;
}
var color1 = "#eeff00";
var color2 = "#22faef";
var color3 = "#f1f1f1";
document.querySelector('#a').style = `color:${color1};background-color:${invert(color1)}`;
document.querySelector('#b').style = `color:${color2};background-color:${invert(color2)}`;
document.querySelector('#c').style = `color:${color3};background-color:${invert(color3)}`;
div {
padding: 10px;
}
<div id="a">Hello world!</div>
<div id="b">Hello world!</div>
<div id="c">Hello world!</div>
You can determine the entered color to be light or dark on the basis of its luminance.
Here you can find a formula it's calculated on.
So, you can, for example, define the function isLight like this
function isLight(color) {
// Converting hex color to rgb
const [red, green, blue] = hexToRgb(color);
// Determine luminance
const luminance = (0.299 * red + 0.587 * green + 0.114 * blue)/255;
// Returning true if color is light
return luminance > 0.5;
}
// function for converting hex colors to rgb array format
function hexToRgb(hex) {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
}
By using this function you can determine if the user color is light or dark and thus set the appropriate background

Determine Color Lightness via RGB

I have some color swatches that should show the rgb value of the color displayed, with the background being the actual color. Then, if the color in question is light-ish, the text should be black, and if the color in question is dark-ish, the text color should be white.
How can I detect if the RGB value is light-ish or dark-ish??
JS FIDDLE
<style>
#preview {
display: block;
height: 40px;
line-height: 40px;
font-size: 20px;
vertical-align: middle;
width: 150px;
text-align: center;
}
</style>
<!-- html -->
<button id="new_color">Try Random Color</button>
<p id="preview">Click the button!</p>
<script>
const getRandNum = () => Math.floor(Math.random() * 256);
const get_random_color = () => (`rgb(${getRandNum()}, ${getRandNum()}, ${getRandNum()})`);
const checkColor = (color) => {
// color = 'rgb(x, y, z)';
// check color is light
// or color is dark
return true;
}
$('#new_color').click(function(){
const p = $('#preview');
const bg_color = get_random_color();
const color_is_light = checkColor( bg_color );
const text_color = color_is_light ? 'black' : 'white';
p.css({
color: text_color,
backgroundColor: bg_color
})
});
</script>
I only found solutions for #hex colors, but not for rgb. Any help is very much appreciated.
If you're looking for relative luminance, a quick formula you can use is:
Y = 0.2126R + 0.7152G + 0.0722B
Source: https://en.wikipedia.org/wiki/Relative_luminance
To be able to use the coefficients above directly, you'll have to either normalize your RGB components to 1. Or divide by 255 first. The Y value you'll get is between 0-1, so you can probably then do:
const color_is_light = y > 0.5;
I'd do something like:
const getRandomRgb = () => [
Math.random(),
Math.random(),
Math.random()
];
const getRelativeLuminance = (rgb) =>
0.2126 * rgb[0]
+ 0.7152 * rgb[1]
+ 0.0722 * rgb[2];
const getCssColor = (rgb) => `rgb(${rgb.map((c) => c * 255)}`;
Though, there'll literally be a "gray area" where you will not get enough contrast with either white or black text against a mid-gray background.
You may want to change your get_random_color function to return the individual components, do the math above, and then construct the CSS color value afterwards.
So if you have answers for hex, adapt those for RGB because the hex values are just the base 16 numbers of the rgb base 10 values. Looking for a way to convert between bases now.
EDIT: If your r value in hex is "5a", the way to get that r value in base 10 for rgb() is parseInt("5a",16)
EDIT2: To get the hex value from decimal, this works: const hex = d => Number(d).toString(16).padStart(2, '0') ~ taken from How to convert decimal to hex in JavaScript?
You have to check if(red + green + blue >= 255 * 1.5) for a light color as said by the second answer in this post
const checkColor = (color) => {
// extract values of red, green and blue from color
let clrarr = color.match(/\d+/g).map(num => +num);
if(clrarr[0] + clrarr[1] + clrarr[2] >= 255 * 3 / 2)
return true; // color is light
return false; // color is dark
}
JSFiddle

JS : from RGB Blue to RGB Red

I'm trying to convert RGB color from blue (rgba(0,0,255)) to red (rgba(255,0,0)) on JS mouseenter, progressively.
So, each time the mouse enter an element, it "increments" its background color, from blue to green and then to red.
With a WIP live demo : http://codepen.io/enguerranws/pen/ZQOBwe
Here's what I've done so far :
function onGridDone(){
var gridders = document.querySelectorAll('.gridder');
for(var i = 0; i < gridders.length; i++){
gridders[i].addEventListener('mouseenter', onHover );
}
}
function onHover () {
var currentColor = this.style.backgroundColor,
currentColorArr = currentColor.replace(/[^\d,]/g, '').split(',');
R = currentColorArr[0],
G = currentColorArr[1],
B = currentColorArr[2];
console.log(R,G,B);
if(B > 0) B = B-10;
var indic = 255-B;
G = indic/2;
R = indic;
this.style.backgroundColor = "rgb("+R+","+G+","+B+")";
}
I've tried multiple things, but basically, I want my color to go from rgba(0,0,255), then rgba(0,255,130), then rgba(255,130,0) and finally rgba(255,0,0) (so, from blue to green then green to red).
I know I could do multiple if/else statements to check each case, but I'm just wandering if there'is a more efficient way using maths ?
I'm not trying to do any animations / transitions.
To make use of a mathematical formula, it is helpful to have some numeric indicator of progress, e.g., from 0 to 255 and then calculate the colors from that.
It is not exactly what you "basically" asked for but it illustrates what I mean: Let's say the red component would increase linearly from 0 to 255 during the process. Then you could look at an existing field's red value and know immediately where you are. If you wanted to move through green, this should be close to what you want to do:
// assume r,g,b are the current values
var progress = r;
progress += 1; // of course you can increment faster
r = progress;
g = 255 - (255 * (Math.abs(progress-127)/128))
b = 255 - progress;
This way you will not pass the color rgba(255,130,0) as in your question. However, I think it might still solve your problem. r increases linearly, b decreases linearly and g first increases and then decreases after 50% of the process.

Calculate color values from green to red

I would like to calculate color value according to given number.
0 -> pure red
100 -> pure green
example: 75 -> color, which is 75% from red to green.
I need this for expiration counter, which shows appropriate colors as days count down.
You could indeed go for the solution provided by #KamilT. Disadvantage of this method (imo) is that the colors in the middle (around 50) will get brownish and not very nice compared to your full red and green.
I think it would be much nicer to follow the color spectrum, and passing over orange and yellow, in stead of that ugly brownish.
This can easily by achieved by working with HSL values rather then RGB values. If you set the Hue value based on your number between 0 and 100 to a value between 0°(red) and 120°(green), and keep your Saturation at 100% and your Lightness at 50%, you should get nice bright colors.
I found a way to convert between rgb and hsl here: HSL to RGB color conversion
And I wrote a simple function to calculate your rgb value using the conversion function from the answer above:
// convert a number to a color using hsl
function numberToColorHsl(i) {
// as the function expects a value between 0 and 1, and red = 0° and green = 120°
// we convert the input to the appropriate hue value
var hue = i * 1.2 / 360;
// we convert hsl to rgb (saturation 100%, lightness 50%)
var rgb = hslToRgb(hue, 1, .5);
// we format to css value and return
return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
}
And I set up a fiddle to demonstrate the diffrences between the HSL method and the RGB method: http://jsfiddle.net/rE6Rk/1/
update a more versatile version:
If you do not want to work with a range from red to green, you can slightly adapt the above method. The value that determines the actual color in a hsl representation is the hue, so that's the one we'll need to calculate.
If you define the range of your hue, by providing the 0 and 1 value as parameters, the calculation of the hue value becomes basic math. Have a look at the updated method:
function percentageToHsl(percentage, hue0, hue1) {
var hue = (percentage * (hue1 - hue0)) + hue0;
return 'hsl(' + hue + ', 100%, 50%)';
}
As you can see I changed the API a bit. The parameters are as follows:
percentage: a value between 0 and 1
hue0: the hue value of the color you want to get when the percentage is 0
hue1: the hue value of the color you want to get when the percentage is 1
Also, there is no longer a need to calculate the rgb value, modern browsers support hsl values as is.
So now you can use the method as follows:
// green(120) to red(0)
color = percentageToHsl(perc, 120, 0);
// blue(225) to pink(315)
color = percentageToHsl(perc, 225, 315);
// blue (225) to yellow(45 + 360)
color = percentageToHsl(perc, 225, 405);
So if you want to go clockwise you have to make hue0 < hue1. If you want to go counter clockwise you have to make hue0 > hue1. And since these are degrees, you can just add or subtract 360 to force the direction. You can even use this technique to wrap around the hue circle multiple times.
I've created a new fiddle to demonstrate: https://jsfiddle.net/r438s65s/
The answer by Pevara is great. I have adapted his jsfiddle to my needs, and maybe it is useful for others too: http://jsfiddle.net/rE6Rk/8/
It allows to have an uneven distribution of colors. In my case I wanted everything below 0.5 (50) to be red. And a 0.75 would be in the middle between red and green. So instead of working with hard borders 0 and 1, they can both be shifted.
The changes are in the numberToColorHsl() function only:
* the i is a floating point 0-1 instead of the int 0-100
* additional params min/max
/**
* Convert a number to a color using hsl, with range definition.
* Example: if min/max are 0/1, and i is 0.75, the color is closer to green.
* Example: if min/max are 0.5/1, and i is 0.75, the color is in the middle between red and green.
* #param i (floating point, range 0 to 1)
* param min (floating point, range 0 to 1, all i at and below this is red)
* param max (floating point, range 0 to 1, all i at and above this is green)
*/
function numberToColorHsl(i, min, max) {
var ratio = i;
if (min> 0 || max < 1) {
if (i < min) {
ratio = 0;
} else if (i > max) {
ratio = 1;
} else {
var range = max - min;
ratio = (i-min) / range;
}
}
// as the function expects a value between 0 and 1, and red = 0° and green = 120°
// we convert the input to the appropriate hue value
var hue = ratio * 1.2 / 3.60;
//if (minMaxFactor!=1) hue /= minMaxFactor;
//console.log(hue);
// we convert hsl to rgb (saturation 100%, lightness 50%)
var rgb = hslToRgb(hue, 1, .5);
// we format to css value and return
return 'rgb(' + rgb[0] + ',' + rgb[1] + ',' + rgb[2] + ')';
}
The visuals explain it better than words.
This is just simple maths ;)
Red = 255 - (255 * (Number / 100))
Green = 255 * (Number / 100)
Blue = 0
That's all.

Categories

Resources