読者です 読者をやめる 読者になる 読者になる

Develop and Design Note

フロントエンドなデザイナーの覚書

AngularJSを使ってタイムキーパーを作ってみよう #1-4【カウンドダウンの実装】

z前回(AngularJSを使ってタイムキーパーを作ってみよう #1-3【入力値の合計】 - Web Design Note)までの実装で、入力した数値を合計するところまでできました。
今度は、その合計値をカウントして、効果音を鳴らすところまで実装しうようと思います。

カウント用の「式」を作成

数値の合計は「{{sumTime()}}」の式で出力しているのですが、カウント用の式は別に作ります(ここでは{{countTime}})。

index.html 修正前

<p>会議時間{{sumTime()}}分</p>

index.html 修正後

<p>会議時間 {{countTime}} / {{sumTime()}} 分</p>

ちなみにですが、「{{hoge}}」のようなコードをAngularJSでは「式」と呼びます(式(Expressions) | AngularJS 1.2 日本語リファレンス | js STUDIO)。「式」には、「変数」と「関数」があり、関数には「{{hoge()}}」のように括弧を記述します。

{{countTime}}には、「数値を合計する関数」ではなく、「数値を合計する関数の返り値(合計値)」を入れるので、{{countTime}}は変数であり、()は不要になります。

アジェンダの「追加」と「削除」時に「式」を発動する

この返り値(合計値)は、「追加」ボタンを押した時と、「削除」ボタンを押した時に取得したいので、$scope.addAgendaと$scope.deleteAgendaの関数内に記述します。

script.js 修正前

// アジェンダ追加
$scope.agendas =[];
$scope.addAgenda = function() {
  $scope.agendas.push({time:$scope.settingTime});
  $scope.settingTime ='';
}
// アジェンダ削除
$scope.deleteAgenda = function(i){
  $scope.agendas.splice(i,1);
}

script.js 修正後

>|javascript
// アジェンダ追加
$scope.agendas =[];
$scope.addAgenda = function() {
$scope.agendas.push({time:$scope.settingTime});
$scope.settingTime ='';
$scope.countTime = $scope.sumTime();
}
// アジェンダ削除
$scope.deleteAgenda = function(i){
$scope.agendas.splice(i,1);
$scope.countTime = $scope.sumTime();
}
|

くどいですが、$scope.countTimeに入れるのは返り値なので、括弧付きの$scope.sumTime()を代入しています。

カウントダウン関数の作成

次に、「スタート」ボタンを押したら{{countTime}}の値をカウントし、「ストップ」を押したら{{countTime}}のカウントを止める仕組みを作ります。まずは「スタート」「ストップ」ボタン用のディレクティブを作ります(ディレクティブとは)。

index.html 修正前

<p>会議時間 {{countTime}} / {{sumTime()}} 分</p>

index.html 修正後

<p>会議時間 {{countTime}} / {{sumTime()}} 分</p>
<p>
  <button ng-click="countStart()">スタート</button>
  <button ng-click="countStop()">ストップ</button>
</p>

続いて、countStart()の関数をscript.jsに書きます。
・・・が、これがなかなかヒントになる情報が見つからず、苦労しました。検索の仕方を変えて、やっと、英語サイトですが参考にできそうなページが見つかりました。

カウントダウンには、AngularJSの$timeout関数を使うとのことで、出来上がった関数がこちら。※ここでは秒カウントにしています。

$scope.countTime = 0;
var promise;
$scope.countStart = function() {
  promise = $timeout(function() {
    console.log($scope.countTime);
    $scope.countTime--;
    $scope.countStart();
  }, 1000);
  if($scope.countTime<=0) {
    $timeout.cancel(promise);
  }
};
$scope.countStop = function() {
  $timeout.cancel(promise);
}

$scope.countTimeには、初期値として0を入れておきます。また、カウントが0になったら停止するように、if文で$timeout.cancel()を使います。

カウントが0になったら効果音を鳴らす

最後に、カウントが0になった時に、効果音が鳴るような処理を加えます。
これはけっこう簡単で、HTML5のaudio要素を使えば、以下の2行で記述できます。

var callbell = new Audio('sound/sample.mp3');
callbell.play();

「new Audio()」には、音声ファイルのパスを記述します(ここでは、'sound/bell.mp3')。「callbell.play();」は実際は「if($scope.countTime<=0) {〜}」の中に記述します。
※音声ファイルはブラウザによって対応状況が異なるので注意。今回はChromeで対応しているmp3ファイルで検証しています。


ここまでで、以下の挙動が完成しました。

  1. フォームに「半角数字」を入力して「追加」すると、連番の項目と合計値が出力される
  2. 「削除」を押すと、その項目が消え、合計値に反映される
  3. 「スタート」を押すと合計値がカウントされ、0で止まり、音がなる
  4. 「ストップ」を押すとカウントが止まる

See the Pen NPRmJw by tnk-mitsuru (@tnk-mitsuru) on CodePen.


※input要素のautofocus属性はこのブログにも効いちゃうので外してあります。
※分カウントにしたいのですが、わかりやすくするため、秒カウントにしています。

このままだと、カウント中も「スタート」ボタンが押せてしまうので、次は、それができないようにボタンの活性、非活性を制御します。→AngularJSを使ってタイムキーパーを作ってみよう #1-5【スタート・ストップの制御】 - Web Design Note