GASでガントチャートもどきを作ってみた



どうもはじめまして、ぺんまるです。

私は半導体系(LSIの開発および研究)で、プログラムとは無縁の生活を送っていたのですが、仕事でPythonやらimagejのマクロ言語、VBAなどに触れる機会があり、プログラムに興味を持ちはじめました。

# なぜ、GASでガントチャート？
元々は会社のPCで、VBAやPythonを使ったファイルの入出力やCSVを操作していたのですが、Googleが提供するスプレッドシートがVBAっぽいことをJavaScriptの記述でできるとのことなので、試しに触ってみるか、くらいの気持ちではじめました。
ただ、作るのものが思いつかなかったので、ガントチャートもどきを作ることにしました。
備忘録くらいに使おうと思ったので、稚拙な文章やコードでよければ、覗いていってください。

# ガントチャートの仕様
ガントチャートといっても、簡易的なもので
1. A列にタスクを記述。
1. タスクのセルに背景色を追加。
1. B列、4行以降に数字の１や背景色を追加。
1. A列2、3行目にあるタスクチェックボタンを押す。
1. A列タスクと同じ背景色を取得し、１という数字が入っているセルに同じ行のタスクの背景色が入力される。
1. 同じ月にタスクが５つ(設定値）あると、月が入力されているセルの一つ上にoverの表示がされる。

といったものです。

![スクリーンショット 2023-09-25 23.27.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556254/dd185333-3088-dd01-abf9-3f63b0f358be.png)
これが
![スクリーンショット 2023-09-25 23.51.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3556254/8c2b423e-5e53-8348-66a5-ac12b41b090f.png)
# 以下、ソースコード
```js:ガントチャートもどきGAS

function main() {
  var active_sh = SpreadsheetApp.getActiveSheet();   //アクティブシート名取得
  active_sh.getRange("B2:AD2").clearContent()   //タスクオーバーステータスのクリア
  r = task_row(active_sh);  //タスク一覧の行数を取得
  c = month_column(active_sh);    //時間軸の列数を取得
  task_color(active_sh, r, c);    //指定した値が入っているセルをタスクの背景色を参照して背景色を設定
  count_color(active_sh, r, c)    //タスクフィールドの背景色をカウント、タスク数が設定値を超えるとover表示
}

function task_row(active_sh){
  var i = 4;
  while(true){
    var row_value = active_sh.getRange(i, 1)
    if(row_value.isBlank()){
      break;
    }
    i++
  }
  return i;
}

function month_column(active_sh){
  var i = 2;
  while(true){
    var row_value = active_sh.getRange(3, i)
    if(row_value.isBlank()){
      break;
    }
    i++
  }
  return i;
}

function task_color(active_sh, r, c){
  for(var i = 4; i < r; i++){
      var bg_task_values = active_sh.getRange(i, 2, 1, c).getValues();    //タスクごとに全月の値を取得、二次元配列に格納
      var bg_task_flat = bg_task_values.flat();   //1次元配列化、なんか処理しやすそう
      var task_bg_color = active_sh.getRange(i, 1).getBackgrounds();    //タスクごとの背景色を取得、二次元配列に格納
      var bg_color_flat = task_bg_color.flat();  
      values_jadge(active_sh,bg_task_flat, bg_color_flat, i) ;  //タスクの値を格納した二次元配列を走査、1判定箇所にタスクと同じ背景色を設定
    }
}

function values_jadge(active_sh, bg_task_flat, bg_color_flat, i){
  for(var j = 0; j < bg_task_flat.length; j++){
    if(bg_task_flat[j] == 1)
      active_sh.getRange(i, j + 2).setBackground(bg_color_flat[0]);
  }
}

function count_color(active_sh, r, c){
  const over_value = 4;   
  const transpose = a => a[0].map((_, c) => a.map(r => r[c]));
  var target_color = "#ffffff";   //カラーコード取得
  var bg_color = active_sh.getRange(4, 2 , r, c).getBackgrounds();   //指定範囲の背景色取得
  var count = 0;
  var bg_color_trans = transpose(bg_color);   //二次元配列を列ごとに走査するために転置行列にする
  for(var i = 0; i < bg_color_trans.length; i++){
    for(var j = 0; j < bg_color_trans[i].length; j++){
      if(bg_color_trans[i][j].toUpperCase() != target_color.toUpperCase()){   //白い色以外の場合にカウント
        count++ ;
      }
    }
    if(count >= 4){
      active_sh.getRange(2, i + 2).setValue("over");
    }
    count = 0;
  }
}
```
文法がちょっと冗長すぎるかもしれませんが、動きます…

動くので、ヨシ！

# ChatGPTさんに添削していただいた。

>提供いただいたコードを検討しました。このGoogle Apps Scriptは、Google Sheetsの操作とデータ処理に関連しており、タスク管理やセルの背景色の設定など、便利なタスクを実行するのに役立つものです。いくつかのコメントと改善提案があります

あ、はい…よろしくお願いいたします…

>1. コメントの追加: コード内にコメントを追加することは、コードの理解とメンテナンスを助けます。すでにコメントがいくつかあるようですが、さらに詳細なコメントを追加して、コードの機能や各関数の目的を説明することをお勧めします。

なるほど、コメント…

>2. 変数の宣言: 変数を宣言する際に、`var`の代わりに`let`または`const`を使用することを検討してください。`let`は再代入が必要な場合に、`const`は再代入しない場合に使用できます。

この理由はなんなんでしょうかね…？

>3. エラーハンドリング: コード内にエラーハンドリングが欠けています。スクリプトがエラーに遭遇した場合、適切に処理することが重要です。エラーメッセージの表示やログへの記録などの対策を追加することを検討してください。

エラー用のコードの記述ですか、なるほど…(めんどくさくてしていない)

>4. マジックナンバーの削減: コード内で数値を直接使用する代わりに、意味のある定数を使用することで、コードの可読性を向上させることができます。例えば、`const over_value = 4;`のように定数を宣言し、`4`を直接使用する代わりにそれを参照するようにします。

なるほど…
const over_valueみたいにところどころ使用するっていうより、統一した方がいいんですかね…

>5. 関数のドキュメンテーション: 各関数の目的、パラメータ、返り値に関するドキュメンテーションコメントを追加することで、コードの理解が容易になります。

ふむふむ

>6. スクリプトのテスト: スクリプトをテストして、期待どおりに機能することを確認しましょう。特にエラーハンドリングやエッジケースを考慮してテストします。

えっと、動くからヨシ！はダメなんですね…

>これらの改善提案を考慮して、コードを改良することができます。また、具体的な質問や修正が必要な部分があれば、どんどんお知らせください。

ありがとうございました！！

ちょっと時間ある時にこれらを参考にもう一度コードを書いてみます