2020年1月22日に発売された「SpreadJS(スプレッドJS)」のバージョンV13Jでは多くの機能が追加されていますが、今回は、その中でも、1つのセルに複数の情報を表示する「テンプレート型セル」を作成する方法をご紹介します。
「テンプレート型セル」はシート上に作成したテンプレートの情報を参照して、単一セル上に複数のデータ表示を実現します。テンプレートには表示するテキストデータのバインド情報に加えて、数式や書式、画像なども設定可能です。
1. テンプレート型セルとは?
テンプレート型セルは、セル範囲を単一のセル型として定義したもので、通常のセル型と同じようにセルや列に設定することができます。テンプレート型セル内の各セルの値は、JSON形式のデータへのバインディングパスを指定することで設定します。
ヘルプには、テンプレート型セルの構造や利用方法についての解説のほか、動作を確認できるサンプルコードも記載しているので、ご一読いただければと思います。
テンプレート型セルでは、データの表示のみが可能で、テンプレート型セルの中のセルの値を直接編集することはできません。ただし、データ連結した場合には、他のセルを経由することでユーザー操作による値の変更が可能になります。その方法については記事の後半で解説します。
2. テンプレート型セルの実装
StackBlitz上で作成したサンプルを上に示します。実際に操作してサンプルの構造や動きをご確認いただければと思います。
それでは、テンプレート型セルを実装する方法をご紹介していきましょう。
サンプルの作成手順
テンプレート型セルの作成と設定は、次のステップで行います。
- テンプレート用シートを作成(createTemplateSheet関数)
- テンプレート型セルを作成(RangeTemplateメソッド)
- 表示用シートにテンプレート型セルを設定(setCellTypeメソッド)
- テンプレート型セルにデータを設定(setValueまたはsetDataSourceメソッド)
具体的なコード(主要部分)は次のとおりです。データの設定方法については、以下のように、テンプレート型セルにJSONデータを直接設定する方法と、データ連結する方法の2種類がありますが、サンプルではデータ連結する方法を採用しています。データ連結の方法については、後ほどご紹介します。
// テンプレート型セルの設定 var templateSheet = createTemplateSheet(); var templateCell = new GC.Spread.Sheets.CellTypes.RangeTemplate(templateSheet); renderSheet.setCellType(-1, 0, templateCell); // テンプレート型セルにJSONデータを設定 renderSheet.setValue(0, 0, data[0]); renderSheet.setValue(1, 0, data[1]); renderSheet.setValue(2, 0, data[2]); renderSheet.setValue(3, 0, data[3]);
実行すると、下のようになります。

データの作成
通常、テンプレート型セルは複数のセルで構成されているので、それぞれのセルに適切な値を設定できるように、JSON形式のデータを使います。
サンプルで使っているJSON形式の配列データを以下に示します。
// データの作成 var image1 = "https://blogs-dev.grapecity.co.jp/wp-content/uploads/hatena/20200126175013.gif"; var image2 = "https://blogs-dev.grapecity.co.jp/wp-content/uploads/hatena/20200126174949.gif"; var image3 = "https://blogs-dev.grapecity.co.jp/wp-content/uploads/hatena/20200126175001.gif"; var image4 = "https://blogs-dev.grapecity.co.jp/wp-content/uploads/hatena/20200126175013.gif"; var data = [ { "image": image1, "A": 1000, "B": 2000 }, { "image": image2, "A": 3000, "B": 4000 }, { "image": image3, "A": 5000, "B": 6000 }, { "image": image4, "A": 7000, "B": 8000 }, ];
配列変数であるdataの各要素は、次の3つのフィールドから構成されています。
- imageフィールド:画像を表示するためのパスを保持
- Aフィールド:項目Aに設定する数値を保持
- Bフィールド:項目Bに設定する数値を保持
このJSON形式データをテンプレート型セルにを設定する方法として、前述のようにセルに直接設定する方法とデータ連結する方法があります。データ連結については、次の項目で説明します。
- setValueメソッドを使った直接設定
- setDataSourceメソッドを使ったデータ連結
テンプレートの作成
今回作成するサンプルでは、テンプレート型セル内で次のような実装を行っています。
- 数式の利用
- 数値書式の設定
- 背景色と罫線の設定
- 画像の表示
項目Aと項目Bの数値は、桁区切り文字(,)を使って表示し、それらの合計をSUM関数を使って合計欄のセルに表示しています。また、これらのセルには背景色を設定し、合計欄のセルの上辺には罫線を設定しています。数値を表示しているセルの左側には画像を表示していますが、画像を表示する手法については、後ほど詳しく解説します。
画像はB2セル(B2セルからB4セルまでをセル結合)に、項目Aと項目Bの値はF2セルとF3セルに表示されます。そして、合計がF4セルに表示されます。
下図の説明文の括弧の中にある文字列は、dataの要素を構成している3つのフィールド(image、A、B)を表しています。

このテンプレートは、StackBlitz上のサンプルのcreateTemplateSheet関数で作成しているので、詳細についてはサンプルをご覧ください。
テンプレート内のセルとJSONデータのdata内のフィールドは、createTemplateSheet関数の中のsetBindingPathメソッドで連結しています。連結の結果、テンプレート内のB2セルはdataのimageフィールドに対応付けられ、F2セルとF3セルはそれぞれAとBの各フィールドに対応付けられます。
templateSheet.setBindingPath(1, 1, "image"); templateSheet.setBindingPath(1, 5, "A"); templateSheet.setBindingPath(2, 5, "B");
実際のサンプルでは、見栄えを考慮してグリッド線を非表示にしていますが、上図では、テンプレートを構成するセルが分かるようにグリッド線を表示しています。
テンプレート用シートの扱い
サンプルでは、テンプレート用シートについて説明するために、Templateシートをコントロールに追加していますが、テンプレート用シートをコントロールのシートコレクションに追加することは必須ではありません。
例えば、ヘルプのサンプルコードでは、シートをRangeTemplateメソッドの引数に渡してテンプレート型セルを作成しているだけで、コントロールには追加していません。
また、今回はテンプレート用のシートをcreateTemplateSheet関数を使ってコードで生成していますが、製品デモのように、SpreadJSデザイナで作成したシートをJSONデータとして保存し、それをfromJSONメソッドを使って読み込むことも可能です。
ユーザー操作による値の変更
テンプレート型セル内の値をユーザーが変更できるようにするために、A列に加えてB列とC列にもJSONデータを連結します。こうすることで、B列とC列でセルの値を変更したときにA列のテンプレート型セルの項目Aと項目Bの値が変更されるようになります。
データ連結するためのコードは次のとおりです。
// データの連結 renderSheet.bindColumn(0, { displayName: "テンプレート型セル", value: function (item) { return item; }}); renderSheet.bindColumn(1, { displayName: "項目A", name: "A" }); renderSheet.bindColumn(2, { displayName: "項目B", name: "B" }); renderSheet.autoGenerateColumns = false; renderSheet.setDataSource(data);
bindColumnメソッドは、JSONデータのフィールドと表示用シートの列を連結します。
表示用シートの第2列と第3列はnameを使ってAとBの各フィールドに連結できますが、問題は第1列です。この列にはimageとAとBの3つのフィールドを連結する必要がありますが、nameにはそのような機能はありません。そこで、ヘルプで解説しているfunction型の値を保持するvalueを使うことになります。
第1列を連結するbindColumnメソッドの引数にあるfunction (item)のitemには、imageとAとBの各フィールドに対応したすべての値が含まれていて、function(item)によってそれらを関数の内部に取り込みます。取り込んだitemは関数内のreturnメソッドによって戻り値としてセルのvalueに渡されます。
valueに渡されたitem内の3つの値は、テンプレート内の各セルに設定されているバインディングパス(image、A、B)に応じて、該当するセルに表示されます。

また、itemの中身がどのようなものかは、次のようなコードでも確認できます。
// nameを使ってフィールドを連結する一般的な記述方法 renderSheet.bindColumn(1, { displayName: "項目A", name: "A" }); renderSheet.bindColumn(2, { displayName: "項目B", name: "B" }); // valueにfunction型を設定することでも連結が可能 // ただし、参照のみが可能で、設定すること(値の変更)はできません renderSheet.bindColumn(1, { displayName: "項目A", value: function (item) { return item["A"]; }}); renderSheet.bindColumn(2, { displayName: "項目B", value: function (item) { return item["B"]; }});
データ連結の結果、下のようになります。

StackBlitz上のサンプルで、例えば項目A列の数値を変更すると、対応するテンプレート型セルの項目Aの値が変更されますので、ご確認ください。
3. 画像を表示するための工夫
ヘルプで解説しているように、画像はセルのbackgroundImageプロパティを使って設定しますが、セルに表示する画像を動的に変更するには、画像のファイルパスをセルのvalueプロパティに設定する必要があります。
サンプルでは、カスタムセル型を作成してvalueプロパティの値をbackgroundImageプロパティに渡すことで、この動作を実現しています。
カスタムセル型の詳細については、ヘルプをご参照ください。
// カスタムセル型(画像表示用)の作成 function ImageCellType() { this.typeName = "ImageCellType"; } ImageCellType.prototype = new GC.Spread.Sheets.CellTypes.Base(); ImageCellType.prototype.paint = function (ctx, value, x, y, w, h, style, context) { style.backgroundImage = value; style.backgroundImageLayout = GC.Spread.Sheets.ImageLayout.center; style.foreColor = "white"; value = ""; GC.Spread.Sheets.CellTypes.Text.prototype.paint.apply(this, arguments); };
上記の中の次の2行は、ImageCellType型セルに画像のファイルパス文字列が表示されないようにするためのものです。
style.foreColor = "white"; value = "";
4. おわりに
製品Webサイトでは、SpreadJS V13Jのデモアプリケーションを公開しています。Webアプリケーションの開発に役立つ豊富な機能について、その外観や動作だけでなく、実装されているコードの内容も確認できますので、以下より是非お試しください。
グレープシティは2020年2月13日から開催される、ITエンジニアの祭典「Developers Summit 2020(デブサミ2020)」に協賛しています。
当日はスポンサーブースにて、今回ご紹介した「SpreadJS」をはじめ、標準ツールに最適なUIセットの「Wijmo(ウィジモ)」、日本仕様の入力をきめ細かくサポートする入力コントロールセットの「InputManJS(インプットマンJS)」、モダンなWebアプリケーションに帳票機能を組み込める「ActiveReportsJS(アクティブレポートJS)」を展示しておりますので、イベントにお越しの際はお気軽にお立ち寄りください!
