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.
Related
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.
So I have this color wheel, That will be used for a color picker.
I am making this via NativeScript for a mobile application. And I would like to know how to get an RGB or HEX (since I can use either) with using only the X/Y coordinates?
{x:0,y:0} is the very center so negative numbers will be left and up while positive numbers are right and down.
I am stuck with trying to figure out how to get the color. I have no code to show as I do not know where to start.
The color wheel is an image pre-made instead of me auto generating it with a canvas when ever the application is used.
All the following angular measures are based on the usual mathematic sense: 0° is horizontal to the right with angles increasing anti–clockwise so 90°is up, 180° to the left and 270° is down.
Using the colour wheel in MS PowerPoint (because it's available), values are calculated by dividing the circle into 3 120° wide segments centred on 0°, 120° and 240° for red, green and blue respectively.
On segments boundaries, the colour is 100% of the adjacent colours, so 60° is 100% red and 100% green. The adjoining colour fades to the centre of the segment, so at 90° (half way from the red/green boundary toward the green centre), the colour is 100% green and 50% red.
That gives the mix of adjoining colours, the mix of the opposing colour is based on the distance from the centre.
This mapping scheme doesn't work for RGB as it's a 3 dimensional space, however it gives 2 of the 3 dimensions for HSV if coordinates are used for the hue and saturation and an adjacent slider for value. For simplicity the following just uses a disc with value set to 1.
A full explanation is at Hand-coding a color wheel with canvas.
/* Convert radians to degrees.
*
* #param {number} rad - radians to convert, expects
* rad in range +/- PI per Math.atan2
* #returns {number} degrees equivalent of rad
*/
function rad2deg(rad) {
return (360 + 180 * rad / Math.PI) % 360;
}
/* Convert h,s,v values to r,g,b
* See: https://en.wikipedia.org/wiki/HSL_and_HSV#From_HSV
*
* #param {number} hue - in range [0, 360]
* #param {number} saturation - in range 0 to 1
* #param {number} value - in range 0 to 1
* #returns {Array|number} [r, g,b] in range 0 to 255
*/
function hsv2rgb(hue, saturation, value) {
hue /= 60;
let chroma = value * saturation;
let x = chroma * (1 - Math.abs((hue % 2) - 1));
let rgb = hue <= 1? [chroma, x, 0]:
hue <= 2? [x, chroma, 0]:
hue <= 3? [0, chroma, x]:
hue <= 4? [0, x, chroma]:
hue <= 5? [x, 0, chroma]:
[chroma, 0, x];
return rgb.map(v => (v + value - chroma) * 255);
}
/* Convert cartesian coordinates to RGB
* Converts: x, y to polar (radial_distance, angle), then
* polar to HSV, then
* HSV to RGB
*
* #param {number} x - x coordinate in range -1 to 1
* #param {number} y - y coordinate in range -1 to 1
* #returns {Array|number} [red, green, blue] values in range 0 to 255
*/
function rectToRGB(x, y) {
// Hue is from angle, saturation from distance from centre, value set to 1
var r = Math.sqrt(x*x + y*y);
// Limit extent to disc
var sat = r > 1? 0 : r;
var hsv = [rad2deg(Math.atan2(y, x)), sat, 1];
var rgb = hsv2rgb(...hsv).map(Math.round);
return rgb;
}
function posToColour(evt) {
var node = this;
var originOffset = node.width / 2;
var offsetLeft = offsetTop = 0;
do {
offsetLeft += node.offsetLeft;
offsetTop += node.offsetTop;
node = node.offsetParent;
} while (node.offsetParent)
// Adjust coordinates then scale to range -1 to 1
var x = ((evt.x - offsetLeft - originOffset) / originOffset).toFixed(2);
var y = ((originOffset - evt.y + offsetTop) / originOffset).toFixed(2);
var rgb = rectToRGB(x, y);
var patch = document.getElementById('colorPatch');
patch.style.backgroundColor = `rgb(${rgb.join()})`;
document.getElementById('data').innerHTML =
`x, y : ${(x<0?'':' ')+x}, ${(y<0?'':' ')+y}<br>r,g,b: ${rgb.map(x=>(' '+x).slice(-3)).join(', ')}`;
}
document.addEventListener('DOMContentLoaded', function() {
document.getElementById('colourDisc').addEventListener('mousemove', posToColour, false);
}, false);
img {width:200px;height:200px;}
div {width: 90px; height: 90px}
<table>
<tr>
<td><img src="https://i.stack.imgur.com/lPPOO.png" id="colourDisc"></td>
<td><div id="colorPatch"></div>
<div><pre id="data"></pre></div></td>
</table>
If you generate the colour wheel as a canvas per the linked article, then likely you can just get the colour under the curser.
The hsv2rgb is somewhat minified from the original, but I think it's much clearer for being shorter, at the risk of overusing the :? operator.
You seem to be excluding some details, i will assume you have already a coordinate translator method or something, i know you have a canvas, hence you have the canvas api and image data.
function getRGB(x, y, canvas) {
let context = canvas.getContext('2d');
let [red, green, blue, alpha] = context.getImageData(x, y, 1, 1).data;
return {red, green, blue, alpha};
}
The easy way to get colors from this wheel is to get it as Hsl and then convert it to RGB (or Hex).The hue and saturation values are easily determined from a circle, tan(hue) = y/x; hue = hue%360 // saturation = √(x²+y²) * 100 / radius. but the lightness value cannot be determined from the picture so i would choose 50%.
I am building a simple website that gives a random quote when I click a button, and with that, the background color changes. The thing is that sometimes the background color is too dark and the font is black, and consequently the person can't read the quote.
My question:
Is there is any way to create a random color code using just bright colors, or pastel colors?
I got this code to generate a random color. I tried to edit to get only A to F strings but no success:
'#'+((1<<24)*(Math.random()+1)|0).toString(16).substr(1)
Thank you very much in advance.
HSL Colors
Using HSL Colors colors may be the easiest. HSL color values are specified in CSS as
hsl( hue, saturation%, lightness%)
where hue is in range 0-360 (without a unit marker when using degrees), and both saturation and lightness are percentages with a trailing % sign.
Note
"Bright" colors refer to the colors of an RGB color wheel formed by starting at red and then blending pure red into green, pure green into blue, and finally pure blue back into red again.
In HSL color space, bright colors are represented by a hue based on their position on the color wheel with 100% saturation and a lightness value of 50%:
hue 0 ▶ ◀ hue 360
saturation: 100%
lightness: 50%
Colors blend with white - and become more "pastel" as lightness increases above 50%. A lightness value of 100% creates white regardless of what the values of hue and saturation are.
Colors blend with grey as the saturation decreases and become more washed out depending on how low the saturation gets. A saturation value of 0% creates a grey-scale tone based on lightness alone.
Colors blend with black as lightness decreases below 50%. A lightness value of 0% creates black no matter what the hue and saturation values are.
Warning
The human eye is least sensitive to the color blue. Black text on a blue background - or blue over black - is harder to read in comparison to other colors. If this becomes an issue for random color selection, example 2 shows one way to compensate.
Example 1: Some random pastel colors with saturation in range 25-95% and lightness in range 85-95%:
function getColor(){
return "hsl(" + 360 * Math.random() + ',' +
(25 + 70 * Math.random()) + '%,' +
(85 + 10 * Math.random()) + '%)'
}
// Generate 20 colors
for( var i = 20; i--; ){
var item = document.createElement('div')
item.style.cssText = `
display:inline-block;
padding: 2em;
margin:5px;
border-radius:50%;
background: ${getColor()};
`
document.body.appendChild(item);
}
Example 2: This example demonstrates adjusting colors for the eye's lack of sensitivity to blue. It generates a boxed set of letters colored with hues in the range 0 to 340 presented on a black background.
"use strict";
// individual letter classes:
function letterCSS(letter, i, length, blueBoost) {
let hue = Math.floor( i/length * 341); // between 0 and 340
let saturation = 100;
let lightness = 50;
// color adjustment:
if( blueBoost && hue > 215 && hue < 265) {
const gain = 20;
let blueness = 1 - Math.abs( hue-240)/25;
let change = Math.floor( gain * blueness);
lightness += change;
saturation -= change;
}
let hsl = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
return `.${letter} {
color: ${hsl};
border-color: ${hsl};
background-color: black;
}
` ;
}
// generate and display boxed letters of the alphabet
function letterBlocks() {
let letters = Array.from("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
let cssText = "";
let html = ""
let blueBoost = document.getElementById("boost").checked;
letters.forEach( (letter, i, a) => {
cssText += letterCSS( letter, i, a.length, blueBoost);
html += ` <span class="letter ${letter}">${letter}<\/span> `;
});
let style = document.createElement("style");
style.textContent = cssText;
document.body.appendChild(style);
let p = document.getElementById("blocks");
p.innerHTML = html;
}
#blocks {
line-height: 2.5rem;
}
.letter {
display: inline-block;
text-align: center;
line-height: 2rem;
font-size: 1.5rem;
height: 2rem;
width: 2rem;
font-family: sans-serif;
font-weight: bold;
border-width: 0.125rem;
border-style: solid;
border-radius: 0.25rem;
}
<button type="button" onclick="letterBlocks()">Generate Letter Blocks</button><label>
- optionally lighten colors near pure blue:<input type="checkbox" id="boost">
</label>
<p id="blocks"></p>
Letter colors start out with full saturation and 50% lightness. Check the option box and click the button to adjust colors close to blue by increasing lightness and decreasing saturation.
"Close to blue" is hard coded to mean within 25 degree units of hue value 240,
The maximum adjustment amount is set by gain to 20 percentage units,
Demonstration code. Real code and adjustment values would be altered on a case by case basis depending on why and how color adjustments are being made.
By randomizing only the hue, it's faster.
HSLA colors are made of Hue, saturation, lightness and alpha.
Example, lightness to be adjusted as needed (third value).
function randomHSL(){
return "hsla(" + ~~(360 * Math.random()) + "," +
"70%,"+
"80%,1)"
}
rdm.onclick = (function(){
document.body.style.backgroundColor = randomHSL()
})
rdm.click()
<button id="rdm">Random pastel color!</button>
Or similary:
function randomHSL(){
return `hsla(${~~(360 * Math.random())},70%,70%,0.8)`
}
rdm.onclick = (function(){
document.body.style.backgroundColor = randomHSL()
})
rdm.click()
<button id="rdm">Random pastel color!</button>
You could choose among lighter colours by appropriately setting the background-color property using rgb.
rgb(0,0,0) is black, while rgb(255,255,255) is white. You could therefore use random values which are closer to (but not higher than) 255.
An example (using JQuery):
var rand = Math.floor(Math.random() * 10);
var colorQ = "rgb(" + (215 - rand * 3) + "," + (185 - rand * 5) + "," + (185 - rand * 10) + " )";
$("body").css("background-color", colorQ);
You can play around with the values until you find the colours that you prefer - keep in mind that the closer the 3 rgb values are to each other, the closer your colour will be to grey. E.g. rgb(100,100,100), rgb(221,221,221) and rgb(133,133,133) are all shades of grey. What changes is how light your grey will be.
I would like to be able to call a function that takes a base color and returns an array of values that correspond to different shades of the same color. The array can contain either hex values or rgba() values. I would like to be able to input the amount of desired shades as well. The amount of shades would then also be able to be used as a metric to increment the shade. For example if I wanted the output have 3 different shades, the 1st shade would be 1/3 of the base.. however that math would work... Additionally, In some situations the 1st shade may need to be 100% transparent so I would like to accept an argument for the initial alpha. I've organized what I think would be the basic logic of the function but the math is unclear to me.
var buildColorStops = function (baseColor,numberOfValues,initialAlpha) {
var b = baseColor;
var n = numberOfValues //expected number of colors in the output. If n was 3 results would be [light blue, blue(base), dark blue] (# or rgba will work)
var d = 1 / n; // if number of values was 5 d would represent 1/5 of the base.
var ia = initialAlpha; // some situations may require the first color to be 100% transparent
var outputArray = [];
var i = 0;
while (i < n) {
if (i == 0) {
//...math on base color & incorporate initial alpha
outputArray.push("result of math on base")
}
else {
//...math on base color by incrementing d or 1/n
outputArray.push("result of math on base")
}
}
return outputArray;
}// end of buildColorStops
Shades can be generated by maintaining the ratio of the colors same. Suppose that your base color has (r,g,b) red, green, blue values.
So the ratio between the components is r:g:b. If you want to generate 10 shades then your shades would be.
(r/10, g/10, b/10)
(2*r/10, 2*g/10, 2*b/10)
(3*r/10, 3*g/10, 3*b/10)
(4*r/10, 4*g/10, 4*b/10) and so on
That's for the darker shades.
for lighter shades
(11*r/10, 11*g/10, 11*b/10)
(12*r/10, 12*g/10, 12*b/10)
(13*r/10, 13*g/10, 13*b/10) and so on
Check resulting values of r,g, b to not be more than 255 as lightening them increases their values.
In fact to avoid going over 255, you can check whichever of r,g,b is maximum and use that value to generate shades.
var max = Math.max(Math.max(r, Math.max(g,b)), 1);
var step = 255 / (max * 10)
(r * step, g * step, b * step)
(r * step * 2, g * step * 2, b * step * 2)
(r * step * 3, g * step * 3, b * step * 3)
I got ready function to create a Sphere using Raphael javascript. Below is the code
Raphael.fn.ball = function (x, y, r, hue) {
hue = hue || 0;
return this.ellipse(x, y, r, r).attr({fill: "r(.3,.25)hsb(" + hue + ", 1, .99)-hsb(" + hue + ", .5, .25)", stroke: "none"});
};
This function creates the sphere with the shaded color inside it. The color is generated using the hue variable passed to it. In the orginal code the value of the hue parameter was taken from 'Math.random()'. But now i want my expected color shade to the sphere. I have Hex codes for the expected code, but I dont know how to get exact hue parameter value to generate same color.
Basically I want to understand -
How I can read the expression - "r(.3,.25)hsb(" + hue + ", 1, .99)-hsb(" + hue + ", .5, .25)"?
How I can find the hue parameter value to get given color(e.g. - #FEFE31)
Note: I am using HTML and javascript only
Any help is highly appritiated
You must convert your Hex color to RGB and then to HSB
var hex = "#cc0000";
var rgb = Raphael.getRGB(hex)
var hsb = Raphael.rgb2hsb(rgb)
alert(hsb.h + " is the hue");
Keep in mind that RGB doesn't map perfectly to HSB. So, for example, if you set...
fill: "hsb(.55, 0%, 0%)"
You might get back something different for hue.h, as in pure black the hue doesn't matter.
Raphael.fn.ball = function (x, y, r, hue) {
hue = hue || 0;
var hex = hue;
var rgb = Raphael.getRGB(hex)
var hsb = Raphael.rgb2hsb(rgb)
return this.ellipse(x, y, r, r).attr({fill: "r(.3,.25)hsb(" + hsb['h'] + ", 1, .99)-hsb(" + hsb['h'] + ", .5, .25)", stroke: "none"});
};`
using #Duopixel's response plus your code, this has been concocted together, i believe this is what you wanted.