時刻取得

javascript 時計」で検索するといろんな所でソース付きで紹介されているけど、どれもsetIntervalかsetTimeoutで1000ms毎に実行するタイプのもの。この場合最大999msずれている可能性もあるのだけど、まぁjavascriptで表示するレベルのだからしょうがないのかもしれない。
先日購入したwonderflの本では、1フレーム毎に実行する関数内でSECONDS_CHANGEDやMINUTES_CHANGEDのようなイベントを発行しているという記述がされていた。
なので、これをjavascriptで作ってみたらより正確な時計ができるのではないかと思った。

イベントを発生させるのはTimelineクラスのインスタンス。そのインスタンスにaddListener()すると
第一引数で指定したイベント発生時に第二引数で指定したコールバックが実行される。
コールバックの引数は秒,分,時としてある。


var tl = new Timeline();
var now = new Date();
var format2 = function(n){ return (''+n).length == 1 ? '0'+n : n;}

↑Timelineオブジェクトの生成と1ケタの場合10の位に0を表示する関数。


var secondsElem = document.getElementById('seconds');
secondsElem.innerHTML = now.getSeconds();
tl.addListener('secondsChanged',function(seconds,minutes,hours){
  secondsElem.innerHTML = format2(seconds);
});

↑Timelineオブジェクトの'secondsChanged'イベント発生時に実行する関数の登録。
id="seconds"の要素に秒を表示する。



書き方がややこしくなるけど、secondsElemを宣言しないようにすると無名関数を使って、

tl.addListener('minutesChanged',(function(elem){
  elem.innerHTML = format2(now.getSeconds());
  return function(seconds,minutes,hours){
    elem.innerHTML = format2(seconds);
  }
})(document.getElementById('seconds')));

↑こう書ける。



同様に、分と時もやっちゃう。

tl.addListener('minutesChanged',(function(elem){
  elem.innerHTML = format2(now.getMinutes());
  return function(seconds,minutes,hours){
    elem.innerHTML = format2(minutes);
  }
})(document.getElementById('minutes')));
tl.addListener('hoursChanged',(function(elem){
  elem.innerHTML = format2(now.getHours());
  return function(seconds,minutes,hours){
    elem.innerHTML = format2(hours);
  }
})(document.getElementById('hours')));
tl.start();

↑そしてTimelineを開始するとデジタル時計が表示されることになる。



以下、Timelineクラスの定義。

Timeline = function(fps){
  this.observer = {};
  this.fps = fps;
}
Timeline.prototype.addListener = function(type,callback){
  if(!this.observer[type]){
    this.observer[type] = []
  }
  this.observer[type].push(callback);
}
Timeline.prototype.stop = function(){
  if(!this.intervaltimer){return}
  clearInterval(this.intervaltimer);
}
Timeline.prototype.start = function(){
  if(this.intervaltimer){return}
  this.intervaltimer = setInterval((function(instance){
    var sec;
    return function(){
      var d = new Date();
      var callbacks = [];
      t = d.getSeconds(); 
      if(instance.observer['flameChanged']){
        callbacks = callbacks.concat(instance.observer['flameChanged']);
      }
      if(instance.observer['secondsChanged'] && t != sec){
        callbacks = callbacks.concat(instance.observer['secondsChanged']);
        sec = t;
        if(instance.observer['minutesChanged'] && d.getSeconds() == 0){
          callbacks = callbacks.concat(instance.observer['minutesChanged']);
        }
        if(instance.observer['hoursChanged'] && d.getMinutes() == 0){
          callbacks = callbacks.concat(instance.observer['hoursChanged']);
        }
      }
      if(callbacks.length < 1){return}
      var seconds = d.getSeconds();
      var minutes = d.getMinutes();
      var hours = d.getHours();
      for(var i=0;i<callbacks.length;i++){
        callbacks[i](seconds,minutes,hours);
      }
    }
  })(this),1000 / (this.fps || 30))
}


ブラウザで無料ではじめるActionScript 3.0 ―It's a wonderfl world―

ブラウザで無料ではじめるActionScript 3.0 ―It's a wonderfl world―