こんにちは。デバイスソフトウエア開発部の斎藤です。
エッジAIシステム開発と、iOSアプリケーション開発を担当しています。
昨年より、とあるiOSアプリ開発のプロジェクトを任せていただいており、
Googleスプレッドシート上にWBSとガントチャートを作成して、タスク進捗の管理や可視化を行っています。
プロジェクト発足当初は、インターネット上で公開されている利用可能なサンプル等を使おうと思い、
丁度良い雛形を探していたのですが、
私のプロジェクトではおそらく使わないような機能がたくさん入っていたり、色鮮やかで個人的に目が疲れそうだなと思うようなものだったり、スクリプトを少しいじったら環境壊れてしまったり…
となかなかフォーマットが決まらなかったので、まずは「見やすくて最低限の機能のものを自作して運用してみよう!」と考え、自分で作ることにしました。
本記事では、私が実際の業務で使用しているWBSとガントチャートの構成に加えて、
GAS(Google Apps Script)を用いた親タスクの再計算や、完了行の表示切替といった補助的な処理の仕組みについてご紹介いたします。
私自身、日常的にGAS開発をしているわけではなく、今回ご紹介する技術も基本的な機能と処理の紹介にはなりますが、
WBSやガントチャートはExcelで管理している方々が「GAS便利そうだしGoogleスプレッドシートで管理するのもありだな。」と感じていただけるような内容を目指して書いていきます!
なお、本記事では WBSとガントチャートを一体で管理する構成を前提として、以降は「WBSガントチャート」と呼ぶこととします。
今回作るWBSガントチャートの全体像
本記事では、iOSアプリ開発を想定したサンプルプロジェクトを題材に自作WBSガントチャートの作り方をご紹介いたします。
最初に、今日が2026年1月20日という設定で、今回作成するWBSガントチャートの完成版をお見せします。

WBS部分に関しては、タスクを作業単位で分解した一般的な構成とし、各タスクIDに対して以下の情報を持たせています。
-
タスク名
-
担当者
-
開始日
-
終了日
- 進捗率
-
ステータス(未着手 / 実装中/ 遅延中 / 完了)
ガントチャート部分に関しては、1日を1列としたシンプルな構成を採用しており、
各項目の開始日と終了日を入力することで、進捗ステータスと連動してカレンダーの色が変わるようになっています。
また、ステータス列にある「完了表示切替」をクリックすることで、完了状態の項目の表示と非表示を切り替えることができます。
全体像をご覧いただいたところで、次の章から実際の作成手順に入っていきます!
※ID~終了日列(A~E列)まではただ値を入力するだけなので、終了日列までが完成している前提で進みます。
1. ステータス列の自動判定
まずはじめに、数式をセルに埋め込んでステータス列(G列)を自動化します。
具体的には、終了日(E列)と進捗率(F列)を入力したときに「未着手 / 実装中 / 遅延中 / 完了」の4種類のステータスを自動表示できるようにします。
判定ルールはシンプルに、0%は未着手、100%は完了、それ以外は、終了日が当日より前なら遅延中、当日以降なら実装中とします。
ステータス列の先頭セル(G5)に、次の数式を入力し、下までコピーします。(ただし、今回は親タスク行には数式を入れていません。)
|
1 2 3 4 5 |
=IF(F5="", "", IF(F5>=100, "完了", IF(F5<=0, "未着手",IF(TODAY()>E5, "遅延中", "実装中") ) )) |
上記の数式を埋め込むことで、進捗率や終了日を更新するだけでステータスが自動的に切り替わるようになります。
2. ガントチャートのベース作成
続いて、H列以降にガントチャートのベースを作成します。
具体的には以下2つの作業を実施します。
1日=1列のカレンダーを作成する。
まずはガントチャートのヘッダ行に日付を並べます。(今回はサンプルのため、2026年1月の1か月分のみ作ります。)
H3 に開始日(2026/01/05)を代入し、I3 に =H3+1 を入力して右方向に日付分コピーすることで連続した日付行にします。
日付行(3行目)を選択して、メニューの [表示形式] > [数字] > [カスタム日時] > [先行ゼロなしの日] を適用することで、年月を除いた日のみを表示することができます。
また、日付の上の行(H2:AH37)に =TEXT(H4,"ddd") を入れて右方向にコピーすれば、日付に対応した曜日が表示されます。
「WBSの開始日・終了日に合わせて該当期間の色を塗り分ける」条件付き書式を設定する。
日付ヘッダが用意できたら、条件付き書式を利用して以下の手順で開始日〜終了日の範囲を塗り潰す処理を入れます。
- ガントチャート領域(H4以降)を選択し、[表示形式] > [条件付き書式] を選択する。
- 「+条件を追加」をクリックする。
- 書式ルールにて、[カスタム数式] を選択し、[値または書式]部分に下記の未完了ステータス用の数式を代入して [完了] をクリックする。
- 1-3を、残りの3つのステータス分繰り返す。
- 各ステータスの数式
-
未着手
=AND(H$4>=$D5, H$4<=$E5, $G5="未着手") -
実装中
=AND(H$4>=$D5, H$4<=$E5, $G5="実装中") -
遅延中
=AND(H$4>=$D5, H$4<=$E5, $G5="遅延中") -
完了
=AND(H$4>=$D5, H$4<=$E5, $G5="完了")
-
ついでに、同じ要領で=H$3=TODAY()という条件付き書式も設定すると、日付を参照して今日の列に色を付けることができます。
以下画像のように、5つの書式が設定されてガントチャート部分の色が塗りつぶされていれば成功です!

ここまでで、「WBS側の開始日・終了日・ステータスが変わると、ガントチャート該当範囲の色塗りが自動で更新される。」という状態が完成しました。
3. 親タスクを子タスクから再計算する
ここまでで、子タスク(例:1-1)の開始日・終了日・進捗率・ステータスを更新すれば、ガント側の色も連動して変わる状態になりました。
一方で、WBS運用をしていると 親タスクの更新が地味に面倒になります。
親タスクは入力の主体ではなく「集計結果」なので、子タスクだけ更新すれば親は自動で追従してほしい、というのが本音です。
そこで、GASスクリプトを使用して、次の3点を子タスクからまとめて再計算する機能を追加します。
-
親タスクの開始日:子タスクの開始日の最小値
-
親タスクの終了日:子タスクの終了日の最大値
-
親タスクの進捗率:子タスクの進捗率の平均
※本記事のサンプルでは、IDが 1, 1-1, 1-2 のような、親はハイフン無し、子は 親ID- で始まるフォーマットを前提としています。
Apps Scriptの追加
スプレッドシート上部メニューから [拡張機能] > [Apps Script] を開き、[ファイルを選択]をクリックして以下のコードを保存してください。
(列構成は、ID=A列、開始日=D列、終了日=E列、進捗率=F列 を前提にしています)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
/** * 設定値の共通化 */ const CONFIG = { SHEET_NAME: 'iOSアプリ_サンプル開発', ROW_START: 4, COL_ID: 1, // A列:タスクID COL_START: 4, // D列:開始日 COL_END: 5, // E列:終了日 COL_PROGRESS: 6, // F列:進捗率 COL_STATUS: 7 // G列:ステータス }; /** * 親タスクの期間と進捗率を子タスクから自動計算する */ function recalcParentTasks() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName(CONFIG.SHEET_NAME); if (!sheet) throw new Error(`対象シートが見つかりません: ${CONFIG.SHEET_NAME}`); const lastRow = sheet.getLastRow(); if (lastRow < CONFIG.ROW_START) return; const numRows = lastRow - CONFIG.ROW_START + 1; const values = sheet.getRange(CONFIG.ROW_START, 1, numRows, CONFIG.COL_STATUS).getValues(); // ID列のフォーマットチェック const dateLikeIds = []; values.forEach((row, i) => { if (row[0] instanceof Date) dateLikeIds.push(CONFIG.ROW_START + i); }); // 子タスクを親IDごとにグループ化 const groups = {}; values.forEach((row) => { const id = String(row[0] || '').trim(); if (!id || !id.includes('-')) return; const parentId = id.split('-')[0].trim(); if (!groups[parentId]) groups[parentId] = []; groups[parentId].push(row); }); // 書き込み用データの初期化と書式適用が必要な行番号の保持 const outDEF = values.map(r => [r[3], r[4], r[5]]); const parentRowsToFormat = []; // 親タスク進捗率の平均値を算出 values.forEach((row, index) => { const id = String(row[0] || '').trim(); if (!id || id.includes('-')) return; const children = groups[id]; if (!children || children.length === 0) return; let minStart = null; let maxEnd = null; let progressSum = 0; children.forEach((child) => { const start = child[3]; const end = child[4]; const progress = Number(child[5]) || 0; if (start instanceof Date && (!minStart || start < minStart)) minStart = start; if (end instanceof Date && (!maxEnd || end > maxEnd)) maxEnd = end; progressSum += progress; }); // 親タスクの値を更新 outDEF[index][0] = minStart || ''; outDEF[index][1] = maxEnd || ''; outDEF[index][2] = Math.round(progressSum / children.length); parentRowsToFormat.push(CONFIG.ROW_START + index); }); // 対象スプレッドシートへの値反映と書式設定 sheet.getRange(CONFIG.ROW_START, 4, outDEF.length, 3).setValues(outDEF); parentRowsToFormat.forEach((r) => { sheet.getRange(r, 4, 1, 2).setNumberFormat('yyyy/MM/dd').setHorizontalAlignment('center'); sheet.getRange(r, 6).setHorizontalAlignment('center'); }); SpreadsheetApp.flush(); } |
子タスクの状態を更新した後にrecalcParentTasks()を実行することで、親が自動で再計算されるようになりました。
この機能を入れることで、親タスクを「入力する場所」ではなく「集計結果」として扱えるようになり、WBS更新で考えることを減らすことができるようになります。
(ハイフンでパースする処理が若干力技感あるので時間作って修正したいとか思ったり…)
4. 完了行の表示/非表示を切り替える
プロジェクトが順調に進んでいくと、当然ですが後半は完了済みのタスクが増えていきます。
しかし、プロジェクトを管理する上では、「終わったタスクは一旦視界から外して、今終わっていない作業だけ見てスケジュール練り直したい!」みたいなことが度々発生します。
そこで、スプレッドシート上の図形(ボタンの代わり)とGASスクリプトを紐づけた、”完了表示切替ボタン”を作成しました。
先ほどと同様に Apps Script を開き、以下のコードを追加します。
※「3. 親タスクを子タスクから再計算する」のコードにて定義したCONFIGもないと動かないです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
/** * 完了済みタスクの表示・非表示を切り替える */ function toggleCompletedRows() { const ss = SpreadsheetApp.getActiveSpreadsheet(); const sheet = ss.getSheetByName(CONFIG.SHEET_NAME); if (!sheet) throw new Error(`対象シートが見つかりません: ${CONFIG.SHEET_NAME}`); const lastRow = sheet.getLastRow(); if (lastRow < CONFIG.ROW_START) return; const numRows = lastRow - CONFIG.ROW_START + 1; const props = PropertiesService.getDocumentProperties(); const mode = props.getProperty('COMPLETED_ROWS_MODE') || 'show'; if (mode === 'show') { // 非表示処理 const statuses = sheet.getRange(CONFIG.ROW_START, CONFIG.COL_STATUS, numRows, 1).getValues(); sheet.showRows(CONFIG.ROW_START, numRows); statuses.forEach((row, i) => { const status = String(row[0] || '').trim(); if (status === '完了') { sheet.hideRows(CONFIG.ROW_START + i); } }); props.setProperty('COMPLETED_ROWS_MODE', 'hide'); } else { // 再表示処理 sheet.showRows(CONFIG.ROW_START, numRows); props.setProperty('COMPLETED_ROWS_MODE', 'show'); } } |
ボタンの作成に関しては、シート上の [挿入] > [図形描画] を選択してボタンっぽい図形を追加し、
図形をクリックして [スクリプトを割り当て] にて、先ほど作成した関数toggleCompletedRows を指定します。
出来上がったボタン(画像G列の緑ボタン)をクリックすると、以下のように完了ステータス行が非表示となり、未完了のタスクだけを確認することができます。
もう一度クリックすれば再び完了ステータス行も表示されます。

ここまでの手順を実施すると、冒頭でご紹介したWBSが完成します!
おわりに
今回は、Googleスプレッドシートを使ったWBSガントチャートの作り方として、ステータス列の自動生成、ガント領域の塗り分け、親タスクの再計算、完了行の表示切替をご紹介しました。
本記事でご紹介したように、関数で日々の更新をしやすくしつつ、GASで運用時の手間を減らす機能を追加することで、シンプルかつ実務で扱いやすいWBSガントチャートを作ることができます。
プロジェクト管理のツールはさまざまありますが、Googleスプレッドシートは表計算の扱いやすさに加えて、GASで自分たちの運用に合わせて少しずつ拡張できる点に大きな価値があると感じています。
今後は、進捗バーの表現をもう少しリッチにしてイナズマ線で進捗の遅れをより直感的に見えるようにしたり、月の実績を別シートに出力する機能などを追加して、さらに使いやすい形に発展させていきたいと考えています!
続編をご期待ください。
最後に、エコモットではソフトウェアエンジニアを募集しています!
IoTやWeb開発に興味のある方はぜひ、弊社採用ページもご覧ください。





