Shorter JS Iron Chef!
The challenge: write a JS function that takes a given hex color and returns a suitably-contrasted greyscale shade, in as few lines of JS as possible.
My first pass went like this:
function contrast(c) { var av = (parseInt(c.substring(1,3),16) + parseInt(c.substring(3,5),16) + parseInt(c.substring(5,7),16)) / 3; av = (av >= 100)? av-100:av+100; return "rgb(" + av +"," + av + "," + av + ")"; }
A quick overview of what's happening here. c is the 6-character hex color (sans the "#"). The first JS statement uses the substring
function to break the hex color string into its three 2-character hex pairs, which are then passed to parseInt
to convert them to decimal values. Then we find the average by adding them and dividing by 3.
So, FF0000 (pure red) becomes FF+00+00 becomes 255+0+0 becomes 255/3 becomes 85.
The function then looks at this average and, using 100 as its "bias" point, either adds or subtracts 100 (an arbitrary value that produced the best results for our needs). The last line returns a greyscale RGB value (perfectly valid in CSS! No need to convert back to hex!).
Now the fun: I sent this off to another webdev for review and challenged him to make it even shorter. He came back with this:
function f(c,n) {return parseInt(c.substring(n,n+2),16);} function contrast(c) { var av=(f(c,1)+f(c,2)+f(c,3))/3; av+=100*(av>=100)?-1:1; return "rgb("+av+","+av+","+av+")"; }
Nice, but I pointed out that av
wasn't being calculated correctly without an additional set of parenthesis. Plus, we could shave off a few characters by replacing substring
with the shorter substr
to the same effect. I countered with this:
function f(c,n) {return parseInt(c.substr(n,2),16);} function x(c) { var av=(f(c,1)+f(c,3)+f(c,5))/3; av+=(av>=100)?-100:100; return "rgb("+av+","+av+","+av+")"; }
Of course, I hadn't thought to remove the whitespace yet :) His riposte:
function f(c,n){return parseInt(c.substr(n,2),16);} function x(c){var a=(f(c,1)+f(c,3)+f(c,5))/3;c=100; a+=(a>c)?-c:c;c=",";return "rgb("+a+c+a+c+a+")";}
Bested but not broken by his ingenious re-use of local variables, I nonetheless proclaimed victory by deleting the requirement for such a JS function from the spec, reducing the necessary code to:
Don't ever let it be said I don't think outside the box!
9 Comments:
I think there is a better way to calculate the grayscale value of a color. The human eye is much more receptive for the green component of a color than for the red and blue components, which is why the grayscale value should not be a simple mean. Instead do something like this:
gray = 0.3 * red + 0.59 * green + 0.11 * blue
function f(c,n){return parseInt(c.substr(n,2),16)}
function x(c){var a=(f(c,1)+f(c,3)+f(c,5))/3;c=100;
a+=(a>c)?-c:c;c=",";return "rgb("+a+c+a+c+a+")"}
The judges accept your entry, Ken, despite that leaving off the semicolons is Just Wrong(TM). Have you no shame? ;)
Henning's right. Here's a version with tweakable colour weightings. It's also somewhat smaller due to using integer maths instead of substrings.
function x(c){c=parseInt(c.substr(1),16); c=(c>>16)*0.3+(c>>8&255)*0.5+(c&255)*0.2;
c+=c<100?100:-100;return'rgb('+c+','+c+','+c+')';}
Guys, I should have clarified: by "suitably contrasting color" I meant "low-contrast," so we were intentionally going for something that was more difficult to see against the base color. Sorry, should have mentioned that.
Andrew wins with his crazy mathses.
Do you know eric meyers colourBlender?
I need one that produces only 'websmart' colors.
http://www.realsimplcms.com
Man there is alot of comment spam I have noticed. Is there any way to remove it from the blogs?
Good post
I wanted to recommend this blog owner to use Adsense on his Blog.
He could have made 100$/Day.
Good Blog
I wanted to show you some superb resourses on the net.
Learn to earn 90000$/Month
For which you may also see my Personal Website
Here.
and for a Personal Education Career Tools
free Study Database.
This site is for seeing the
Hifi Electronics.
And this is for
World Class Gadgets
Post a Comment
<< Home