Logic of comparing two RGB colours for contrast in Javascript [duplicate] - javascript

Pretty straight-forward, take yellow and white:
back_color = {r:255,g:255,b:255}; //white
text_color = {r:255,g:255,b:0}; //yellow
What law of physics on God's Earth of universal constants, makes the fact that yellow text can't be read on white backgrounds but blue text can?
For the sake of my customizable widget I tried all possible color models that I found conversions functions for; neither can say that green can be on white and yellow can't, based on just numerical comparisons.
I looked at Adsense (which is created by the Budda of all Internet) and guess what they did, they made presets and color cells distance calculations. I can't to do that. My users have the right to pick even the most retina-inflammatory, unaesthetic combinations, as long as the text can still be read.

According to Wikipedia, when converting to grayscale representation of luminance, "one must obtain the values of its red, green, and blue" and mix them in next proportion: R:30% G:59% B:11%
Therefore white will have 100% luminance and yellow will have 89%. At the same time, green has as small as 59%. 11% is almost four times lower than 41% difference!
And even lime (#00ff00) is not good for reading large amounts of texts.
IMHO for good contrast colors' brightness should differ at least for 50%. And this brightness should be measured as converted to grayscale.
upd: Recently found a comprehensive tool for that on the web
which in order uses formula from w3 document
Threshold values could be taken from #1.4
Here is an implementation for this more advanced thing.
function luminance(r, g, b) {
var a = [r, g, b].map(function(v) {
v /= 255;
return v <= 0.03928 ?
v / 12.92 :
Math.pow((v + 0.055) / 1.055, 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
}
function contrast(rgb1, rgb2) {
var lum1 = luminance(rgb1[0], rgb1[1], rgb1[2]);
var lum2 = luminance(rgb2[0], rgb2[1], rgb2[2]);
var brightest = Math.max(lum1, lum2);
var darkest = Math.min(lum1, lum2);
return (brightest + 0.05) /
(darkest + 0.05);
}
console.log(contrast([255, 255, 255], [255, 255, 0])); // 1.074 for yellow
console.log(contrast([255, 255, 255], [0, 0, 255])); // 8.592 for blue
// minimal recommended contrast ratio is 4.5, or 3 for larger font-sizes
For more information, check the WCAG 2.0 documentation on how to compute this value.

There are various ways for calculating contrast, but a common way is this formula:
brightness = (299*R + 587*G + 114*B) / 1000
You do this for both colors, and then you take the difference. This obviously gives a much greater contrast for blue on white than yellow on white.

const getLuminanace = (values) => {
const rgb = values.map((v) => {
const val = v / 255;
return val <= 0.03928 ? val / 12.92 : ((val + 0.055) / 1.055) ** 2.4;
});
return Number((0.2126 * rgb[0] + 0.7152 * rgb[1] + 0.0722 * rgb[2]).toFixed(3));
};
const getContrastRatio = (colorA, colorB) => {
const lumA = getLuminanace(colorA);
const lumB = getLuminanace(colorB);
return (Math.max(lumA, lumB) + 0.05) / (Math.min(lumA, lumB) + 0.05);
};
// usage:
const back_color = [255,255,255]; //white
const text_color = [255,255,0]; //yellow
getContrastRatio(back_color, text_color); // 1.0736196319018405

Based on the kirilloid answer:
Angular Service that will calculate contrast and luminescence by passing in the hex value:
.service('ColorContrast', [function() {
var self = this;
/**
* Return iluminance value (base for getting the contrast)
*/
self.calculateIlluminance = function(hexColor) {
return calculateIluminance(hexColor);
};
/**
* Calculate contrast value to white
*/
self.contrastToWhite = function(hexColor){
var whiteIlluminance = 1;
var illuminance = calculateIlluminance(hexColor);
return whiteIlluminance / illuminance;
};
/**
* Bool if there is enough contrast to white
*/
self.isContrastOkToWhite = function(hexColor){
return self.contrastToWhite(hexColor) > 4.5;
};
/**
* Convert HEX color to RGB
*/
var hex2Rgb = function(hex) {
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result ? {
r: parseInt(result[1], 16),
g: parseInt(result[2], 16),
b: parseInt(result[3], 16)
} : null;
};
/**
* Calculate iluminance
*/
var calculateIlluminance = function(hexColor) {
var rgbColor = hex2Rgb(hexColor);
var r = rgbColor.r, g = rgbColor.g, b = rgbColor.b;
var a = [r, g, b].map(function(v) {
v /= 255;
return (v <= 0.03928) ?
v / 12.92 :
Math.pow(((v + 0.055) / 1.055), 2.4);
});
return a[0] * 0.2126 + a[1] * 0.7152 + a[2] * 0.0722;
};
}]);

Recently I came across the answer on this page, and I used the code make a script for Adobe Illustrator to calculate the contrast ratio's.
Here you can see the result: http://screencast.com/t/utT481Ut
Some of the shorthand notations of the script above where confusing for me and where not working in Adobe extend script. Therefore I thought would be nice to share my improvement/interpretation of the code that kirilloid shared.
function luminance(r, g, b) {
var colorArray = [r, g, b];
var colorFactor;
var i;
for (i = 0; i < colorArray.length; i++) {
colorFactor = colorArray[i] / 255;
if (colorFactor <= 0.03928) {
colorFactor = colorFactor / 12.92;
} else {
colorFactor = Math.pow(((colorFactor + 0.055) / 1.055), 2.4);
}
colorArray[i] = colorFactor;
}
return (colorArray[0] * 0.2126 + colorArray[1] * 0.7152 + colorArray[2] * 0.0722) + 0.05;
}
And of course you need to call this function
within a for loop I get all the colors from my illustrator object
//just a snippet here to demonstrate the notation
var selection = app.activeDocument.selection;
for (i = 0; i < selection.length; i++) {
red[i] = selection[i].fillColor.red;
//I left out the rest,because it would become to long
}
//this can then be used to calculate the contrast ratio.
var foreGround = luminance(red[0], green[0], blue[0]);
var background = luminance(red[1], green[1], blue[1]);
luminanceValue = foreGround / background;
luminanceValue = round(luminanceValue, 2);
//for rounding the numbers I use this function:
function round(number, decimals) {
return +(Math.round(number + "e+" + decimals) + "e-" + decimals);
}
More information about contrast ratio: http://webaim.org/resources/contrastchecker/

module.exports = function colorcontrast (hex) {
var color = {};
color.contrast = function(rgb) {
// check if we are receiving an element or element background-color
if (rgb instanceof jQuery) {
// get element background-color
rgb = rgb.css('background-color');
} else if (typeof rgb !== 'string') {
return;
}
// Strip everything except the integers eg. "rgb(" and ")" and " "
rgb = rgb.split(/\(([^)]+)\)/)[1].replace(/ /g, '');
// map RGB values to variables
var r = parseInt(rgb.split(',')[0], 10),
g = parseInt(rgb.split(',')[1], 10),
b = parseInt(rgb.split(',')[2], 10),
a;
// if RGBA, map alpha to variable (not currently in use)
if (rgb.split(',')[3] !== null) {
a = parseInt(rgb.split(',')[3], 10);
}
// calculate contrast of color (standard grayscale algorithmic formula)
var contrast = (Math.round(r * 299) + Math.round(g * 587) + Math.round(b * 114)) / 1000;
return (contrast >= 128) ? 'black' : 'white';
};
// Return public interface
return color;
};

For calculate the contrast programmatically, you can use the NPM's color package; if you just want a tool for compare colors then you can use a Contrast Ratio Calculator

Related

Get exact color from two colors with percentage in javascript

I have a percentage variable and two colors in javascript.
Ex. One color is #D7F0FE & another color is #3DB6FC
Percentage variable is 30 (%)
I need to get exact color from these three values.
If percentage is zero then it should be #D7F0FE and if it's 100 then it should be #3DB6FC.
Need to find the best way to do that
I recommend to use RGB value as this value define with numbers.
Such as
#D7F0FE -> rgb(215, 240, 254)
#3DB6FC -> rgb(61, 182, 252)
Now do some math to generate rgb value dynamically based on percentage.
Please check the following code, it generate rgb value depending on Input Percentage.
<html>
<head>
</head>
<body id="body">
<input type="number" id="input-p">
<button onclick="changePercentage()">Percentage: </button>
<script>
var body = document.getElementById('body');
var rgb1 = [215, 240, 254];
var rgb2 = [61, 182, 252];
var rgb = [];
var p = 0;
var r = (rgb2[0] - rgb1[0])/100;
var g = (rgb2[1] - rgb1[1])/100;
var b = (rgb2[2] - rgb1[2])/100;
var color = 'rgb(215, 240, 254)';
body.style.background = color;
function newColor(){
console.log(p * r);
rgb = [
Math.ceil(rgb1[0] + (p * r)),
Math.ceil(rgb1[1] + (p * g)),
Math.ceil(rgb1[2] + (p * b))
];
color = 'rgb('+rgb[0]+','+rgb[1]+','+rgb[2]+')';
body.style.background = color;
}
function changePercentage(){
p = document.getElementById('input-p').value;
newColor();
}
</script>
</body>
</html>
not optimized
Here is a clean solution based on this comment here:
/** eg. gradient("#FF0000", "#0000FF", 0.5) => "#800080" */
function gradient(color1, color2, ratio) {
const from = rgb(color1)
const to = rgb(color2)
const r = Math.ceil(from.r * ratio + to.r * (1 - ratio));
const g = Math.ceil(from.g * ratio + to.g * (1 - ratio));
const b = Math.ceil(from.b * ratio + to.b * (1 - ratio));
return "#" + hex(r) + hex(g) + hex(b);
}
/** eg. rgb("#FF0080") => { r: 256, g: 0, b: 128 } */
function rgb(color) {
const hex = color.replace("#", "")
return {
r: parseInt(hex.substring(0, 2), 16),
g: parseInt(hex.substring(2, 4), 16),
b: parseInt(hex.substring(4, 6), 16),
}
}
/** eg. hex(123) => "7b" */
function hex(num) {
num = num.toString(16);
return (num.length == 1) ? '0' + num : num;
}

Find regions of similar color in image

I've been working on this problem for some time now with little promising results. I am trying to split up an image into connected regions of similar color. (basically split a list of all the pixels into multiple groups (each group containing the coordinates of the pixels that belong to it and share a similar color).
For example:
http://unsplash.com/photos/SoC1ex6sI4w/
In this image the dark clouds at the top would probably fall into one group. Some of the grey rock on the mountain in another, and some of the orange grass in another. The snow would be another - the red of the backpack - etc.
I'm trying to design an algorithm that will be both accurate and efficient (it needs to run in a matter of ms on midrange laptop grade hardware)
Below is what I have tried:
Using a connected component based algorithm to go through every pixel from top left scanning every line of pixels from left to right (and comparing the current pixel to the top pixel and left pixel). Using the CIEDE2000 color difference formula if the pixel at the top or left was within a certain range then it would be considered "similar" and part of the group.
This sort of worked - but the problem is it relies on color regions having sharp edges - if any color groups are connected by a soft gradient it will travel down that gradient and continue to "join" the pixels as the difference between the individual pixels being compared is small enough to be considered "similar".
To try to fix this I chose to set every visited pixel's color to the color of most "similar" adjacent pixel (either top or left). If there are no similar pixels than it retains it's original color. This somewhat fixes the issue of more blurred boundaries or soft edges because the first color of a new group will be "carried" along as the algorithm progresses and eventually the difference between that color and the current compared color will exceed the "similarity" threashold and no longer be part of that group.
Hopefully this is making sense. The problem is neither of these options are really working. On the image above what is returned are not clean groups but noisy fragmented groups that is not what I am looking for.
I'm not looking for code specifically - but more ideas as to how an algorithm could be structured to successfully combat this problem. Does anyone have ideas about this?
Thanks!
You could convert from RGB to HSL to make it easier to calculate the distance between the colors. I'm setting the color difference tolerance in the line:
if (color_distance(original_pixels[i], group_headers[j]) < 0.3) {...}
If you change 0.3, you can get different results.
See it working.
Please, let me know if it helps.
function hsl_to_rgb(h, s, l) {
// from http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
var r, g, b;
if (s == 0) {
r = g = b = l; // achromatic
} else {
var hue2rgb = function hue2rgb(p, q, 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;
}
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
function rgb_to_hsl(r, g, b) {
// from http://stackoverflow.com/questions/2353211/hsl-to-rgb-color-conversion
r /= 255, g /= 255, b /= 255;
var max = Math.max(r, g, b),
min = Math.min(r, g, b);
var h, s, l = (max + min) / 2;
if (max == min) {
h = s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return [h, s, l];
}
function color_distance(v1, v2) {
// from http://stackoverflow.com/a/13587077/1204332
var i,
d = 0;
for (i = 0; i < v1.length; i++) {
d += (v1[i] - v2[i]) * (v1[i] - v2[i]);
}
return Math.sqrt(d);
};
function round_to_groups(group_nr, x) {
var divisor = 255 / group_nr;
return Math.ceil(x / divisor) * divisor;
};
function pixel_data_to_key(pixel_data) {
return pixel_data[0].toString() + '-' + pixel_data[1].toString() + '-' + pixel_data[2].toString();
}
function posterize(context, image_data, palette) {
for (var i = 0; i < image_data.data.length; i += 4) {
rgb = image_data.data.slice(i, i + 3);
hsl = rgb_to_hsl(rgb[0], rgb[1], rgb[2]);
key = pixel_data_to_key(hsl);
if (key in palette) {
new_hsl = palette[key];
new_rgb = hsl_to_rgb(new_hsl[0], new_hsl[1], new_hsl[2]);
rgb = hsl_to_rgb(hsl);
image_data.data[i] = new_rgb[0];
image_data.data[i + 1] = new_rgb[1];
image_data.data[i + 2] = new_rgb[2];
}
}
context.putImageData(image_data, 0, 0);
}
function draw(img) {
var canvas = document.getElementById('canvas');
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, canvas.width, canvas.height);
img.style.display = 'none';
var image_data = context.getImageData(0, 0, canvas.width, canvas.height);
var data = image_data.data;
context.drawImage(target_image, 0, 0, canvas.width, canvas.height);
data = context.getImageData(0, 0, canvas.width, canvas.height).data;
original_pixels = [];
for (i = 0; i < data.length; i += 4) {
rgb = data.slice(i, i + 3);
hsl = rgb_to_hsl(rgb[0], rgb[1], rgb[2]);
original_pixels.push(hsl);
}
group_headers = [];
groups = {};
for (i = 0; i < original_pixels.length; i += 1) {
if (group_headers.length == 0) {
group_headers.push(original_pixels[i]);
}
group_found = false;
for (j = 0; j < group_headers.length; j += 1) {
// if a similar color was already observed
if (color_distance(original_pixels[i], group_headers[j]) < 0.3) {
group_found = true;
if (!(pixel_data_to_key(original_pixels[i]) in groups)) {
groups[pixel_data_to_key(original_pixels[i])] = group_headers[j];
}
}
if (group_found) {
break;
}
}
if (!group_found) {
if (group_headers.indexOf(original_pixels[i]) == -1) {
group_headers.push(original_pixels[i]);
}
if (!(pixel_data_to_key(original_pixels[i]) in groups)) {
groups[pixel_data_to_key(original_pixels[i])] = original_pixels[i];
}
}
}
posterize(context, image_data, groups)
}
var target_image = new Image();
target_image.crossOrigin = "";
target_image.onload = function() {
draw(target_image)
};
target_image.src = "http://i.imgur.com/zRzdADA.jpg";
canvas {
width: 300px;
height: 200px;
}
<canvas id="canvas"></canvas>
You can use "Mean Shift Filtering" algorithm to do the same.
Here's an example.
You will have to determine function parameters heuristically.
And here's the wrapper for the same in node.js
npm Wrapper for meanshift algorithm
Hope this helps!
The process you are trying to complete is called Image Segmentation and it's a well studied area in computer vision, with hundreds of different algorithms and implementations.
The algorithm you mentioned should work for simple images, however for real world images such as the one you linked to, you will probably need a more sophisticated algorithm, maybe even one that is domain specific (are all of your images contains a view?).
I have little experience in Node.js, however from Googling a bit I found the GraphicsMagic library, which as a segment function that might do the job (haven't verified).
In any case, I would try looking for "Image segmentation" libraries, and if possible, not limit myself only to Node.js implementations, as this language is not the common practice for writing vision applications, as opposed to C++ / Java / Python.
I would try a different aproach. Check out this description of how a flood fill algorithm could work:
Create an array to hold information about already colored coordinates.
Create a work list array to hold coordinates that must be looked at. Put the start position in it.
When the work list is empty, we are done.
Remove one pair of coordinates from the work list.
If those coordinates are already in our array of colored pixels, go back to step 3.
Color the pixel at the current coordinates and add the coordinates to the array of colored pixels.
Add the coordinates of each adjacent pixel whose color is the same as the starting pixel’s original color to the work list.
Return to step 3.
The "search approach" is superior because it does not only search from left to right, but in all directions.
You might look at k-means clustering.
http://docs.opencv.org/3.0-beta/modules/core/doc/clustering.html

Generate colors between red and green for an input range [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Color coding based on number
I want for a user to be able to select from a range from 1-100, where as the numbers become less than 50, the color of the area becomes darker green, and as the color becomes closer to 100, the color becomes more red.
I am trying to make it so that as the range in more towards the center, the color should be close to white (where 50 = full white).
I tried the answer from here: Generate colors between red and green for a power meter? to no avail.... 50 ends up being a muddled green...
I have the following html:
<span><span class="value">50</span><input type="range" /></span>​
And the following javascript:
$(document).on({
change: function(e) {
var self = this,
span = $(self).parent("span"),
val = parseInt(self.value);
if (val > 100) {
val = 100;
}
else if (val < 0) {
val = 0;
}
$(".value", span).text(val);
var r = Math.floor((255 * val) / 100),
g = Math.floor((255 * (100 - val)) / 100),
b = 0;
span.css({
backgroundColor: "rgb(" + r + "," + g + "," + b + ")"
});
}
}, "input[type='range']");​
Fiddle: http://jsfiddle.net/maniator/tKrM9/1/
I have tried many different combinations of r,g,b but I really cannot seem to get it right.
You're getting the muddled green because of the way you're creating your gradient in RBG space. To get a "cleaner" gradient, you can use the HSV model as mentioned in the answer of the question you linked to.
RGB gradient (top) vs HSV (bottom)
By scaling the H (hue) value between 0 (red) and 120 (green) you'll get a nice clean transition. However, at the mid point (60) you'll end up with bright yellow instead of your intended white. You can address this by modifying the S (saturation) value -- at 0 saturation, you'll end up with white (1 gives you full colour saturation.
Here's a crude example which scales the saturation from 1 to 0 and back to 1 as the input value goes from 0 to 50 to 100 - http://jsfiddle.net/xgJ2e/2/
var hue = Math.floor((100 - val) * 120 / 100); // go from green to red
var saturation = Math.abs(val - 50)/50; // fade to white as it approaches 50
p.s. Converting between colour models is easy using jquery-colors, although it's not too hard to roll your own.
I came up with this answer with some help from here, which uses an Interpolate function in which I can set the start and end colors easily.
function Interpolate(start, end, steps, count) {
var s = start,
e = end,
final = s + (((e - s) / steps) * count);
return Math.floor(final);
}
function Color(_r, _g, _b) {
var r, g, b;
var setColors = function(_r, _g, _b) {
r = _r;
g = _g;
b = _b;
};
setColors(_r, _g, _b);
this.getColors = function() {
var colors = {
r: r,
g: g,
b: b
};
return colors;
};
}
$(document).on({
change: function(e) {
var self = this,
span = $(self).parent("span"),
val = parseInt(self.value),
red = new Color(232, 9, 26),
white = new Color(255, 255, 255),
green = new Color(6, 170, 60),
start = green,
end = white;
$(".value", span).text(val);
if (val > 50) {
start = white,
end = red;
val = val % 51;
}
var startColors = start.getColors(),
endColors = end.getColors();
var r = Interpolate(startColors.r, endColors.r, 50, val);
var g = Interpolate(startColors.g, endColors.g, 50, val);
var b = Interpolate(startColors.b, endColors.b, 50, val);
span.css({
backgroundColor: "rgb(" + r + "," + g + "," + b + ")"
});
}
}, "input[type='range']");​
Fiddle: http://jsfiddle.net/maniator/tKrM9/53/
In a very hand wavy way, I think I would do it this way:
Make the range from 1-50 have maximum green (FF), and a scaled value for both red and blue ranging from 00 for red and blue at 1, all the way up to FF for red and blue at 50.
(Sample values: 1 -> 00FF00, 25 -> 7FFF7F, 50 -> FFFFFF)
Then from 51-100, keep red at FF, while scaling back blue and green so that blue and green approach 0 as you reach 100.
(Sample values: 51 -> FFFFFF, 75 -> FF7F7F, 100 -> FF0000)
This is guaranteed to give you brilliant green at 0, white at 50, and red at 100.
The areas in between may not be exactly perfect, simply because the eye interprets different color intensities differently (we're better at some colors than others), but it should get you pretty close.
I modified the code in your fiddle to the following, and it does what I describe:
$(document).on({
change: function(e) {
var self = this,
span = $(self).parent("span"),
val = parseInt(self.value);
if (val > 100) {
val = 100;
}
else if (val < 0) {
val = 0;
}
$(".value", span).text(val);
if (val <= 50)
{
r = Math.floor((255 * (val / 50))),
g = 255,
b = Math.floor((255 * (val / 50)));
}
else
{
r = 255,
g = Math.floor((100 - val) / 50 * 255),
b = Math.floor((100 - val) / 50 * 255);
}
span.css({
backgroundColor: "rgb(" + r + "," + g + "," + b + ")"
});
}
}, "input[type='range']");

Return different values from function used multiple times

I have a function which works only once. I'm sure that's because it says "return" and I haven't got any loops, etc. Could anyone help me un-noob this function? (It's all in a jQuery container, although I don't think jQuery probably has much to do with the question.)
The HSL color returned from Farbtastic is in a format like (hue,saturation,lightness). I'm adjusting the 3rd value, lightness, and that part works. All the repetitions don't work though. It makes all the new swatches the color of the first swatch.
function onColorChange(color) {
// retrieve HSL color value
var hslcolor = $.farbtastic('#main_color_picker').hsl;
// create 4 new colors of varying brightness, and variable names to save them to db.
var newcolor1 = hslcolor;
var newcolor2 = hslcolor;
var newcolor3 = hslcolor;
var newcolor4 = hslcolor;
newcolor1[2] = 0.10 * (Math.round(hslcolor[2]*10000)/10000);
newcolor2[2] = 0.85 * (Math.round(hslcolor[2]*10000)/10000);
newcolor3[2] = 1.15 * (Math.round(hslcolor[2]*10000)/10000);
newcolor4[2] = 1.50 * (Math.round(hslcolor[2]*10000)/10000);
var rgb1 = hsl2rgb(newcolor1);
var rgb2 = hsl2rgb(newcolor2);
var rgb3 = hsl2rgb(newcolor3);
var rgb4 = hsl2rgb(newcolor4);
//apply the color to swatches and show original swatch in the middle.
var firstSwatch = $('#section-main_color').find('.square1');
firstSwatch.css( 'background-color', 'rgb('+rgb1.r+','+rgb1.g+','+rgb1.b+')' );
var secondSwatch = $('#section-main_color').find('.square2');
secondSwatch.css('background-color', 'rgb('+rgb2.r+','+rgb2.g+','+rgb2.b+')');
// original color is in square 3
var fourthSwatch = $('#section-main_color').find('.square4');
fourthSwatch.css('background-color', 'rgb('+rgb3.r+','+rgb3.g+','+rgb3.b+')');
var fifthSwatch = $('#section-main_color').find('.square5');
fifthSwatch.css('background-color', 'rgb('+rgb4.r+','+rgb4.g+','+rgb4.b+')');
}
function hsl2rgb(hsl) {
var h = hsl[0], s = hsl[1], l = hsl[2];
var m1, m2, hue;
var r, g, b
h = (Math.round( 360*h )/1);
if (s == 0)
r = g = b = (l * 255);
else {
if (l <= 0.5)
m2 = l * (s + 1);
else
m2 = l + s - l * s;
m1 = l * 2 - m2;
hue = h / 360;
r = Math.round(HueToRgb(m1, m2, hue + 1/3));
g = Math.round(HueToRgb(m1, m2, hue));
b = Math.round(HueToRgb(m1, m2, hue - 1/3));
}
return {r: r, g: g, b: b};
}
For part 1 of this question, about HSL using Farbtastic in Theme-Options-Panel, see: Farbtastic convert HSL back to RGB or Hex
Followup:
If you need an actual copy of an array, I found this bit:
var newcolor = hslcolor.slice(0);
It's probably a good idea to avoid using this in most cases. I found I needed to retain the original array as-is, for use in another set of calculations, so I did my brightness on a copy.
Is this what you are looking for: http://jsfiddle.net/uttqX/6/
The reason why it didn't work, is because you were updating the same variable over and over again, because you assigned all variables to the same initial variable in the begging. So any update to any one of those variables was propagating to the initial variable (hslcolor) and then back to all the other variables.

Random Color Generator with Hue/Saturation and more controls

In this question I found a lot of interesting functions to generate random colors.
I need a random color generator that accept Hue, Saturation and Darkness range and also number of colors that we need.
Actually I can write a random color generator but I don't have good understanding of relationship between color numbers and darkness, hue and saturation of a color. I want the function export colors in an array.
I also made a jsfiddle file here for testing:
function get_random_color() {
var letters = '0123456789ABCDEF'.split('');
var color = '#';
for (var i = 0; i < 6; i++ ) {
color += letters[Math.round(Math.random() * 15)];
}
return color;
}
$.each($('div'),function(){
$(this).css('background-color', get_random_color());
});
Thanks
In CSS3 capable browsers, there's no need to transform HSL colors to RGB, since you can assign them just like that:
function rand(min, max) {
return min + Math.random() * (max - min);
}
function get_random_color() {
var h = rand(1, 360);
var s = rand(0, 100);
var l = rand(0, 100);
return 'hsl(' + h + ',' + s + '%,' + l + '%)';
}
http://jsfiddle.net/5V8mV/1/
With that algorithm, you can easily restrict the colors to bluish tones for example:
http://jsfiddle.net/DH2Bk/
In case you need an RGB conversion algorithm (for IE8, for example), you'll find it directly in the specs: http://www.w3.org/TR/css3-color/#hsl-color
HOW TO RETURN hsl.to.rgb(h, s, l):
SELECT:
l<=0.5: PUT l*(s+1) IN m2
ELSE: PUT l+s-l*s IN m2
PUT l*2-m2 IN m1
PUT hue.to.rgb(m1, m2, h+1/3) IN r
PUT hue.to.rgb(m1, m2, h ) IN g
PUT hue.to.rgb(m1, m2, h-1/3) IN b
RETURN (r, g, b)
HOW TO RETURN hue.to.rgb(m1, m2, h):
IF h<0: PUT h+1 IN h
IF h>1: PUT h-1 IN h
IF h*6<1: RETURN m1+(m2-m1)*h*6
IF h*2<1: RETURN m2
IF h*3<2: RETURN m1+(m2-m1)*(2/3-h)*6
RETURN m1
Edit:
I just found a nice JS library with more options on https://github.com/davidmerfield/randomColor

Categories