2月から就職することになりました。

個人事業主としてフリーランスプログラマとしてやってきましたが、
それだと食えなくなってきたので就職することにしました。

2年いかないくらいしかできなかったけど、
営業するのは、いい経験になりました。

また、通勤電車に乗ることを考えたら少し不安がありますが、
早く慣れたらいいと思います。

そしてノロへ・・・

1日に太郎が退院しました。
退院直後は、元気だったけど夕方からまたもや顔色が悪くご飯が食べられなくなり、
私も熱が出てきて吐き気が。。。

2日は太郎はずっとぐったり&下痢、どうやら入院中にノロかロタのウイルス性腸炎をもらったようです。
私は38度超の熱がでて、食欲はなく、全身が筋肉痛のような痛みで、横になると気持ち悪くて吐きそうで、
起きると痛くてほんとしんどかったです。

3日になってやっと私は熱、筋肉痛、吐き気がすっとひき、食用も戻りましたが、今度は土石流のような下痢です。
太郎もまだまだ、下痢が続いていて毎度漏れてしまうので大変。ロタのときがそうだったんだけど、全部洗って
消毒もしないと花子にうつると悲惨なので。。

年末年始でごみが出せないので大量のおむつごみが溜まっています。

私も、下痢以外は人並みになってきたので少し活動ができそうです。

では、今年もよろしくお願いいたします。

しばらく熱が続いていて風邪かと思いきや、ヘルペス口内炎ということで入院になりました。
昨日は、何も食べられなくなって顔も青白くなってたし。ロタの時みたいに泊まり込みに行ってきます。

ちょっとまえにはてブで上がっていた、ドミニオン買いました。
夫婦ではまっています。
子どもらを寝かしつけた後はドミニまくっています。
しばらくは、これでいけそうです。
拡張が2つほどでているので、いずれ買ってしまいそうな勢いです。

明日から3日ほど帰省します。
花子とおじいは初対面なんで、楽しみにしていることでしょう。おばあはGWに遊びにきたからね。
花子は飛行機初体験だね。
太郎は初めてのときは、気圧の変化に耐えきれず、うんちがでてしまったけど、大丈夫かな?
後は、すげーひさしぶりに高校のときのつれと会う予定。

色相環とjQuery UIの勉強

色に関する勉強

色の属性(色相・明度・彩度)とか色相環について、
特にRGBとの関連についてよくわからなかったので勉強してみました。


「読んだのはWeb配色デザインのセオリー」っていう本です。
そういえば色ってものについてちゃんと考えたことがなかったので、
原色の種類と明るさと鮮やかさという軸で考えると人間の感覚的に
理解・説明しやすいということを体系的に理解できたのはよかったです。


RGBの考え方に最初に触れた時にすごくわかりやすいやん、
と思っていたのは、あくまで原色だけで、中間色を使う必要がほとんどなかったため
あまり深く考えていなかったということでした。
あと、光の3原色っていうのは学校でならったからかなー。
色相とかは習ったのかな?よく覚えてない。

じゃ、色相環でも作るか

でまあ、だいたい分かったところで、せっかくなのでプログラマとしては
色相環を作るプログラムでも作ってみようかというわけです。
んで、最近jQueryを勉強しているので、JavaScriptでかいてみようかなと。


とりあえずは座標変換ですな、HSV色空間からRGB色空間(またその逆)の。
ちょちょっとググってみれば、ありますがな、変換方法が。wikipedia:HSV色空間


こいつを参考にColorパッケージを実装して、jQuery UIを使って、なんかいけてる
感じのUIをのっけたりして楽しくjQueryも勉強してしまおう的なノリです。

まとめ

最終的には、プログラムで色相環を生成して、明度と彩度はスライダを使って
指定できるようにして、特定の色を選ぶとそれをメインカラーとして、サブカラー
とアクセントカラーを並べるダイアログが開くようにしてみました。
jQuery UIすっげー楽しーやんってことで意味もなく色相環をDraggableにしてます。


結果的には、作ることが楽しかったのでいいんですが、メインカラーの選択から
他の色を選定するアルゴリズムが微妙で、この辺が自動化できたらいいなと
思います。(できるのか?)むしろ、絵師の意見を取り入れたいところです。
一応、本のスプリットコンプリメンタリー配色、ドミナントカラー配色っぽいことを
やってはみましたが。。。

プログラムソースについて

さて、肝心のソースですが、舞台となるHTMLはこんな感じ。

x.html
----
<html>
<head>
<title>color</test>
<link rel="stylesheet" href="../jq-css/jquery-ui-1.7.2.custom.css" />
<script type="text/javascript" src="../jquery-1.3.2.js"></script>
<script type="text/javascript" src="../jq-ui/ui/ui.core.js"></script>
<script type="text/javascript" src="../jq-ui/ui/ui.slider.js"></script>
<script type="text/javascript" src="../jq-ui/ui/ui.draggable.js"></script>
<script type="text/javascript" src="../jq-ui/ui/ui.resizable.js"></script>
<script type="text/javascript" src="../jq-ui/ui/ui.dialog.js"></script>
<script type="text/javascript" src="./Color.js"></script>
<script type="text/javascript" src="./main.js"></script>
</head>
<body>
<h1>Color</h1>
<div id="ctrl">
<div id="val">Value:<span class="text"></span><div class="slider"></div></div>
<div id="sat">Saturation:<span class="text"></span><div class="slider"></div></div>
</div>
<div id="colors">
</div>
<div id="dialog" title="Color Scheme Example">
</div>
</body>
</html>

jQuery関係のスクリプトは適当にもってきてください。
控えめなJavaScriptを目指すとHTMLはシンプルですね。要素はほとんど動的に作ってます。
Color.jsは上述のColorパッケージで、HSVクラス?とRGBクラス?を収めています。
main.jsはアプリケーション本体です。


では、Colorパッケージがこんな感じ。

Color.js
----
var Color = {};
(function () {
    function HSV(h,s,v) {
        if ( s === undefined ) { s = 1; }
        if ( v === undefined ) { v = 1; }
        this.hue = this.normHue(h);
        this.saturation = this.norm(s);
        this.value = this.norm(v);
    }
    function RGB(r,g,b) {
        if ( typeof r == "number" ) {
            if ( g === undefined ) { g = r; }
            if ( b === undefined ) { b = r; }
        }
        else if ( typeof r == "string" ) {
            var res = r.match("^#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$");
            r = parseInt(res[1],16)/255;
            g = parseInt(res[2],16)/255;
            b = parseInt(res[3],16)/255;
        }
        this.red = this.norm(r);
        this.green = this.norm(g);
        this.blue = this.norm(b);
    }
    function _norm(v) {
        if ( v > 1 ) { return 1; }
        else if ( v < 0 ) { return 0; }
        return v;
    }
    function _dec2hexstr(v) {
        var ret = Math.floor(v * 255).toString(16);
        if ( ret.length == 1 ) {
            ret = '0' + ret;
        }
        return ret;
    }

    var ns = Color;
    ns.HSV = HSV;
    ns.RGB = RGB;

    ns.HSV.prototype.normHue = function(h) {
        while( h < 0 ) {
            h += 360;
        }
        h = h - Math.floor(h/360)*360;
        return h;
    };
    ns.HSV.prototype.norm = _norm;
    ns.HSV.prototype.toRGB = function() {
        var ret;
        if ( this.saturation == 0 ) {
            ret = new Color.RGB(this.value);
            return ret;
        }
        var H_60,Hi,f,p,q,t;
        H_60 = Math.floor(this.hue/60);
        Hi = (H_60)%6;
        f = this.hue/60 - H_60;
        p = this.value * ( 1 - this.saturation );
        q = this.value * ( 1 - f * this.saturation );
        t = this.value * ( 1 - (1-f) * this.saturation );
        switch(Hi) {
            case 0:
                ret = new Color.RGB(this.value,t,p);
                break;
            case 1:
                ret = new Color.RGB(q,this.value,p);
                break;
            case 2:
                ret = new Color.RGB(p,this.value,t);
                break;
            case 3:
                ret = new Color.RGB(p,q,this.value);
                break;
            case 4:
                ret = new Color.RGB(t,p,this.value);
                break;
            case 5:
                ret = new Color.RGB(this.value,p,q);
                break;
        }
        return ret;
    };
    ns.HSV.prototype.setValue = function(v) {
        this.value = this.norm(v);
    };
    ns.HSV.prototype.addValue = function(v) {
        this.value = this.norm(this.value + v);
    };
    ns.HSV.prototype.setSaturation = function(v) {
        this.saturation = this.norm(v);
    };
    ns.HSV.prototype.addSaturation = function(v) {
        this.saturation = this.norm(this.saturation + v);
    };
    ns.HSV.prototype.addHue = function(v) {
        this.hue = this.normHue(this.hue + v);
    };
    ns.HSV.prototype.clone = function() {
        return new Color.HSV(this.hue,this.saturation,this.value);
    };

    ns.RGB.prototype.norm = _norm;
    ns.RGB.prototype.toString = function() {
        var r = _dec2hexstr(this.red);
        var g = _dec2hexstr(this.green);
        var b = _dec2hexstr(this.blue);
        return '#' + r + g + b;
    };
    ns.RGB.prototype.toHSV = function() {
        var ret,max,min,proc;
        if ( this.red > this.green ) {
            if ( this.green > this.blue ) {
                max = this.red;
                min = this.blue;
                proc = 0;
            }
            else if ( this.red > this.blue ) {
                max = this.red;
                min = this.green;
                proc = 0;
            }
            else {
                max = this.blue;
                min = this.green;
                proc = 2;
            }
        }
        else { // this.green >= this.red
            if ( this.red > this.blue ) {
                max = this.green;
                min = this.blue;
                proc = 1;
            }
            else if ( this.green > this.blue ) {
                max = this.green;
                min = this.red;
                proc = 1;
            }
            else {
                max = this.blue;
                min = this.red;
                proc = 2;
            }
        }
        var v = max,sat,hue;
        if ( v == 0 ) {
            ret = new Color.HSV(0,0,0);
            return ret;
        }
        sat = (max - min)/max;
        if ( sat == 0 ) {
            ret = new Color.HSV(0,0,v);
            return ret;
        }
        switch(proc) {
            case 0:
                hue = 60 * (this.green - this.blue)/(max-min);
                break;
            case 1:
                hue = 60 * (this.blue - this.red)/(max-min) + 120;
                break;
            case 2:
                hue = 60 * (this.red - this.green)/(max-min) + 240;
                break;
        }
        ret = new Color.HSV(hue,sat,v);
        return ret;
    };
})();


そんで、メインになるアプリケーション部分はこんな感じです。

main.js
----
jQuery.noConflict();
jQuery(document).ready(function(){
    var colors = 24;
    var r = 100;
    var dr = 2*Math.PI/colors;
    var l = 2*r*Math.sin(dr/2);
    var p_2 = Math.PI/2;
    var cont = jQuery('#colors')
            .css('width', (2*r)+'px')
            .css('height', (2*r)+'px')
            .css('position','relative')
            .css('top', (r/2)+'px')
            .css('left', (r/2)+'px')
            .draggable();
    for(var i=0;i<colors;i++) {
        var t = dr*i;
        var d = 180*t/Math.PI;
        var x = Math.cos(t - p_2)*(r+l) + r - l/2;
        var y = Math.sin(t - p_2)*(r+l) + r - l/2;
        var hsv = new Color.HSV(d);
        var rgb = hsv.toRGB().toString();
        jQuery.data(
            jQuery('<div></div>')
                .addClass('color')
                .css('background-color',rgb)
                .css('width', l+'px')
                .css('height', l+'px')
                .css('position','absolute')
                .css('top', y+'px')
                .css('left', x+'px')
                .attr('title',rgb)
                .click(function(){
                    var obj = jQuery.data(this,"hsv_obj");
                    jQuery("#dialog")
                        .text( '' )
                        .append( color_scheme1(obj) )
                        .append( color_scheme2(obj) )
                        .append( color_scheme3(obj) )
                        .append( color_scheme4(obj) )
                        .append( color_scheme5(obj) )
                        .dialog('open');
                })
                .appendTo(cont).get(0),
            "hsv_obj", hsv
        );
    }
    jQuery('#val > .text').text( 1.0 );
    jQuery('#sat > .text').text( 1.0 );
    jQuery('#ctrl .slider')
        .css('width','200px')
        .slider({
            max : 1.0 ,
            step : 0.1 ,
            value : 1.0 ,
            change : function(event,ui) {
                jQuery(jQuery(ui.handle).parents().get(1))
                    .find('.text').text( ui.value );
                change_colors();
            } ,
        });
    jQuery("#dialog").dialog({
        autoOpen: false
    });
});

function change_colors() {
    var v = parseFloat(jQuery('#val > .text').text());
    var s = parseFloat(jQuery('#sat > .text').text());
    jQuery('.color').each(function(i){
        var hsv = jQuery.data(this,"hsv_obj");
        hsv.setValue(v);
        hsv.setSaturation(s);
        var rgb = hsv.toRGB().toString();
        jQuery(this).css('background-color',rgb).attr('title',rgb);
    });
}

function _mk_color_bar(base,sub,accent) {
    return jQuery('<div></div>')
        .css('position', 'relative')
        .css('width', '100px')
        .css('height', '15px')
        .css('padding', '5px')
        .append(
            jQuery('<div></div>')
                .css('float', 'left')
                .css('background-color',base.toString())
                .css('width', '70px')
                .css('height', '15px')
        ).append(
            jQuery('<div></div>')
                .css('float', 'left')
                .css('background-color',accent.toString())
                .css('width', '5px')
                .css('height', '15px')
        ).append(
            jQuery('<div></div>')
                .css('float', 'left')
                .css('background-color',sub.toString())
                .css('width', '25px')
                .css('height', '15px')
        )
}

function _mk_colors1(org,delta_hue_sub,delta_hue_acc) {
    var obj1 = org.clone();
    var obj2 = org.clone();
    obj1.addHue(delta_hue_sub);
    obj2.addHue(delta_hue_acc);
    return { "sub" : obj1 , "acc" : obj2 };
}

function _mk_colors2(org,opt) {
    var val_threshold = (opt && opt.val_threshold !== "undefined" ) ? opt.val_threshold : 0.5;
    var sat_threshold = (opt && opt.sat_threshold === "undefined" ) ? opt.sat_threshold : 0.5;
    var delta_acc_val = (opt && opt.delta_acc_val === "undefined" ) ? opt.delta_acc_val : 0.3;
    var delta_acc_sat = (opt && opt.delta_acc_sat === "undefined" ) ? opt.delta_acc_sat : 0.2;
    var delta_sub_val = (opt && opt.delta_sub_val === "undefined" ) ? opt.delta_sub_val : 0.0;
    var delta_sub_sat = (opt && opt.delta_sub_sat === "undefined" ) ? opt.delta_sub_sat : 0.3;
    var sub = org.clone();
    var acc = org.clone();
    if ( org.value >= val_threshold ) {
        acc.addValue(-delta_acc_val);
        sub.addValue(-delta_sub_val);
    }
    else {
        acc.addValue(delta_acc_val);
        sub.addValue(delta_sub_val);
    }
    if ( org.saturation >= sat_threshold ) {
        acc.addSaturation(-delta_acc_sat);
        sub.addSaturation(-delta_sub_sat);
    }
    else {
        acc.addSaturation(delta_acc_sat);
        sub.addSaturation(delta_sub_sat);
    }
    return { "acc" : acc, "sub" : sub };
}

function color_scheme1(org) {
    var pair = _mk_colors1(org,30,180);
    return _mk_color_bar(org.toRGB(),pair.sub.toRGB(),pair.acc.toRGB())
}

function color_scheme2(org) {
    var pair = _mk_colors1(org,-30,180);
    return _mk_color_bar(org.toRGB(),pair.sub.toRGB(),pair.acc.toRGB())
}

function color_scheme3(org) {
    var pair = _mk_colors2(org);
    return _mk_color_bar(org.toRGB(),pair.sub.toRGB(),pair.acc.toRGB());
}

function color_scheme4(org) {
    var pair = _mk_colors2(org);
    return _mk_color_bar(org.toRGB(),pair.acc.toRGB(),pair.sub.toRGB());
}

function color_scheme5(org) {
    var pair = _mk_colors2(org,{"delta_acc_val":0.2,"delta_acc_sat":0.3,"delta_sub_val":0.3,"delta_sub_sat":0.0});
    return _mk_color_bar(org.toRGB(),pair.sub.toRGB(),pair.acc.toRGB());
}

まあね、main.jsは正直もうちょっと何とかしたい。でも息抜きってことでこれでいいっしょ。