How to subtract a color from another - javascript

Is it possible to subtract a color from another one ?
Example (correct me if i'm wrong):
If i subtract red and green from white, i am expecting the
result to be blue.
var white = 0xFFFFFF,
red = 0xFF0000,
result = white - red;
console.log(result); //65535 <-- what is that ? can it be converted to 0x00FFFF ?
[update]
Thanks to Rocket's answer, it turned out i needed a function() to convert my results into an actual color.
Here is the final working example:
var toColor = function ( d ) {
var c = Number(d).toString(16);
return "#" + ( "000000".substr( 0, 6 - c.length ) + c.toUpperCase() );
},
white = 0xFFFFFF,
red = 0xFF0000,
green = 0x00FF00,
result = toColor( white - red - green );
console.log( result ); // logs the expected result: "#0000FF"

Your white-red works fine, it's just that JavaScript represents the values as base 10 values. You need to convert them back to base 16 (hex). Check out this answer, to convert the value back to hex.
var white = 0xFFFFFF, // Stored as 16777215
red = 0xFF0000, // Stored as 16711680
result = white - red; // 16777215 - 16711680 = 65535
console.log(result); // It's stored as base 10, so it prints 65535
var resultHex = result.toString(16); // 'ffff', converted back to hex

I'm just assuming you are using RGB, because there are plenty of other ways to mix colors. You have to represent a color into 3* different parts, R G and B.
// R G B
var white = [ 1, 1, 1];
var red = [ 0, 0, 0 ];
var result = [ white[0] - red[0], white[1] - red[1], white[2] - red[2] ;
To substract the color you have to substract each component of the color, and perhaps convert it back to hex later on.
* You might want to add Alpha later on

Related

Getting A Color Range From Percentage

What I'm Attempting
I am pulling from an API that gets a number between 1 and 32. I'm attempting to turn that return into a certain background color, ranging from green to red, for good to bad respectively. Basically, if the returning number is 32, the background turns bright red, while if it's 1, it returns bright green.
What I've Tried
Here's the Code currently.
function colorChange(x) {
let y = x.substring(0, x.length - 2); <<<----THIS IS TO TAKE THE NUMBER FROM 32ND TO JUST 32.
let z = y / 2
return "#" + z+z+z
}
<div
className="team-stat"
style={{backgroundColor: colorChange(teamStats.stats[1].splits[0].stat.pts)}}
>
<h4>Points:</h4>
<h1>{teamStats.stats[0].splits[0].stat.pts}</h1>
<h3>Rank: {teamStats.stats[1].splits[0].stat.pts}</h3>
</div>
Currently in the code I'm calling an API that results in a result from 1st to 32nd. I've already taken out the last two characters, so no th or nd are included. I managed to make it so it returns basically a hex code of #171717, but the current range goes from black to slightly-less-black. With the hex codes going into letters, I'm a little stumped on how to proceed.
Any help is appreciated,and I'll happily clarify on any misunderstandings.
You could use rgb() for the background-color then scale the red and green values depending on the x value. Assuming 32 is the most green, something like:
function colorChange(x) {
...
const maxPossibleScore = 32;
const individualPointValue = 255 / maxPossibleScore;
return {
red: 255 - individualPointValue * x,
green: individualPointValue * x
}
}
const colors = colorChange(10);
style={{backgroundColor: `rgb(${colors.red}, ${colors.green}, 0)`}}
This doesn't answer your question directly using hex but you in theory could slot in a decimal to hex translation and get the hex result you're looking for.
Use HSLA model for the background color. Then change the first parameter (hue) based on your value from 1 to 32 multiplied by 3.75 (120/32)
Here's an example: https://codepen.io/akost/pen/ZEJWZVx
<script>
let list='';
for(let i = 1; i <= 32; i++) {
let h = i*3.75; // we need hue values from 0 to 120
let row = `<div style='background:hsla(${h}, 100%, 50%, 1)'></div>`;
list += row;
}
document.getElementById('foo').innerHTML = list;
</script>
<style>
#foo div {
width:100px;
height:10px;
border-bottom:solid 1px #fff;
}
</style>
<div id="foo"></div>

seperate Red Green Blue value of rgba Colur value

I'hv rgba value in this format RGBA(205,31,31,1) and I want to separate each red, green, blue and alpha value for further processing how can I achieve it using jQuery;
so the output looks like
red = 205
green = 31
blue = 31
alpha =1
To get these values from a string variable is easy with the following answer so you don't need jQuery
With the help of regex, you can easily achieve it like
var color = "RGBA(205,31,31,1)";
var regExp = /\(([^)]+)\)/; // get the values within ()
var matches = regExp.exec(color);
var splits = matches[1].split(',');
alert("red: " + splits[0] + "green: " + splits[1]+ "blue: "+ splits[2]+ "alpha: " +splits[3] );
JSFiddle
However to get the rgba value from an element you can use jQuery's css method.
Without Regular Expression:
var colorString = "rgba(111,222,333,0.5)",
colorsOnly = colorString.substring(colorString.indexOf('(') + 1, colorString.lastIndexOf(')')).split(/,\s*/),
red = colorsOnly[0],
green = colorsOnly[1],
blue = colorsOnly[2],
opacity = colorsOnly[3];
var string = "RGBA(205,31,31,1)";
var colors = [];
string = string.replace(/[rgba\(\)]/gi, ''); // remove unnecessary characters
string = string.split(","); // split by comma
for(var i = 0;i < string.length; i++){
colors.push(parseFloat(string[i], 10)); // parse the integer and push in colors array
}
console.log(colors); // [ 205, 31, 31, 1 ] the values are in RGBA order
a simple modern approach:
"RGBA(205,31,31,1)".match(/[\d\.]+/g).map(Number); //==[205, 31, 31, 1]
or if you want an object, it's a bit more work:
"RGBA(205,31,31,1)".match(/[\d\.]+/g).map(Number)
.reduce(function(a,b,i){
a[["red","blue","green","alpha"][i]]=b;
return a;
}, {}); // == {red: 205, blue: 31, green: 31, alpha: 1}
using "".match() is nice because it ignores spaces in-between the numbers and the case of the "rgba" text as well.

Converting RGB to HEX fails

Following this question and many others, I'm trying to convert an rgb value to a hex value.
Copying/pasting the most used and accepted answer, I've made this script
function componentToHex(c) {
var hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
function rgbToHex(rgb) {
var colors = rgb.split("(")
colors = colors[1].split(")")
colors = colors[0].split(",")
var r = 255 - parseInt(colors[0])
var g = 255 - parseInt(colors[1])
var b = 255 - parseInt(colors[2])
return componentToHex(r) + componentToHex(g) + componentToHex(b);
}
alert(rgbToHex("rgb(0, 51, 255)"))
Result:
ffcc00
Expected result:
0033ff
Why is it not working?
Use the parseInt result directly, not 255 minus the value:
var r = parseInt(colors[0])
var g = parseInt(colors[1])
var b = parseInt(colors[2])
You're currently producing the exact opposite color by outputting values complementary to (rather than equivalent to) the input values.
Instead of 255 - parseInt(colors[i]), it should be parseInt(colors[i]).
In your current implementation - if red is 0, 255 - 0 = 255, which in hex is FF.

Generate Random Color distinguishable to Humans

I am trying to randomly generate a color in hex in javascript.
However the colors generated are almost indistinguishable from eachother.
Is there a way to improve it?
Here is the code I am using:
function randomColor(){
var allowed = "ABCDEF0123456789", S = "#";
while(S.length < 7){
S += allowed.charAt(Math.floor((Math.random()*16)+1));
}
return S;
}
I heard something about HSL and HSV color model but can't get
it to work in my code.
The easiest way to pick maximally different colors would be to to use HSL values instead of RGB and then manipulate Hue, as it has a value from 0 to 360 value and wraps around (0 is red, and so is 360);
if you need 10 distinguishable colors you can divide 360 by 10 and then pick the individual color by multiplying the value by index (zero based).
Here's an example function that allows you to pick a color from :
function selectColor(colorNum, colors){
if (colors < 1) colors = 1; // defaults to one color - avoid divide by zero
return "hsl(" + (colorNum * (360 / colors) % 360) + ",100%,50%)";
}
This way you can randomize the color selection by randomizing index, but colors will always be in the same palette.
This will select a random color from a palette of 10:
var color = selectColor(Math.floor(Math.random() * 10), 10);
and so will this:
var color = selectColor(Math.floor(Math.random() * 999), 10);
or you can select a specific color from the palette, like 9th color (index 8) out of palette of 13:
var color = selectColor(8, 13);
Here's a fiddle to play with: http://jsfiddle.net/2UE2B/
Update on 2020-02-23:
So, today I needed a solution to this same problem. Googling for this answer here (I know, a very weird way to look for stuff on SO) I ran into the Golden Angle concept. It would make the above example even more trivial, and would not require a predetermined number of colors to be provided:
function selectColor(number) {
const hue = number * 137.508; // use golden angle approximation
return `hsl(${hue},50%,75%)`;
}
This answers the #netoperator-wibby's question
I know I'm very late to this party, but I wrote up a more elaborate function to generate a set of contrasting random colors for another project. They are both (at least somewhat) attractive and genuinely random (not based on predefined colors) but my code is a bit more complicated than some of the other responses (so it's not for just getting the basics)
This is for users who want to have more than one random color on their page, and want to make sure no two colors are too similar.
Fiddle
var generateRandomColors=function(number){
/*
This generates colors using the following algorithm:
Each time you create a color:
Create a random, but attractive, color{
Red, Green, and Blue are set to random luminosity.
One random value is reduced significantly to prevent grayscale.
Another is increased by a random amount up to 100%.
They are mapped to a random total luminosity in a medium-high range (bright but not white).
}
Check for similarity to other colors{
Check if the colors are very close together in value.
Check if the colors are of similar hue and saturation.
Check if the colors are of similar luminosity.
If the random color is too similar to another,
and there is still a good opportunity to change it:
Change the hue of the random color and try again.
}
Output array of all colors generated
*/
//if we've passed preloaded colors and they're in hex format
if(typeof(arguments[1])!='undefined'&&arguments[1].constructor==Array&&arguments[1][0]&&arguments[1][0].constructor!=Array){
for(var i=0;i<arguments[1].length;i++){ //for all the passed colors
var vals = /^#?([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.exec(arguments[1][i]); //get RGB values
arguments[1][i]=[parseInt(vals[1], 16),parseInt(vals[2], 16),parseInt(vals[3], 16)]; //and convert them to base 10
}
}
var loadedColors=typeof(arguments[1])=='undefined'?[]:arguments[1],//predefine colors in the set
number=number+loadedColors.length,//reset number to include the colors already passed
lastLoadedReduction=Math.floor(Math.random()*3),//set a random value to be the first to decrease
rgbToHSL=function(rgb){//converts [r,g,b] into [h,s,l]
var r=rgb[0],g=rgb[1],b=rgb[2],cMax=Math.max(r,g,b),cMin=Math.min(r,g,b),delta=cMax-cMin,l=(cMax+cMin)/2,h=0,s=0;if(delta==0)h=0;else if(cMax==r)h=60*((g-b)/delta%6);else if(cMax==g)h=60*((b-r)/delta+2);else h=60*((r-g)/delta+4);if(delta==0)s=0;else s=delta/(1-Math.abs(2*l-1));return[h,s,l]
},hslToRGB=function(hsl){//converts [h,s,l] into [r,g,b]
var h=hsl[0],s=hsl[1],l=hsl[2],c=(1-Math.abs(2*l-1))*s,x=c*(1-Math.abs(h/60%2-1)),m=l-c/2,r,g,b;if(h<60){r=c;g=x;b=0}else if(h<120){r=x;g=c;b=0}else if(h<180){r=0;g=c;b=x}else if(h<240){r=0;g=x;b=c}else if(h<300){r=x;g=0;b=c}else{r=c;g=0;b=x}return[r,g,b]
},shiftHue=function(rgb,degree){//shifts [r,g,b] by a number of degrees
var hsl=rgbToHSL(rgb); //convert to hue/saturation/luminosity to modify hue
hsl[0]+=degree; //increment the hue
if(hsl[0]>360){ //if it's too high
hsl[0]-=360 //decrease it mod 360
}else if(hsl[0]<0){ //if it's too low
hsl[0]+=360 //increase it mod 360
}
return hslToRGB(hsl); //convert back to rgb
},differenceRecursions={//stores recursion data, so if all else fails we can use one of the hues already generated
differences:[],//used to calculate the most distant hue
values:[]//used to store the actual colors
},fixDifference=function(color){//recursively asserts that the current color is distinctive
if(differenceRecursions.values.length>23){//first, check if this is the 25th recursion or higher. (can we try any more unique hues?)
//if so, get the biggest value in differences that we have and its corresponding value
var ret=differenceRecursions.values[differenceRecursions.differences.indexOf(Math.max.apply(null,differenceRecursions.differences))];
differenceRecursions={differences:[],values:[]}; //then reset the recursions array, because we're done now
return ret; //and then return up the recursion chain
} //okay, so we still have some hues to try.
var differences=[]; //an array of the "difference" numbers we're going to generate.
for(var i=0;i<loadedColors.length;i++){ //for all the colors we've generated so far
var difference=loadedColors[i].map(function(value,index){ //for each value (red,green,blue)
return Math.abs(value-color[index]) //replace it with the difference in that value between the two colors
}),sumFunction=function(sum,value){ //function for adding up arrays
return sum+value
},sumDifference=difference.reduce(sumFunction), //add up the difference array
loadedColorLuminosity=loadedColors[i].reduce(sumFunction), //get the total luminosity of the already generated color
currentColorLuminosity=color.reduce(sumFunction), //get the total luminosity of the current color
lumDifference=Math.abs(loadedColorLuminosity-currentColorLuminosity), //get the difference in luminosity between the two
//how close are these two colors to being the same luminosity and saturation?
differenceRange=Math.max.apply(null,difference)-Math.min.apply(null,difference),
luminosityFactor=50, //how much difference in luminosity the human eye should be able to detect easily
rangeFactor=75; //how much difference in luminosity and saturation the human eye should be able to dect easily
if(luminosityFactor/(lumDifference+1)*rangeFactor/(differenceRange+1)>1){ //if there's a problem with range or luminosity
//set the biggest difference for these colors to be whatever is most significant
differences.push(Math.min(differenceRange+lumDifference,sumDifference));
}
differences.push(sumDifference); //otherwise output the raw difference in RGB values
}
var breakdownAt=64, //if you're generating this many colors or more, don't try so hard to make unique hues, because you might fail.
breakdownFactor=25, //how much should additional colors decrease the acceptable difference
shiftByDegrees=15, //how many degrees of hue should we iterate through if this fails
acceptableDifference=250, //how much difference is unacceptable between colors
breakVal=loadedColors.length/number*(number-breakdownAt), //break down progressively (if it's the second color, you can still make it a unique hue)
totalDifference=Math.min.apply(null,differences); //get the color closest to the current color
if(totalDifference>acceptableDifference-(breakVal<0?0:breakVal)*breakdownFactor){ //if the current color is acceptable
differenceRecursions={differences:[],values:[]} //reset the recursions object, because we're done
return color; //and return that color
} //otherwise the current color is too much like another
//start by adding this recursion's data into the recursions object
differenceRecursions.differences.push(totalDifference);
differenceRecursions.values.push(color);
color=shiftHue(color,shiftByDegrees); //then increment the color's hue
return fixDifference(color); //and try again
},color=function(){ //generate a random color
var scale=function(x){ //maps [0,1] to [300,510]
return x*210+300 //(no brighter than #ff0 or #0ff or #f0f, but still pretty bright)
},randVal=function(){ //random value between 300 and 510
return Math.floor(scale(Math.random()))
},luminosity=randVal(), //random luminosity
red=randVal(), //random color values
green=randVal(), //these could be any random integer but we'll use the same function as for luminosity
blue=randVal(),
rescale, //we'll define this later
thisColor=[red,green,blue], //an array of the random values
/*
#ff0 and #9e0 are not the same colors, but they are on the same range of the spectrum, namely without blue.
Try to choose colors such that consecutive colors are on different ranges of the spectrum.
This shouldn't always happen, but it should happen more often then not.
Using a factor of 2.3, we'll only get the same range of spectrum 15% of the time.
*/
valueToReduce=Math.floor(lastLoadedReduction+1+Math.random()*2.3)%3, //which value to reduce
/*
Because 300 and 510 are fairly close in reference to zero,
increase one of the remaining values by some arbitrary percent betweeen 0% and 100%,
so that our remaining two values can be somewhat different.
*/
valueToIncrease=Math.floor(valueToIncrease+1+Math.random()*2)%3, //which value to increase (not the one we reduced)
increaseBy=Math.random()+1; //how much to increase it by
lastLoadedReduction=valueToReduce; //next time we make a color, try not to reduce the same one
thisColor[valueToReduce]=Math.floor(thisColor[valueToReduce]/16); //reduce one of the values
thisColor[valueToIncrease]=Math.ceil(thisColor[valueToIncrease]*increaseBy) //increase one of the values
rescale=function(x){ //now, rescale the random numbers so that our output color has the luminosity we want
return x*luminosity/thisColor.reduce(function(a,b){return a+b}) //sum red, green, and blue to get the total luminosity
};
thisColor=fixDifference(thisColor.map(function(a){return rescale(a)})); //fix the hue so that our color is recognizable
if(Math.max.apply(null,thisColor)>255){ //if any values are too large
rescale=function(x){ //rescale the numbers to legitimate hex values
return x*255/Math.max.apply(null,thisColor)
}
thisColor=thisColor.map(function(a){return rescale(a)});
}
return thisColor;
};
for(var i=loadedColors.length;i<number;i++){ //Start with our predefined colors or 0, and generate the correct number of colors.
loadedColors.push(color().map(function(value){ //for each new color
return Math.round(value) //round RGB values to integers
}));
}
//then, after you've made all your colors, convert them to hex codes and return them.
return loadedColors.map(function(color){
var hx=function(c){ //for each value
var h=c.toString(16);//then convert it to a hex code
return h.length<2?'0'+h:h//and assert that it's two digits
}
return "#"+hx(color[0])+hx(color[1])+hx(color[2]); //then return the hex code
});
}
Please note, although I don't do so in my example, that this can also be used to add new distinct, random colors to a set:
generateRandomColors(1,generateRandomColors(10))
You could use a fixed set of colors, such as the ones listed in the jquery.color.js plugin.
List of colors from jquery.color.js plugin:
Colors = {};
Colors.names = {
aqua: "#00ffff",
azure: "#f0ffff",
beige: "#f5f5dc",
black: "#000000",
blue: "#0000ff",
brown: "#a52a2a",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgrey: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkviolet: "#9400d3",
fuchsia: "#ff00ff",
gold: "#ffd700",
green: "#008000",
indigo: "#4b0082",
khaki: "#f0e68c",
lightblue: "#add8e6",
lightcyan: "#e0ffff",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightyellow: "#ffffe0",
lime: "#00ff00",
magenta: "#ff00ff",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
orange: "#ffa500",
pink: "#ffc0cb",
purple: "#800080",
violet: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
white: "#ffffff",
yellow: "#ffff00"
};
The rest is simply picking a random property from a Javascript object.
Colors.random = function() {
var result;
var count = 0;
for (var prop in this.names)
if (Math.random() < 1/++count)
result = prop;
return result;
};
Using Colors.random() might get you a human-readable color. I even powered an example below.
(function(){
Colors = {};
Colors.names = {
aqua: "#00ffff",
azure: "#f0ffff",
beige: "#f5f5dc",
black: "#000000",
blue: "#0000ff",
brown: "#a52a2a",
cyan: "#00ffff",
darkblue: "#00008b",
darkcyan: "#008b8b",
darkgrey: "#a9a9a9",
darkgreen: "#006400",
darkkhaki: "#bdb76b",
darkmagenta: "#8b008b",
darkolivegreen: "#556b2f",
darkorange: "#ff8c00",
darkorchid: "#9932cc",
darkred: "#8b0000",
darksalmon: "#e9967a",
darkviolet: "#9400d3",
fuchsia: "#ff00ff",
gold: "#ffd700",
green: "#008000",
indigo: "#4b0082",
khaki: "#f0e68c",
lightblue: "#add8e6",
lightcyan: "#e0ffff",
lightgreen: "#90ee90",
lightgrey: "#d3d3d3",
lightpink: "#ffb6c1",
lightyellow: "#ffffe0",
lime: "#00ff00",
magenta: "#ff00ff",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
orange: "#ffa500",
pink: "#ffc0cb",
purple: "#800080",
violet: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
white: "#ffffff",
yellow: "#ffff00"
};
Colors.random = function() {
var result;
var count = 0;
for (var prop in this.names)
if (Math.random() < 1/++count)
result = prop;
return { name: result, rgb: this.names[result]};
};
var $placeholder = $(".placeholder");
$placeholder.click(function(){
var color = Colors.random();
$placeholder.css({'background-color': color.rgb});
$("#color").html("It's " + color.name);
});
})();
.placeholder {
width: 150px;
height: 150px;
border: 1px solid black;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="placeholder"></div>
<span id="color">Click the square above.</span>
Try this:
function getRandomColor() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
See it in action:
http://jsfiddle.net/3wjgG/1/
What you are saying is that you do not want to generate random colors, you are saying that you want to generate different colors.
You can find a good tutorial on how to do it here: http://krazydad.com/tutorials/makecolors.php .
I made this fiddle with the relevant code from the tutorial demonstrating how you would generate non-repeating colors:
http://jsfiddle.net/rGL52/
The only differnce from the tutorial code is that the makegradient() function returns an array of colors that you can later apply at will in your page.
For randomly generating colors, I tend to go for something simple like this:
​function randomColor () {
var max = 0xffffff;
return '#' + Math.round( Math.random() * max ).toString( 16 );
}
​
I'm not sure what you mean by unrecognizable. This method doesn't offer much customization, but at very least makes it easy to keep numbers from being too light or too dark.
If you want to give bigger gaps between the generated colors, you could try reducing the number of allowed characters. I've used a method like that in the past where I only used 0369cf as the pool of characters to pull from. Combining this with a check for duplicates tends to give more distinguishable colors, as well as only utilizing the #fff 3-character syntax.
Here's your original function modified to use this method:
function randomColor(){
var allowed = "0369cf".split( '' ), s = "#";
while ( s.length < 4 ) {
s += allowed.splice( Math.floor( ( Math.random() * allowed.length ) ), 1 );
}
return s;
}
I needed to solve this problem today for a new course I'm writing, so here is my solution:
function getUniqueColor(n) {
const rgb = [0, 0, 0];
for (let i = 0; i < 24; i++) {
rgb[i%3] <<= 1;
rgb[i%3] |= n & 0x01;
n >>= 1;
}
return '#' + rgb.reduce((a, c) => (c > 0x0f ? c.toString(16) : '0' + c.toString(16)) + a, '')
}
It "spreads" the bits from the input number through the RGB values, backwards. It's not perfect, but the code is compact and adjacent colors are distinguishable. Here is the fiddle.
I agree with all the answers, we don't really know what you expect here...
This is a possibility that can give you the choice between the rgb(r, g, b) output for css elements, and the hex output...
This is a quick example, you have just to adapt this draft but it works as it on Firefox :
<script type="text/javascript">
//<![CDATA[
function RndColor(){
var maximum = 255;
var minimum = 100;
var range = maximum - minimum;
var red = Math.floor(Math.random()*range)+minimum;
var green = Math.floor(Math.random()*range)+minimum;
var blue = Math.floor(Math.random()*range)+minimum;
var redToHex = red.toString(16);
var greenToHex = green.toString(16);
var blueToHex = blue.toString(16);
this.rgbValue = "rgb(" + red + "," + green + "," + blue + ")";
this.hexValue = "#" + redToHex + "" + greenToHex + "" + blueToHex;
}
RndColor.prototype.getRGB = function(){
return this.rgbValue;
}
RndColor.prototype.getHex = function(){
return this.hexValue;
}
//]]>
</script>
Then you can retrieve the value as here bellow :
<script type="text/javascript">
//<![CDATA[
rndCol = new RndColor();
document.write("<div style = width:150px;height:100px;background-color:" + rndCol.getHex() + ">" + rndCol.getHex() + "</div><br /><br />");
document.write("<div style = width:150px;height:100px;background-color:" + rndCol.getRGB() + ">" + rndCol.getRGB() + "</div>");
//]]>
</script>
I hope this can help you.
Best regards.
First of all, why are you building hex values from strings? Just use numbers for the values, then output with something like yourNumber.toString(16).
Then, to make the colours more distinct, don't use the full range of 0 to 255 for each colour component, but maybe go in jumps of 10, or 20, or whatever you need to generate wide enough differences.
I wrote up a small script called SwitchColors.js which can be found here: https://github.com/akulmehta/SwitchColors.js
The script produces more saturated colors and the brightness can be controlled. Although it may not produce visually distinguishable colors, it produces high saturation and bright colors which can also be attractive.

Average 2 hex colors together in javascript

Alright thought I would throw this one out there for the crowd to think over.
Given a function (written in javascript) that expects two strings formated like a hex color (ex #FF0000)
return a hex color that is the average of both of the colors passed.
function averageColors(firstColor,secondColor)
{
...
return avgColor;
}
--edit--
average would be defined as
if the color passed was yellow and the second was light purple the returned color would be a medium orange
I hate sounding like the oh-so-broken jQuery record, but there is a jQuery plugin for this already.
A quick/dirty/convenient/ES6 way to blend two hex colors by a specified perecentage:
// blend two hex colors together by an amount
function blendColors(colorA, colorB, amount) {
const [rA, gA, bA] = colorA.match(/\w\w/g).map((c) => parseInt(c, 16));
const [rB, gB, bB] = colorB.match(/\w\w/g).map((c) => parseInt(c, 16));
const r = Math.round(rA + (rB - rA) * amount).toString(16).padStart(2, '0');
const g = Math.round(gA + (gB - gA) * amount).toString(16).padStart(2, '0');
const b = Math.round(bA + (bB - bA) * amount).toString(16).padStart(2, '0');
return '#' + r + g + b;
}
console.log(blendColors('#00FF66', '#443456', 0.5));
Where amount should be 0 to 1, with 0 being exactly colorA, 1 being exactly colorB, and 0.5 being the "midpoint".
Only requires a few lines of POJS if you don't want to bother with lots of unnecessary stuff:
// Expects input as 'nnnnnn' where each nn is a
// 2 character hex number for an RGB color value
// e.g. #3f33c6
// Returns the average as a hex number without leading #
var averageRGB = (function () {
// Keep helper stuff in closures
var reSegment = /[\da-z]{2}/gi;
// If speed matters, put these in for loop below
function dec2hex(v) {return v.toString(16);}
function hex2dec(v) {return parseInt(v,16);}
return function (c1, c2) {
// Split into parts
var b1 = c1.match(reSegment);
var b2 = c2.match(reSegment);
var t, c = [];
// Average each set of hex numbers going via dec
// always rounds down
for (var i=b1.length; i;) {
t = dec2hex( (hex2dec(b1[--i]) + hex2dec(b2[i])) >> 1 );
// Add leading zero if only one character
c[i] = t.length == 2? '' + t : '0' + t;
}
return c.join('');
}
}());
Smells like homework to me, but here's my clue.
Take each hex value for R, G, and B, and average each of them. If necessary convert to Decimal to do the math.
function d2h(d) {return d.toString(16).padStart(2,'0');}
function h2d(h) {return parseInt(h,16);}
Then return a string containing the concatenated values of the three elements.
Here's a compact set of relevant (interdependent) functions:
Hex ⟷ RGB Color Conversion:
function hexToRgb(h){return['0x'+h[1]+h[2]|0,'0x'+h[3]+h[4]|0,'0x'+h[5]+h[6]|0]}
function rgbToHex(r,g,b){return"#"+((1<<24)+(r<<16)+(g<<8)+ b).toString(16).slice(1);}
Calculate Average of 2 Hex Colors: Requires conversion functions (above)
function avgHex(h1,h2){a=hexToRgb(h1);b=hexToRgb(h2); return rgbToHex(~~((a[0]+b[0])/2),~~((a[1]+b[1])/2),~~((a[2]+b[2])/2));}
Generate Random Hex Color:
function rndHex(){return'#'+('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6);}
Run snippet for demo:
// color functions (average/random/conversion)
function hexToRgb(h){return['0x'+h[1]+h[2]|0,'0x'+h[3]+h[4]|0,'0x'+h[5]+h[6]|0]}
function rgbToHex(r,g,b){return"#"+((1<<24)+(r<<16)+(g<<8)+ b).toString(16).slice(1);}
function rndHex(){return'#'+('00000'+(Math.random()*(1<<24)|0).toString(16)).slice(-6);}
function avgHex(h1,h2){a=hexToRgb(h1);b=hexToRgb(h2);return rgbToHex(~~((a[0]+b[0])/2),~~((a[1]+b[1])/2),~~((a[2]+b[2])/2));}
//code below is just for the demo
function auto(){if(chk.checked){tmr=setInterval(rnd,1000)}else{clearTimeout(tmr)}}auto();
function rnd(go){for(h of[h1,h2]){h.value=rndHex();}avgInput();}
addEventListener('input',avgInput);
function avgInput(){ // get avg & colorize
ha.value=avgHex(h1.value,h2.value);
for(h of [h1,h2,ha])h.style.background=h.value;
}
*{font-family:monospace;font-size:5vw; }
<label>Color 1 → <input id='h1'></label><br>
<label>Average → <input id='ha'></label><br>
<label>Color 2 → <input id='h2'></label><br>
<label>Type hex colors or <input type='checkbox' id='chk' onclick='auto()' style=' transform: scale(1.5)'checked>Autorandom</label>
Here is my function, hope it helps.
function averageColors( colorArray ){
var red = 0, green = 0, blue = 0;
for ( var i = 0; i < colorArray.length; i++ ){
red += hexToR( "" + colorArray[ i ] + "" );
green += hexToG( "" + colorArray[ i ] + "" );
blue += hexToB( "" + colorArray[ i ] + "" );
}
//Average RGB
red = (red/colorArray.length);
green = (green/colorArray.length);
blue = (blue/colorArray.length);
console.log(red + ", " + green + ", " + blue);
return new THREE.Color( "rgb("+ red +","+ green +","+ blue +")" );
}
//get the red of RGB from a hex value
function hexToR(h) {return parseInt((cutHex( h )).substring( 0, 2 ), 16 )}
//get the green of RGB from a hex value
function hexToG(h) {return parseInt((cutHex( h )).substring( 2, 4 ), 16 )}
//get the blue of RGB from a hex value
function hexToB(h) {return parseInt((cutHex( h )).substring( 4, 6 ), 16 )}
//cut the hex into pieces
function cutHex(h) {if(h.charAt(1) == "x"){return h.substring( 2, 8 );} else {return h.substring(1,7);}}
Very late to this party, but I was personally looking for a way to average an undefined amount of HEX values. Based on the answer #RobG, I came up with this. Granted, the more colors you add the more brown/greyish they get, but, perhaps it helps!
/**
* Averages an array of hex colors. Returns one hex value (with leading #)
*
* #param {Array} colors - An array of hex strings, e.g. ["#001122", "#001133", ...]
*/
function averageHex(colors) {
// transform all hex codes to integer arrays, e.g. [[R, G, B], [R,G,B], ...]
let numbers = colors.map(function(hex) {
// split in seperate R, G and B
let split = hex.match(/[\da-z]{2}/gi);
// transform to integer values
return split.map(function(toInt) {
return parseInt(toInt, 16);
});
});
// reduce the array by averaging all values, resulting in an average [R, G, B]
let averages = numbers.reduce(function(total, amount, index, array) {
return total.map(function(subtotal, subindex) {
// if we reached the last color, average it out and return the hex value
if (index == array.length - 1) {
let result = Math.round((subtotal + amount[subindex]) / array.length).toString(16);
// add a leading 0 if it is only one character
return result.length == 2 ? '' + result : '0' + result;
} else {
return subtotal + amount[subindex];
}
});
});
// return them as a single hex string
return "#" + averages.join('');
}
console.log(averageHex(["#FF110C", "#0000AA", "#55063d", "#06551e"]));
// expected: #571b44, see also https://www.colorhexa.com/ and enter "#FF110C+#0000AA+#55063d+#06551e"
Here is the function
function avgColor(color1, color2) {
//separate each color alone (red, green, blue) from the first parameter (color1)
//then convert to decimal
let color1Decimal = {
red: parseInt(color1.slice(0, 2), 16),
green: parseInt(color1.slice(2, 4), 16),
blue: parseInt(color1.slice(4, 6), 16)
}
//separate each color alone (red, green, blue) from the second parameter (color2)
//then convert to decimal
let color2Decimal = {
red: parseInt(color2.slice(0, 2), 16),
green: parseInt(color2.slice(2, 4), 16),
blue: parseInt(color2.slice(4, 6), 16),
}
// calculate the average of each color (red, green, blue) from each parameter (color1,color2)
let color3Decimal = {
red: Math.ceil((color1Decimal.red + color2Decimal.red) / 2),
green: Math.ceil((color1Decimal.green + color2Decimal.green) / 2),
blue: Math.ceil((color1Decimal.blue + color2Decimal.blue) / 2)
}
//convert the result to hexadecimal and don't forget if the result is one character
//then convert it to uppercase
let color3Hex = {
red: color3Decimal.red.toString(16).padStart(2, '0').toUpperCase(),
green: color3Decimal.green.toString(16).padStart(2, '0').toUpperCase(),
blue: color3Decimal.blue.toString(16).padStart(2, '0').toUpperCase()
}
//put the colors (red, green, blue) together to have the output
let color3 = color3Hex.red + color3Hex.green + color3Hex.blue
return color3
}
console.log(avgColor("FF33CC", "3300FF"))
// avgColor("FF33CC", "3300FF") => "991AE6"
console.log(avgColor("991AE6", "FF0000"))
// avgColor("991AE6", "FF0000") => "CC0D73"
console.log(avgColor("CC0D73", "0000FF"))
// avgColor("CC0D73", "0000FF") => "6607B9"
To check you can use this link and midpoint 1 then blend
https://meyerweb.com/eric/tools/color-blend/#CC0D73:0000FF:1:hex

Categories

Resources