RGB

ビット演算を使ったコードサンプルなはずなのに arguments は透過的でなくて使いにくいとか zero padding は標準で提供すべきとか思ってしまった。あと RGB <--> HSV 変換式のわかりづらさは異常。コーディングしたもののうごかねー。

で、これがあると何がうれしいかって rgb それぞれと #xxxxxx 的な表現を指定する type="text" な input 要素や css で color / background-color をいじる JavaScript コードを組み合わせるとよくある色指定ツールができるはず。というか作ってしまった -> http://www012.upp.so-net.ne.jp/legio/color.html http://www012.upp.so-net.ne.jp/legio/colortest/ 。おいィ !? センスが微塵も感じられないんだが ?

// for RGB
function RGB() {
    this.initialize.apply(this, arguments);
}
RGB.prototype = {
    initialize: function () {
        this.errmsg = 'you can assign Array that have more than 3 vlaues or string look like RGB value';

        if (arguments.length === 1) this.set(arguments[0]);
        else if (arguments.length === 3) this.set(arguments[0], arguments[1], arguments[2]);
        else throw new Error(this.errmsg);
    },

    range: function (n) {
        if (0 <= n && n < 256) return n;
        else throw new Error('each RGB value must be integer and lesser than 256');
    },

    set: function () {
        if (arguments.length === 3) {
            this.r = this.range(arguments[0]);
            this.g = this.range(arguments[1]);
            this.b = this.range(arguments[2]);
            return;
        }
        else if (arguments.length !== 1) throw new Error(this.errmsg);

        var rgb = arguments[0];
        switch (typeof rgb) {
            case 'object':
                if (rgb instanceof Array && rgb.length >= 3) {
                    this.r = this.range(rgb[0]);
                    this.g = this.range(rgb[1]);
                    this.b = this.range(rgb[2]);
                    return;
                }
                else throw new Error(this.errmsg);
                break;
            case 'number':
                {
                    rgb = rgb.toString(16);
                    var l = rgb.length, t = [];

                    if (l <= 3)      rgb = this.zeroPadding(rgb, 3);
                    else if (l <= 6) rgb = this.zeroPadding(rgb, 6);
                    else            throw new Error(this.errmsg);
                }
            case 'string':
                if (/^#?([0-f]{3})$/.test(rgb)) {
                    var n = parseInt(RegExp.$1, 16);
                    this.r = (n & 0xf00) >> 4; // >> 8 << 4
                    this.g = (n & 0x0f0);      // >> 4 << 4
                    this.b = (n & 0x00f) << 4; //      << 4
                    return;
                }
                if (/^#?([0-f]{6})$/.test(rgb)) {
                    var n = parseInt(RegExp.$1, 16);
                    this.r = (n & 0xff0000) >> 16;
                    this.g = (n & 0x00ff00) >> 8;
                    this.b = n & 0x0000ff;
                    return;
                }
                throw new Error(this.errmsg);
            default:
                throw new Error(this.errmsg);
        }

    },

    toNumber: function () (this.r << 16) | (this.g << 8) | this.b,
    toString: function () '#' + this.zeroPadding(this.toNumber().toString(16), 6),
    get red()   this.r,
    get green() this.g,
    get blue()  this.b,
    zeroPadding: function (str, digit) {
        var z = [], l = str.length;
        for (var i=0, m=digit-l ; i<m ; ++i) z.push('0');
        return z.join('') + str;
    },

    // refer: http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
    // not work!!
    toHSV: function () {
        var max = Math.max(this.r, this.g, this.b);
        var min = Math.min(this.r, this.g, this.b);
        if (max === 0) return new HSV(0, 0, 0);

        var sub = max - min;
        var v = max;
        var s = Math.ceil(255 * sub / max);
        var h;
        if (sub) {
            switch (max) {
                case this.r:
                    h = 60 * ((this.b - this.g) / sub);
                    break;
                case this.g:
                    h = 60 * (2 + (this.r - this.b) / sub);
                    break;
                case this.b:
                    h = 60 * (4 + (this.g - this.r) / sub);
                    break;
                default:
                    throw new Error('naiwa-');
            }
            h = Math.ceil(h);
            while (h < 0) h += 360;
        }
        else {
            h = 0;
        }

        return new HSV(h, s, v);
    },
};

// for HSV
function HSV() {
    this.initialize.apply(this, arguments);
}
HSV.prototype = {
    initialize: function (h, s, v) {
        this.set(h, s, v);
    },

    set: function (h, s, v) {
        this.h = h;
        this.s = s;
        this.v = v;
    },

    // refer: http://ja.wikipedia.org/wiki/HSV%E8%89%B2%E7%A9%BA%E9%96%93
    // not work!!
    toRGB: function () {
        if (this.s === 0) return new RGB(0, 0 ,0);
        var ht = this.h / 60;
        var st = this.s / 255;

        var hi = Math.ceil(ht) % 6;
        var f = ht - hi;
        var m = Math.ceil(this.v * (1 - st));
        var n = Math.ceil(this.v * (1 - st * f));
        var k = Math.ceil(this.v * (1 - st * (1 - f)));
        if (m > 255) m = 255;
        if (n > 255) n = 255;
        if (k > 255) k = 255;
        if (m < 0) m = 0;
        if (n < 0) n = 0;
        if (k < 0) k = 0;

        liberator.log([m,n,k], 0);
        switch (hi) {
            case 0:
                return new RGB(this.v, k, m);
            case 1:
                return new RGB(n, this.v, m);
            case 2:
                return new RGB(m, this.v, k);
            case 3:
                return new RGB(m, n, this.v);
            case 4:
                return new RGB(k, m, this.v);
            case 5:
                return new RGB(this.v, m, n);
        }
    },
    get hue()        this.h,
    get saturation() this.s,
    get brightness() this.v,
};