Handy! RGB to HSL and RGB to HSV color model conversion algorithms in JavaScript

Reposted from mjijackson.com -- this is so cool that we should make sure there are more copies of this on the net, just in case. =D

Here is a set of additive color model conversion algorithms that I found published on Wikipedia and have implemented in JavaScript. It was surprisingly difficult to find these actually implemented anywhere in compact, efficient, and bug-free code, so I wrote my own. These should be easily portable to other programming languages if desired.

/**
 * Converts an RGB color value to HSL. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and l in the set [0, 1].
 *
 * @param   Number  r       The red color value
 * @param   Number  g       The green color value
 * @param   Number  b       The blue color value
 * @return  Array           The HSL representation
 */
function rgbToHsl(r, g, b){
    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];
}

/**
 * Converts an HSL color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSL_color_space.
 * Assumes h, s, and l are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  l       The lightness
 * @return  Array           The RGB representation
 */
function hslToRgb(h, s, l){
    var r, g, b;

    if(s == 0){
        r = g = b = l; // achromatic
    }else{
        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 [r * 255, g * 255, b * 255];
}

/**
 * Converts an RGB color value to HSV. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes r, g, and b are contained in the set [0, 255] and
 * returns h, s, and v in the set [0, 1].
 *
 * @param   Number  r       The red color value
 * @param   Number  g       The green color value
 * @param   Number  b       The blue color value
 * @return  Array           The HSV representation
 */
function rgbToHsv(r, g, b){
    r = r/255, g = g/255, b = b/255;
    var max = Math.max(r, g, b), min = Math.min(r, g, b);
    var h, s, v = max;

    var d = max - min;
    s = max == 0 ? 0 : d / max;

    if(max == min){
        h = 0; // achromatic
    }else{
        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, v];
}

/**
 * Converts an HSV color value to RGB. Conversion formula
 * adapted from http://en.wikipedia.org/wiki/HSV_color_space.
 * Assumes h, s, and v are contained in the set [0, 1] and
 * returns r, g, and b in the set [0, 255].
 *
 * @param   Number  h       The hue
 * @param   Number  s       The saturation
 * @param   Number  v       The value
 * @return  Array           The RGB representation
 */
function hsvToRgb(h, s, v){
    var r, g, b;

    var i = Math.floor(h * 6);
    var f = h * 6 - i;
    var p = v * (1 - s);
    var q = v * (1 - f * s);
    var t = v * (1 - (1 - f) * s);

    switch(i % 6){
        case 0: r = v, g = t, b = p; break;
        case 1: r = q, g = v, b = p; break;
        case 2: r = p, g = v, b = t; break;
        case 3: r = p, g = q, b = v; break;
        case 4: r = t, g = p, b = v; break;
        case 5: r = v, g = p, b = q; break;
    }

    return [r * 255, g * 255, b * 255];
}

 

Facebook Scribe: Open source logging platform that is used a ton

Imagine hundreds of thousands of machines across many geographical dispersed datacenters just aching to send their precious log payload to the central repository off all knowledge. Because really, when you combine all the meta data with all the events you pretty much have a complete picture of your operations. Once in the central repository logs can be scanned, indexed, summarized, aggregated, refactored, diced, data cubed, and mined for every scrap of potentially useful information.

Just imagine the log stream from all of Facebook's Apache servers alone. Brutal. My guess is these are not real-time feeds so there are no streaming query issues, but the task is still daunting. Let's say they log 10 billion messages a day. That's over 1 million messages per second!

When no off the shelf products worked for them they built their own. Scribe can be downloaded from Sourceforge. But the real action is on their wiki.

I was fascinated by this account of launching an election counter in 12 hours on Facebook's main interface, all enabled through Scribe. It was done by one engineer and just a couple of designers.

How funny is it to think that this election counter is really just script that greps of a tail of logs from Scribe?

LowPro: The essential Prototype companion library to clean up your markup

It’s 2008. There is a short list of things that should never be seen in markup from this point forward:

  • inline event handlers
  • script elements outside of your document’s head

Yes, this includes your Google Analytics tracking scripts. Put those script tags in your document’s head where they belong, and use DOM ready events to fire your tracking.

The key to modern scripting is in your markup. Make it as semantic as you can. Use class names that makes sense, more than one if necessary. Use microformats if you can. Once you do this, you will find id attributes become much less important. I tend to only use them for database objects these days- and even then it can get you into trouble.

There are a lot of third party libraries that expect to be passed an element with an id attribute to function properly. I believe parts of Script.aculo.us are like this. Do not allow these libraries seduce you into adding id attributes where you do not otherwise need them. Behavior-based JavaScript is based around the relationship between elements in the DOM. In most cases, none of the elements need id attributes. From inside behaviors, use DOM traversal methods to find other nodes you need to work with.

...

The core of LowPro revolves around two functions: Event.addBehavior and Behavior.create. Event.addBehavior can map DOM elements to anonymous functions based on CSS selectors:

Event.addBehavior({
   'div.main': function() {
     // 'this' is a reference to a matching DOM node
   },
   'div.secondary,div.tertiary': function() {
     // multiple CSS selectors can be separated by a comma
   }
 });

Event.addBehavior also supports attaching event listeners to DOM elements. Note how the CSS selector has a pseudo-class appended to it:

Event.addBehavior({
   'div.main:click': function(event) {
     // 'this' is a reference to a matching DOM node
     // 'event' it the standard Prototype-extended event object
   }
 });

Now when a user clicks on a page element that matches the selector ‘div.main’, the anonymous function is passed the standard Prototype-extended event object and executed, which is cool. 

No more inline <script> tags FTW. I've been using LowPro all this weekend and I've been quite pleased.