俺の報告

RoomClipを運営するエンジニアの日報(多分)です。

日報 #37 - グラデーションをjavascriptで

肘に石灰が沈着したんだけどさ、
あれって吸収されないんだって奥さん。
これからも痛くなる可能性あるんだってやぁねぇー。
マジ腹立つねぇー。

さて、
今日はちょっとしたjavascriptツールの話。

とある理由で、365日に対応したカラーバリエーションが欲しくなりました。
HSVでグラデーションをさせれば楽との情報を聞きつけ、
それっぽいの作ってみました。

要求機能としては、

  • 日付を渡すと、16進数ウェブカラーかRGBが返ってくる。
  • 日付はその年の1月1日からの経過日数に変換される。

  • 経過日数に応じた色は365パターンあり、1月1日からグラデーションを作る

という感じ。
要は


var color365=new Hoge.fn.color365({
     date: '2014-07-20',
     format: 'web'
});


console.log(color365.make_color()); // #51a8cc

こんな感じで出力できる。
諸事情でインスタンス化しているけど別に何でもいいと思います。

で、連続で回すことも考えて、reset_optionも入れておきます。
諸々のしがらみのせいと、俺の知識不足のせいで、一目して冗長な書き方担っていると思いますが、一応動きましたのでざっくり貼り付けます。
(option周りが回りくどいのは諸事情ありです。)


(function(window){
     // Need HogeApp
     if(!window.HogeApp)
          throw new Error('There is no HogeApp');


     HogeApp.fn.color365= function(option) {
          this._init(option);
     };


     HogeApp.fn.color365.prototype = {
          _option: {
               num: 0, //priory
               date: '',
               format: 'web' // web or rgb
          },
          option: {},


          _init: function(option) {
               $.extend(this.option,option);
               this._validate_num();
               this._validate_date();
               this._validate_format();


               if (!this._validate_option())
                    throw new Error('Option Error!!');
          },
         
          _validate_option: function(){
               if (this.option.num===0 && this.option.date==='')
                    return false;
               else
                    return true;
          },


          _validate_num: function(){
               // num check
               this.option.num = parseInt(this.option.num);
               if (this.option.num >= 0 || this.option.num <= 364) {
               } else {
                    this.option.num=HogeApp.fn.color365.prototype._option.num;
               }
          },
         
          _validate_date: function(){
               // date check
               var date_obj = new Date( Date.parse(this.option.date) );
               if (date_obj=='Invalid Date')
                    this.option.date='';         
          },
         
          _validate_format: function(){
               if (this.option.format!='web' && this.option.format!='rgb')
                    this.option.format=HogeApp.fn.color365.prototype._option.format;
          },
         
          reset_option: function(option) {
               this._init(option);
          },
         
          make_color: function() {
               // set num from date
               if (this.option.date && this.option.num===0) {
                    var date_obj = new Date( Date.parse(this.option.date) );
                    var day_sec=60*60*24;
                    var year_start=new Date( Date.parse(date_obj.getFullYear()+'-01-01'));
                    this.option.num=Math.floor((date_obj.getTime()-year_start.getTime())/(day_sec*1000));              
               }
              
               var result='';
               var hsv={h:this.option.num/365, s:0.6, v:0.8};
               switch (this.option.format) {
                    case 'web': result=this.HSVtoWEB(hsv); break;
                    case 'rgb': result=this.HSVtoRGB(hsv); break;
               }
              
               return result;
          },
         
          HSVtoRGB: function (hsv) {
              var r, g, b, i, f, p, q, t;
              var h=hsv.h;
              var s=hsv.s;
              var v=hsv.v;
              if (h && s === undefined && v === undefined) {
                  s = h.s, v = h.v, h = h.h;
              }
              i = Math.floor(h * 6);
              f = h * 6 - i;
              p = v * (1 - s);
              q = v * (1 - f * s);
              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: Math.floor(r * 255),
                  g: Math.floor(g * 255),
                  b: Math.floor(b * 255)
              };
          },
         
          HSVtoWEB: function (hsv) {
               var rgb=this.HSVtoRGB(hsv);
               return '#' + rgb.r.toString(16) + rgb.g.toString(16) + rgb.b.toString(16);
          }
     };


})(window);


基本的にHSVのHをいじってグラでしているので、
グラデーションの具合が悪いと思ったら、s,vの値をちょちょっと変えればおkです。
特にHSVについて学ばずに作っても、案外きれーに出ました。

f:id:tom_rc:20140829234540p:plain

やぁ、しかし、
雨が多くていやですね。