必要な環境
本記事のサンプルコードは、以下の環境で動作を確認しています。
-
macOS Sonoma
- SpreadJS(17.1.5)
- Visual Studio Code 1.95.1(Live Server 5.7.9)
- Google Chrome 130.0
対象読者
- Webアプリにガントチャート機能を実装したい方
- Webアプリでプロジェクトの工程管理を行いたい方
- SpreadJSのスプレッドシート以外の機能を知りたい方
作成するガントチャート
本記事では、図1のガントチャートを作成します。このガントシートは、架空のプロジェクトにおける進捗を表示します。ワークシートを2つ作成し、ガントシートのデータ形式であるレベル階層形式と子階層形式で、それぞれガントチャートを表示します。また、先行タスクと達成率の表示、ガントチャートのスタイルのカスタマイズも実施します。
開発環境と事前準備
最初に、開発環境と必要なファイルを準備しておきます。
開発環境
開発環境としては、VSCode(Visual Studio Code)をインストールしておきます。そのあと、VSCodeにHTTPサーバを提供する拡張機能Live Serverをインストールします。本記事のサンプルではHTTPサーバは必須ではありませんが、ホットリロードなどが利用できるので、インストールしておくと便利です。
SpreadJSモジュールの入手と配置
アプリの拠点となる作業フォルダを作成しておきます。ここでは、spreadjs_ganttとしました。この作業フォルダに、JavaScriptファイルの置き場所であるscriptsフォルダと、CSSファイルの置き場所であるcssフォルダをさらに作成しておきます。
SpreadJSのトライアル版、または製品版を入手して配置します。トライアル版は公式ページからダウンロードできます。Zipファイルを解凍してできるSpreadJS_Release/SpreadJS-Libs/SpreadJS以下にあるフォルダから、以下のファイルを作業フォルダにコピーします。scriptsフォルダ配下のファイルはscriptsフォルダへ、cssフォルダ配下のファイルはcssフォルダへ、それぞれコピーしてください。
なお、cssフォルダにはCSSファイルが7種類収納されています。ライト系とダーク系などからお好みのデザインのものを選択してください。ここではオーソドックスなexcel2013white.17.1.5.cssとしました。
scripts/gc.spread.sheets.all.17.1.5.min.js
scripts/plugins/gc.spread.sheets.tablesheet.17.1.5.min.js
scripts/plugins/gc.spread.sheets.ganttsheet.17.1.5.min.js
scripts/resources/ja/gc.spread.sheets.resources.ja.17.1.5.min.js
css/gc.spread.sheets.excel2013white.17.1.5.css
SpreadJSのバージョン
執筆にはSpreadJS 17.1.5を使用しました。入手したバージョンが異なる場合には、index.htmlファイルの<link>タグと<script>タグにおいて、ファイル名中のバージョンの表記を実際のバージョンに合わせてください。
カスタムCSSファイルの準備
カスタムCSSは、ガントシートをHTMLにどのように表示させるかを決めるためのものです。以下のリストの内容で作成し、cssフォルダに配置します。基本的にページ領域いっぱいを使用して表示します。
body, html { /* ガントシートをページいっぱいに表示 */ padding: 0; margin: 0; width: 100%; height: 100%; position: relative; overflow: hidden; } .sample, .spreadsheets{ /* 親要素に対して100%の領域で表示 */ width: 100%; height: 100%; }
レベル階層形式ガントシートの組み込み
SpreadJSモジュールとカスタムCSSの準備ができたら、HTMLファイルなどを作成してガントシートを組み込んでいきましょう。
HTMLファイルの準備
アプリの起点であるindex.htmlファイルを、以下のリストの内容で作業フォルダに作成します。(1)のCSSファイルの読み込みパスは、実際に使うCSSファイルに合わせてください。(2)以降のJavaScriptファイルの読み込みも同様です。(3)がガントシートアプリとデータの読み込みで、(4)がスプレッドシートが展開される要素です。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <link rel="stylesheet" type="text/css" href="css/gc.spread.sheets.excel2013white.17.1.5.css"> (1) <script src="scripts/gc.spread.sheets.all.17.1.5.min.js"></script> (2) <script src="scripts/gc.spread.sheets.tablesheet.17.1.5.min.js"></script> <script src="scripts/gc.spread.sheets.ganttsheet.17.1.5.min.js"></script> <script src="scripts/gc.spread.sheets.resources.ja.17.1.5.min.js"></script> <script src="scripts/app.js"></script> (3) <script src="scripts/data.js"></script> <link rel="stylesheet" type="text/css" href="css/styles.css"> </head> <body style="height: 100%; font-size: 14px;"> <div class="sample"> <div id="ss" class="spreadsheets"></div> (4) </div> </body> </html>
JavaScriptファイルの準備
ガントシートを表示するためのapp.jsファイルを、scriptsフォルダに作成します。まずは、ガントシート作成処理以前の部分を、以下のリストの内容で作成します。
// (1)ライセンスキーと言語の設定 //GC.Spread.Sheets.LicenseKey = "ここにSpreadJSのライセンスキーを設定します"; GC.Spread.Common.CultureManager.culture("ja-jp"); // (2)ページ読み込み後にワークブックを初期化する window.onload = () => { const spread = new GC.Spread.Sheets.Workbook(document.getElementById("ss"), { sheetCount: 0 }); initSpread(spread); // スプレッドシートの初期化 }; // (3)スプレッドシートの初期化関数 function initSpread(spread) { spread.suspendPaint(); // 描画の停止 initGanttSheetLevel(spread); // レベル階層形式ガントシートの初期化 spread.resumePaint(); // 描画の再開 }
(1)のライセンスキーの設定では、各自が入手したライセンスキーを記述してください。ライセンスキーを設定せずにトライアル版として利用する場合には、1行目をコメントアウトしてください。この場合、実行時にトライアル版であることを示すメッセージが表示されます。
(2)は、ページ読み込み終了時のイベントハンドラ(onload)で、ワークブックを初期化しています。表示領域となるHTML要素(id="ss")を指定してWorkbookオブジェクトを生成します。sheetCountプロパティをゼロに設定しているのは、初期状態でシートを作成しないことを意味します。
(3)は、ワークブックの生成後に呼び出されるinitSpread関数です。ここでは、ガントシート描画中の画面のちらつきを抑えるために、suspendPaintメソッドで描画を保留し、initGanttSheetLevel関数の呼び出し後に、resumePaintメソッドで描画を再開しています。
続いて、レベル階層形式のガントシートの初期化関数です。
// ガントシートの初期化関数(レベル階層) function initGanttSheetLevel(spread) { // (1)データマネージャの取得とテーブルの作成 const dataManager = spread.dataManager(); const table = dataManager.addTable("linkTable", { data: getDataLevel(), // バインドするデータの指定 batch: true, // 同期モードにバッチを指定 schema: { // スキーマの指定 hierarchy: { type: "Level", // レベル階層形式の指定 column: "level" // レベルはlevelプロパティで指定 } } }); // (2)ガントシートの追加と外見の設定 const ganttSheet = spread.addSheetTab(0, "レベル階層プロジェクト", GC.Spread.Sheets.SheetType.ganttSheet); // ガントシートのシートを追加 //ganttSheet.project.startDate = new Date("2024/11/13 09:00"); // 開始日時(省略時は現在日時) ganttSheet.gridlines.bottomTierColumn.lineType = // 縦線をダッシュに GC.Spread.Sheets.GanttSheet.GanttGridlineType.dashed; ganttSheet.gridlines.ganttRows = { // 横線は細線のグレー lineType: GC.Spread.Sheets.GanttSheet.GanttGridlineType.thin, lineColor: "lightgray", } // (3)ビューの作成 const view = table.addView("linkView", [ { value: "taskNumber", caption: "NO.", width: 70 }, { value: "name", caption: "タスク名", width: 260 }, { value: "pic", caption: "担当責任者", width: 120 }, { value: "duration", caption: "予定工数", width: 90 } ]); // (4)データの読み込みとビューのバインド view.fetch().then(() => { ganttSheet.bindGanttView(view); }).then(() => { // (5)タイムスケールの設定 const tierMode = GC.Spread.Sheets.GanttSheet.TimescaleTierMode.topMiddleBottom; // 上段、中段、下段の全てを指定 ganttSheet.project.timescale.tierMode = tierMode; ganttSheet.project.timescale.topTier.unit = GC.Spread.Sheets.GanttSheet.TimescaleUnit.months; // 上部は月表示 ganttSheet.project.timescale.topTier.formatter = "yyyy年mm月"; // 月表示のフォーマット }); }
initGanttSheetLevel関数は、ガントシートを初期化します。
(1)以降は、データ管理をつかさどるデータマネージャオブジェクトをdataManagerで取得し、addTableメソッドでテーブルを追加しています。テーブルは、名前("linkTable")とオプションで構成されます。以下は、それぞれのプロパティの意味です。
- data:バインドするデータを表します。ここでは後述するgetDataLevel関数から返される配列を渡しています。
- batch:リモートデータベースの更新方法をBatchモードに指定します。通信効率の向上のために、スプレッドシートの変更を保存し、一度に更新するようになります。サンプルには更新処理はありませんが、ガントシートでは、batchプロパティをtrueに設定する必要があります。
- schema:データの構成を指定します。レベル階層形式では、hierarchy.typeプロパティに"Level"を、columnプロパティにはレベルを指定するデータソース上のプロパティ(この場合は"level")を指定します。
(2)以降は、addSheetTabメソッドでシートタブを追加し、外見を設定しています。addSheetTabメソッドの引数は、前から「位置(ここでは0=先頭)」「名前(ここでは"レベル階層プロジェクト")」を意味します。gridlinesプロパティは、名前の通り、グリッド線の見た目を設定します。なお、サンプルではコメントアウトしていますが、project.startDateプロパティを設定すると、プロジェクトの開始日を指定できます。省略時は、現在日時となります。
(3)以降では、テーブルに対応するビューを作成します。ここで、個々の列情報を指定できます。それぞれのプロパティの意味は、以下の通りです。
- value:列名
- caption:キャプション
- width:表示幅
- visible:列を表示するか
表示したい列を追加する場合には、ここに列情報を追加していきます。
あとは、(4)のfetchメソッドでデータを読み込み、bindGanttViewメソッドでガントシートにバインドするだけです。なお、必須ではありませんが、(5)のように、タイムスケールの表示をカスタマイズすることも可能です。なお、タイムスケールとはガントチャート部の列ヘッダーです。最大3段階の表示が可能で、月、週、日などの期間を表示できます。
データソースの準備
レベル階層形式のデータソースとして、data.jsファイルをscriptsフォルダ配下に以下のリストの内容で作成します。全体は配布サンプルを参照してください。
function getDataLevel() { const Gantt_Data = [ { "id": 1, "level": 0, (1) "taskNumber": 1, "name": "要件定義", "duration": "6 days", "pic": "正門 恵子" }, …略 ] return Gantt_Data; }
データソースにおけるポイントは(1)のlevelプロパティで、レベル階層形式においてレベルを指定することです。スキーマ設定におけるhierarchy.columnプロパティに指定した名前である必要があります。値には、レベルを整数値で指定します。数値に応じた階層に項目が配置されます。
実行確認
ここまで作成すると、実行確認できます。VSCodeのエクスプローラーからindex.htmlファイルを右クリックして、メニューから[Open with Live Server]をクリックしてサーバを起動します。図2のようにガントシートが表示されれば、ここまでの手順はうまくいっています。以降は、コードの修正で自動的にページが更新されます。
ガントシートの活用例
ここからは、先行タスクの設定やタスク達成度の表示、スタイルのカスタマイズなど、ガントシートの活用についてのトピックスをいくつか紹介します。
先行タスクの設定
ここまでのサンプルでは、複数のタスクがあってもそれらは同時進行していました。しかし、現実的なプロジェクトでは、通常は先行タスクがあって、その終了を待って次のタスクが始まるのが一般的です。このように、別のタスクの終了に依存する形で次のタスクを開始させたい場合には、predecessorsプロパティをタスクデータに追加し、ビューにも項目を追加します。
predecessorsプロパティの値は文字列で、通常は先行タスクのidを指定します(複数ある場合にはカンマ区切り)。先行タスクがない場合には、空文字列を指定します。ここには、先行タスクなしの場合とありの場合の例を示すので、全体は配布サンプルを参照してください。
function getDataLevel() { const Gantt_Data = [ …略… { "id": 2, "level": 1, "taskNumber": 2, "name": "社内関係者ヒアリング", "duration": "1 day", "predecessors": "", // 先行タスクなし "pic": "正門 恵子" }, { "id": 3, "level": 1, "taskNumber": 3, "name": "要求事項の細分化", "duration": "3 days", "predecessors": "2", // 先行タスクはid=2のタスク "pic": "青木 俊之" }, …略…
対応するビューは、以下のとおりです。項目は必要ですが、列として見える必要はないのでvisibleプロパティをfalseとしています。
const view = table.addView("linkView", [ …略… { value: "duration", caption: "予定工数", width: 90 }, { value: "predecessors", caption: "先行タスク", width: 120, visible: false }, ]); // 追加
タスク達成度の表示
それぞれのタスクには、達成度をパーセント表示することができます。タスクにcompleteプロパティを追加し、達成度を0~1.0までの数値で指定します。なお、completeプロパティを追加できるのは子要素を持たない要素のみです(追加しても無視されます)。親要素には、子要素の達成度を合計したものが反映されます。
…略… { "id": 8, "level": 2, "taskNumber": 8, "name": "帳票設計", "duration": "2 days", "predecessors": "", "pic": "成宮 真紀", "complete": 0.5, // 達成度は50パーセント } …略…
ビューは、以下のリストのようになります。
const view = table.addView("linkView", [ …略… { value: "predecessors", caption: "先行タスク", width: 120, visible: false }, { value: "complete", caption: "進捗率", width: 70 }, // 追加 ]);
タスクの表示スタイルのカスタマイズ
タスクの表示スタイル(シェイプや色など)は、タスクバーの各要素につき、スタイルルール(GC.Spread.Sheets.GanttSheet.TaskbarStyleRuleName)という形で決められています。各要素のスタイルルールは以下が組み込みで用意されています。
スタイルルール | 概要 |
---|---|
durationOnly | 期間 |
durationOnlyMilestone | 期間(マイルストーン) |
finishOnly | タスク終了 |
finishOnlyMilestone | タスク終了(マイルストーン) |
manualMilestone | マイルストーン、手動スケジュール |
manualProgress | 進捗、手動スケジュール |
manualSummary | サマリー、手動スケジュール |
manualTask | タスク、手動スケジュール |
milestone | マイルストーン |
progress | 進捗 |
projectSummary | プロジェクトのサマリー |
startOnly | タスク開始 |
startOnlyMilestone | タスク開始(マイルストーン) |
summary | サマリータスク |
task | タスク |
カスタマイズの基本は、上記いずれかのスタイルルールのオブジェクトを取得し、シェイプや色のプロパティを変更してオブジェクトを書き戻すという流れです。なお、以下の行に挙げるプロパティが指定できます。シェイプは矩形(rectangle)、円(circle)、矢印(arrow)などから選択できます。タイプは実線(solid)、破線(dashed)、枠線(framed)から選択できます。テキストに指定できるのは、プロパティ名と列の数式です。
プロパティ | 型 | 概要 |
---|---|---|
startShape | GC.Spread.Sheets.GanttSheet.TaskbarStartShape | 開始部のシェイプ形状 |
startType | GC.Spread.Sheets.GanttSheet.TaskbarStartType | 開始部のタイプ |
startColor | string | 開始部のカラー |
middleShape | GC.Spread.Sheets.GanttSheet.TaskbarMiddleShape | 中間部のシェイプ |
middlePattern | GC.Spread.Sheets.GanttSheet.TaskbarFillPattern | 中間部の埋めパターン |
middleColor | string | 中間部のカラー |
endShape | GC.Spread.Sheets.GanttSheet.TaskbarEndShape | 終了部のシェイプ |
endType | GC.Spread.Sheets.GanttSheet.TaskbarEndType | 終了部のタイプ |
endColor | string | 終了部のカラー |
topText | string | 上部に表示するテキスト |
rightText | string | 右に表示するテキスト |
bottomText | string | 下部に表示するテキスト |
leftText | string | 左に表示するテキスト |
insideText | string | 内部に表示するテキスト |
以下のリストは、taskスタイルルールを取得し、startShapeとendShape(始点と終点のシェイプ)に"circle"(円)を設定し、さらにカラー(startColorとendColor)に中間部の色(middleColor)を設定しています。最後に、taskbarStyleオブジェクトに書き戻している点に注意してください。この設定により、タスク工程のバーの両端が丸くなります(図4)。
let taskRule = ganttSheet.project.taskStyleRules.getRule("task"); let taskStyle = taskRule.style.taskbarStyle; taskStyle.startShape = "circle"; taskStyle.endShape = "circle"; taskStyle.startColor = taskStyle.middleColor; taskStyle.endColor = taskStyle.middleColor; taskRule.style.taskbarStyle = taskStyle;
子階層形式ガントシートの組み込み
ここまではレベル階層形式(levelプロパティで階層を表す形式)を使った例を紹介しましたが、最後に子階層形式での指定方法についても紹介します。基本的なコードはレベル階層形式(initGanttSheetLevel関数)と同じなので、異なるポイントのみを紹介します。
子階層形式のデータは、以下のリストのように表します。簡略化のためにnameプロパティとchildrenプロパティのみ掲載しているので、全容は配布サンプルを参照してください。見た目に階層構造が分かりやすいのが子階層形式の特徴です。
function getDataChildren() { const Gantt_Data = [ …略… { "name": "設計", "children": [ // スキーマで指定する子階層のキー { "name": "基本設計", "children": [ { "name": "画面設計", }, …略…
app.jsファイルでは、childrenプロパティが子階層のデータであることを示すために、スキーマの設定において、hierarchy.typeプロパティを"ChildrenPath"に、columnプロパティを"children"に設定します。
…略… const table = dataManager.addTable("childTable", { data: getDataChildren(), // 子階層形式のデータを指定 batch: true, schema: { hierarchy: { type: "ChildrenPath", // 子階層形式であることを示す column: "children" // データ中のプロパティ名を指定する } } });
initGanttSheetChildren関数の呼び出しを、initSpread関数に追加します。すると子階層形式のシートが追加され、子階層形式のデータで表示されます(図6)。シートが複数になったので、どのシートを表示するかをシート左下の4本線のボタンで選択できます。
まとめ
本記事では、SpreadJS V17Jの新機能であるガントシート機能でガントチャートをWebアプリに組み込み、複数の階層フォーマットの使い方や、先行タスク、達成度の表示、スタイルのカスタマイズなどの事例を紹介しました。