GoogleSpreadSheetで疑似ストップウォッチを使おう！


# 概要
GoogleSpreadSheetにおいて
GoogleAppsScriptを用いて実装した疑似ストップウォッチを紹介
###できること
カウントの同期
途中経過時間の記録

###できないこと
カウント表示のリアルタイム自動更新
ストップウォッチの一時停止(未対応)

##こんな人のために
#### 複数人でストップウォッチを共有したい方
- グループで行うプレゼン 
- 音響等の裏方がいる規模のイベント

ストップウォッチの表示は同期されるので、スタッフ一人が操作すれば発表者・司会者はしゃべりに集中できる

####スプレッドシートとストップウォッチの機能を一つの画面で済ませたい方
- イベント司会者
- プレゼンテーター

スプレッドシートに原稿を書けばタブレットの一画面で完結でき、コンパクト

##サンプル
以下のリンクからスプレッドシートを開き、コピーを作成してすぐに利用することができます

https://docs.google.com/spreadsheets/d/1RRxuoL400Wh4AD9P1TtDnm6Oq0b0Y850rF3mVEUNJDI/edit?usp=sharing


##実装
細かい調整をしたい方のために、各ボタンに対応するスクリプトを記載しておきます

###セッティング

```javascript:
const SHEET_ID = /*導入したいスプレッドシートのID*/;
const DISPLAY_SHEET = /*ストップウォッチを表示したいシート名*/;
const RECORD_SHEET = /*結果を保存したいシート名*/;

//ストップウォッチの開始時刻を保存するセル、ストップウォッチを表示するセル
const TIMER_NOTATION = {
  "total":{"start": "I1", "display":"A2"},
  "partial":{"start": "I2", "display":"B2"}
};
// ラベル用セルの開始セル
const LABEL_NOTATION = {
  "start": "A3"
};
```

###「開始」ボタン
```javascript
// DBの開始時間を更新して画面更新
function timerStart() {
  const now = Date.now();
  const ss = SpreadsheetApp.openById(SHEET_ID);
  var sheet = ss.getSheetByName(DISPLAY_SHEET);

  sheet.getRange(TIMER_NOTATION.total.start).setValue(now);
  sheet.getRange(TIMER_NOTATION.partial.start).setValue(now);
  refreshCountView(sheet, now);

  sheet = ss.getSheetByName(RECORD_SHEET);
  sheet.appendRow([now]);
}

// DBの情報から合計時間と部分時間の表示を更新
function refreshCountView(sheet, now){
  if(sheet.getSheetName()!=DISPLAY_SHEET){
    Logger.log("Invarid Sheet");
    return
  }
  for(const timer in TIMER_NOTATION){
    const start = sheet.getRange(TIMER_NOTATION[timer].start).getValue();
    const record = getRecord(start, now);
    sheet.getRange(TIMER_NOTATION[timer].display).setValue(record);
  }
}

// 経過時間を計算
function getRecord(start, end){
  var time = end - start;
  var second = Math.floor(time%(60*1000)/1000);
  if(second < 10) second = "0" + second;
  return Math.floor(time/(60*1000)) + ":" + second;
}
```
###「画面更新」ボタン

```javascript

// 画面更新のみ
function timerReflesh() {
  const now = Date.now();
  const sheet = SpreadsheetApp.openById(SHEET_ID).getSheetByName(DISPLAY_SHEET);
  refreshCountView(sheet, now);
}
```

###「次へ」ボタン

```javascript
// 実行時刻をDBに反映してから画面更新、記録
function timerRecord() {
  const now = Date.now();
  const ss = SpreadsheetApp.openById(SHEET_ID);
  var sheet = ss.getSheetByName(DISPLAY_SHEET);
  
  sheet.getRange(TIMER_NOTATION.partial.start).setValue(now);
  refreshCountView(sheet, now);

  const record = sheet.getRange(TIMER_NOTATION.total.display).getValue();
  sheet = ss.getSheetByName(RECORD_SHEET);
  const row = sheet.getLastRow();
  const column = sheet.getRange(row,sheet.getMaxColumns()).getNextDataCell(SpreadsheetApp.Direction.PREVIOUS).getColumn()+1;
  sheet.getRange(row,column).setValue(record); 
}
```


###「ラベルを更新」ボタン

```javascript
// DISPLAY_SHEETからラベルと想定時間を受け取ってRECORD_SHEETの表示更新
function timerSet() {
  const ss = SpreadsheetApp.openById(SHEET_ID);
  var sheet = ss.getSheetByName(DISPLAY_SHEET);
  var range = sheet.getRange(LABEL_NOTATION.start);
  var label = sheet.getRange(range.getRow(),range.getColumn()+2);
  var labels = ["開始",label.getValue()];
  var labelsBackground = [, label.getBackground()];
  var times = ["0:00"];

  range = range.getNextDataCell(SpreadsheetApp.Direction.DOWN);
  while(range.getRow()<1000){
    var labelRange = sheet.getRange(range.getRow(),range.getColumn()+2);
    labels.push(labelRange.getValue());
    labelsBackground.push(labelRange.getBackground());
    times.push(formatTime(range.getValue()));
    range = range.getNextDataCell(SpreadsheetApp.Direction.DOWN);
  }
  
  sheet = ss.getSheetByName(RECORD_SHEET);
  for(var i=0;i<labels.length;i++){
    sheet.getRange(1,i+1).setValue(labels[i]);
    sheet.getRange(1,i+1).setBackground(labelsBackground[i]);
    sheet.getRange(2,i+1).setValue(times[i]);
  }
}


// spreadsheetの時間型の値を分数:秒数表示に変える
function formatTime(date) {
  return Utilities.formatDate(date, "Asia/Tokyo", "HH:mm");
}
```

##筆者情報
プログラミング学習開始から6カ月
GASでの自作は今回のストップウォッチが初めて


##参考にさせていただいた記事

https://somachob.com/stopwatch-spreadsheet/

その他、GASにおけるspreadsheetの基本的な扱い方についての諸記事