SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

高機能JavaScriptグリッド部品「SpreadJS」の活用(AD)

「SpreadJS」のスプレッドシートをVue.js+ASP.NET Coreで活用してデータ集計するWebページを作ろう

  • X ポスト
  • このエントリーをはてなブックマークに追加

 本記事では、ExcelライクなスプレッドシートをWebページに表示できるグレープシティのJavaScriptライブラリ「SpreadJS」を、JavaScriptのフレームワークVue.jsと組み合わせて利用する例を紹介します。サーバー側はマイクロソフトのASP.NET CoreでWeb APIを作成して、Web APIから取得したデータをSpreadJSで表示させます。

  • X ポスト
  • このエントリーをはてなブックマークに追加

はじめに

 SpreadJSは、ExcelライクなスプレッドシートをWebページに表示できる、グレープシティのJavaScriptライブラリです。2022年10月に「V15.2J」バージョンが公開されました。

図1 SpreadJSの製品ページ(https://www.grapecity.co.jp/developer/spreadjs)
図1 SpreadJSの製品ページ

 SpreadJSは単独の利用以外に、JavaScriptライブラリやフレームワークと組み合わせて利用することもでき、過去記事ではAngularと組み合わせる方法(過去記事1)、Reactと組み合わせる方法(過去記事2)を紹介してきました。

 さらに今回はSpreadJSにVue.jsを組み合わせてWebページを実装し、ASP.NET Coreで実装したWeb APIからデータを取得してスプレッドシートに表示する例を紹介します。スプレッドシートならではの機能として、計算式を設定して最大値などのデータ集計を行う方法も説明します。

対象読者

  • ExcelライクなスプレッドシートをWebページで実現したい方
  • ASP.NET CoreのWeb API実装を体験したい方
  • Vue.jsほか、さまざまな環境で統一的に使えるスプレッドシートライブラリが必要な方

必要な環境

 本記事のサンプルコードは、以下の環境で動作を確認しています。

  • Windows 10 64bit版
  • SpreadJS 15.2.4
  • Vue.js 3.2.41
  • Microsoft Visual Studio Community 2022 17.3.6
  • Node.js 16.18.0 64bit版
  • Microsoft Edge 106.0.1370.52

 サンプルコードに含まれるソリューションファイル(*.sln)をVisual Studio 2022で開くことで、ソースコードの確認や実行が行えます。

Visual StudioでVue.js+ASP.NET Coreのプロジェクト環境を作る

 今回のサンプルで利用する「クライアント側にVue.js、サーバー側にASP.NET Core」という環境のプロジェクトテンプレートは、Visual Studio 2022に標準では存在しないため、クライアント側にAngularを使用するプロジェクトテンプレートを元に、クライアント側だけをVue.jsに差し換えて実行させます(図2)。

図2 Visual Studio 2022でVue.jsを実行できるようにしたプロジェクトの実行結果(P001VueOnVS)
図2 Visual Studio 2022でVue.jsを実行できるようにしたプロジェクトの実行結果(P001VueOnVS)

 詳細な手順は、類似環境でグレープシティのJavaScriptライブラリWijmoを動作させた過去記事を参照してください。ここでは大まかな流れだけを示します。

 Visual Studioで「Angular での ASP.NET Core」のプロジェクトテンプレートでプロジェクトを作成後、クライアント側(Angular)のソースコードが格納されているClientAppフォルダーを別の場所に退避します。その後、Visual Studioプロジェクト内の<プロジェクト名>フォルダーで「npm init vue@latest」コマンドを実行してVue.jsのプロジェクトを生成します。プロジェクト名は元のVisual Studioプロジェクトと同じにします。プロジェクト生成後、フォルダー名をClientAppに変更します。

図3 Vue.jsプロジェクトに置き換えられたClientAppフォルダー(P001VueOnVS)
図3 Vue.jsプロジェクトに置き換えられたClientAppフォルダー(P001VueOnVS)

 Vue.jsに置き換えられたClientAppフォルダーのソースコードは、そのままではVisual Studioから実行できないため、Vue.jsプロジェクトの設定ファイル(vite.config.js、package.json)を編集して実行できるようにします。編集内容の詳細は過去記事を参照してください。

過去1カ月の気温をスプレッドシートに表示するWebページを作る

 本記事でSpreadJSに表示する題材は、過去1カ月の最高気温・最低気温です。これらをサーバー側のWeb APIで提供し、それをSpreadJSで表示するように実装していきます(図4)。このサンプルでは最高気温・最低気温そのもの以外に、SpreadJSのスプレッドシート機能を利用して、クライアント側で最大値・最小値・平均値を集計して表示します。

図4 SpreadJSで気温のデータを表示するサンプル(P002VueSpreadJS)
図4 SpreadJSで気温のデータを表示するサンプル(P002VueSpreadJS)

 表示するデータは、気象庁の「過去の気象データ・ダウンロード」から、2022年9月の大阪のデータをCSVファイルでダウンロードして利用します。ダウンロードしたCSVファイルは事前に内容の整形とヘッダー付加を行い、図5の状態にしておきます。

図5 Web APIで提供する気温のデータ(P002VueSpreadJS/P002VueSpreadJS/data.csv)
図5 Web APIで提供する気温のデータ(P002VueSpreadJS/P002VueSpreadJS/data.csv)

 以下では、このデータをWebページ上に表示する実装を、サーバー側(ASP.NET Coreで実装するWeb API)とクライアント側(Vue.js、SpreadJS)とに分けて説明していきます。

サーバー側の実装

 サーバー側には、図5のCSVファイルを読みだして、戻り値として返却するWeb APIを実装します。このサーバー側実装内容は、過去記事1過去記事2のサンプルと同じものです。

 サーバー側でCSVファイルを読み出すため、NuGet パッケージ マネージャーでCSVファイル用ライブラリの「CsvHelper」パッケージをインストール後、Web APIのクラスが配置されるControllers配下に、Web API処理をリスト1の通り実装します。

[リスト1]Web APIの実装(P002VueSpreadJS/P002VueSpreadJS/Controllers/TemperatureController.cs)
// 気温Web APIのコントローラー ...(1)
[Route("api/[controller]")]
[ApiController]
public class TemperatureController : ControllerBase
{
    // GET時の処理 ...(2)
    [HttpGet]
    public object Get()
    {
        // CSVファイルを読み込むReaderを生成 ...(3)
        using (var reader = new StreamReader("data.csv"))
        {
            // CSV内容を読み込むReaderを生成 ...(4)
            using (var csv = new CsvReader(reader, 
                new CsvConfiguration(CultureInfo.InvariantCulture)))
            {
                // CSVファイルからレコードを取得して返却 ...(5)
                var records = csv.GetRecords<TemperatureData>();
                return records.ToList();
            }
        }
    }
}

 クラスに付与した(1)の[Route("api/[controller]")]、[ApiController]属性により、「api/Temperature」というパスに対応するWeb APIであることを指定します。Getメソッド(2)に付与した[HttpGet]属性は、HTTP GET時の処理であることを表します。

 Getメソッド内では(3)および(4)でCSV内容を読み込むCsvReaderを生成し、(5)で内容をレコードのリストにして返却します。ASP.NET Coreの処理により、リスト内容がJSON文字列に変換されてAPIの戻り値として返却されます。

クライアント側の実装

 クライアント側の実装は、Vue.jsプロジェクトにSpreadJSを追加する方法が公式ドキュメントで案内されているので、基本的にその手順に従って進めます。最初にClientAppフォルダーでリスト2のコマンドを実行して、プロジェクトにSpreadJSを追加します。コマンド末尾の「@15.2.4」は、インストールするパッケージのバージョン指定です。

[リスト2]SpreadJSパッケージをプロジェクトに追加するコマンド
npm install @grapecity/spread-sheets-vue@15.2.4 # ...Vue.js用モジュール
npm install @grapecity/spread-sheets-resources-ja@15.2.4 #...日本語リソース

 Webページ表示時、最初に実行されるmain.jsに、リスト3の通り実装します。SpreadJSのスプレッドシート、ワークシート、列にそれぞれ対応するGcSpreadSheets、GcWorkSheet、GcColumnを(1)でインポートします。Vue.jsの初期化処理(2)で得られるVue.jsアプリのインスタンスappに対して、(3)のcomponentメソッドで、SpreadJSのコンポーネントにそれぞれ「gc-spread-sheets」「gc-worksheet」「gc-column」という名前を指定します。その後(4)でVue.jsアプリをマウント(表示)します。

[リスト3]SpreadJSのコンポーネントを登録する実装(P002VueSpreadJS/P002VueSpreadJS/ClientApp/src/main.js)
// SpreadJSコンポーネントをインポート ...(1)
import { GcSpreadSheets, GcWorksheet, GcColumn }
  from '@grapecity/spread-sheets-vue'
// Vue.jsの初期化処理 ...(2)
const app = createApp(App);
// SpreadJSのコンポーネント指定 ...(3)
app.component('gc-spread-sheets', GcSpreadSheets);
app.component('gc-worksheet', GcWorksheet);
app.component('gc-column', GcColumn);
// Vue.jsアプリをマウント ...(4)
app.mount('#app');

 ページ全体に対応するAppコンポーネント(App.vue)に、SpreadJSのコンポーネントを設定していきます。画面の表示内容を表す<template>部はリスト4の通りです。

[リスト4]SpreadJSを表示する<template>部(P002VueSpreadJS/P002VueSpreadJS/ClientApp/src/App.vue)
<template>
  <div id="spread-host">
    <gc-spread-sheets :hostStyle="hostStyle"
      @workbookInitialized="workbookInit"> <!--(1)-->
      <gc-worksheet name="気温" :dataSource="temperatures"> <!--(2)-->
        <gc-column headerText="日時" dataField="date" width="200"> <!--(3)-->
        </gc-column>
        <gc-column headerText="最高気温" dataField="maxTemperature" width="200">
        </gc-column>
        <gc-column headerText="最低気温" dataField="minTemperature" width="200">
        </gc-column>
      </gc-worksheet>
    </gc-spread-sheets>
  </div>
</template>

 まず、スプレッドシート全体を表す<gc-spread-sheets>コンポーネント(1)を記述します。スプレッドシートの表示スタイルを表すhostStyleには後述するサイズ指定(hostStyle変数)を反映します。また、workbookInitializedはスプレッドシート初期化時のイベントハンドラーメソッドで、後ほど実装するworkbookInitメソッドを指定します。

 <gc-spread-sheets>内に、1つのワークシートに対応した<gc-worksheet>コンポーネント(2)を記述します。nameはワークシートの名前、dataSourceは後述するデータ変数temperaturesを指定します。

 <gc-worksheet>内には(3)の通り、データを表示する列に対応した<gc-column>コンポーネントを、列の数だけ記述します。dataFieldはデータの属性名、headerTextはヘッダー部の文言、widthは列の幅指定です。

 一方、画面の処理内容は<script>部に、リスト5の通り実装します。

[リスト5]SpreadJSを表示する<script>部(P002VueSpreadJS/P002VueSpreadJS/ClientApp/src/App.vue)
<script setup>
import { nextTick, ref } from 'vue'
// SpreadJSをインポート ...(1)
import '@grapecity/spread-sheets/styles/gc.spread.sheets.excel2016darkGray.css'
import * as GC from '@grapecity/spread-sheets'
import '@grapecity/spread-sheets-resources-ja'
// カルチャ設定 ...(2)
GC.Spread.Common.CultureManager.culture('ja-jp')
// ライセンスキー設定 ...(3)
GC.Spread.Sheets.LicenseKey = '<ライセンスキー>'
// スプレッドシートの表示サイズ ...(4)
const hostStyle = { width: '100%', height: '500px' }
// 受信した気温データを格納する変数 ...(5)
let temperatures = ref([])
// ワークブック初期化後の処理 ...(6)
const workbookInit = (args) => {
  // Web APIからデータ取得 ...(7)
  fetch('/api/Temperature')
    .then(res => res.json())
    .then(result => {
      // データを変数に保持 ...(8)
      temperatures.value = result
      // ワークシートを装飾 ...(9)
      nextTick(() => {
        decorateWorksheet(args) // Webページにデータが反映されてから処理
      })
    })
}
(略)
</script>

 (1)でSpreadJSのCSSとJavaScriptをインポートします。(2)はカルチャの設定で、日本語(ja-jp)を設定します。(3)はライセンスキーの設定です。ライセンスキーを設定しない場合は、トライアル版である旨の透かしがスプレッドシートに表示されます。

 コンポーネント内で、スプレッドシートの表示サイズを表すhostStyle(4)を記述します。また、スプレッドシートに表示する温度データを格納する配列temperatures(5)は、変数をリアクティブにして、データの変更を画面に反映させるため、Vue.jsのComposition APIが提供するrefメソッドを利用して記述します。初期値は空の配列です。

 ワークブック初期化後に実行されるworkbookInitメソッド(6)では、(7)のfetchメソッドでWeb API(/api/Temperature)からデータを取得して、(8)でtemperatures.valueに設定します(この処理により、Web APIから取得したデータが画面に反映されます)。

 (9)は後述するスプレッドシートの装飾処理です。メソッド引数にarg(=workbookInitで渡されてくるSpreadJSのインスタンス)を渡して実行します。ここではVue.jsが提供するnextTickメソッドにより、Webページにデータが反映されてから装飾処理が実行されるようにします。

スプレッドシートのヘッダー行に集計行を追加

 リスト5(9)のdecorateWorksheetメソッドには、スプレッドシートを装飾する処理を、リスト6の通り実装します。

[リスト6]スプレッドシートを装飾する処理(P002VueSpreadJS/P002VueSpreadJS/ClientApp/src/App.vue)
const decorateWorksheet = (spread) => {
  // ワークシートを取得 ...(1)
  const sheet = spread.getActiveSheet()
  // 最高気温・最低気温列のフォーマット設定 ...(2)
  sheet.setFormatter(-1, 1, "#.0", GC.Spread.Sheets.SheetArea.viewport)
  sheet.setFormatter(-1, 2, "#.0", GC.Spread.Sheets.SheetArea.viewport)
  // ヘッダーが4行になるよう設定 ...(3)
  sheet.setRowCount(4, GC.Spread.Sheets.SheetArea.colHeader)
  // 最大値ヘッダー行のスタイルを定義 ...(4)
  const style1 = new GC.Spread.Sheets.Style()
  style1.backColor = '#ffe6d5'
  style1.foreColor = '#ff0000'
  style1.formatter = "#.0"
  // 最大値ヘッダー行に文字を指定 ...(5)
  sheet.setValue(0, 0, '最大値', GC.Spread.Sheets.SheetArea.colHeader)
  // 最大値ヘッダー行にスタイルを指定 ...(6)
  sheet.setStyle(0, -1, style1, GC.Spread.Sheets.SheetArea.colHeader)
  // 最大値ヘッダー行に数式を指定 ...(7)
  // 2列目:「=MAX(<シート名>!B:B)」、3列目:「=MAX(<シート名>!C:C)」
  sheet.setFormula(0, 1, `=MAX(${sheet.name()}!B:B`,
    GC.Spread.Sheets.SheetArea.colHeader)
  sheet.setFormula(0, 2, `=MAX(${sheet.name()}!C:C`,
    GC.Spread.Sheets.SheetArea.colHeader)
(以下略:最小値と平均値の行をヘッダーに設定)
}

 引数に渡されるSpreadJSのオブジェクトspreadのgetActiveSheetメソッド(1)で、処理対象のワークシートを取得します。(2)は、スプレッドシートの最高気温、最低気温の列にフォーマットを設定する処理です。setFormatterメソッドの第1引数は行(-1はすべての行を表す)、第2引数は列、第3引数の「#.0」は数字を小数第一位まで表示することを表し、第4引数のGC.Spread.Sheets.SheetArea.viewportはビューポート(つまりワークシートの本体)に対する処理であることを表します。

 (3)ではsheet.setRowCountメソッドで、ヘッダー行が4行になるように指定しています。第2引数のGC.Spread.Sheets.SheetArea.colHeaderは、ヘッダー行に対する処理であることを表します。

 (4)でGC.Spread.Sheets.StyleクラスのオブジェクトにbackColor(背景色)、foreColor(文字色)、formatter(表示フォーマット)を設定します。

 (5)のsetValueメソッドでセルの値を、(6)のsetStyleメソッドでセルのスタイルを、(7)のsetFormulaメソッドでセルの数式を、それぞれヘッダー行に設定します。各メソッドの第1引数は行番号、第2引数は列番号、第3引数は設定値です。第4引数のGC.Spread.Sheets.SheetArea.colHeaderはヘッダー行を表し、(5)の第2引数(列番号)「-1」は、すべての列への指定を意味します。

 以上の実装により、図4のスプレッドシートをWebブラウザーに表示できます。Web APIから取得できるのは最高気温と最低気温の生データだけですが、SpreadJSのスプレッドシート機能により、最大値・最小値・平均値をクライアント側の処理により表示できます。

フレームワークやライブラリが違ってもSpreadJSの利用法は一緒

 今回はSpreadJSをVue.jsと組み合わせましたが、SpreadJSはAngularやReactといったフレームワーク・ライブラリとも組み合わせることができます。それぞれの実装方法は各フレームワーク・ライブラリの流儀に従いますが、SpreadJSに関する実装は多くが類似しています。例えば、SpreadJSのコンポーネントをWebページに配置するリスト4の記述は、同じ表示をAngularで行う場合、リスト7となります(このサンプルの詳細は過去記事で説明しています)。

[リスト7]リスト4に対応するAngularでの記述(P002AngularSpreadJS/P002AngularSpreadJS/ClientApp/src/app/spread-sample/spread-sample.component.html)
<gc-spread-sheets [hostStyle]="hostStyle"
  (workbookInitialized)="workbookInit($event)">
  <gc-worksheet name="気温" [dataSource]="temperatures"
    [autoGenerateColumns]="false">
    <gc-column headerText="日時" dataField="date" width="200">
    </gc-column>
    <gc-column headerText="最高気温" dataField="maxTemperature" width="100"
      formatter="#.0"></gc-column>
    <gc-column headerText="最低気温" dataField="minTemperature" width="100"
      formatter="#.0"></gc-column>
  </gc-worksheet>
</gc-spread-sheets>

 また、Reactでの実装はリスト8です(このサンプルの詳細は過去記事で説明しています)。リスト4/7/8の記述内容は非常に似通っていることがわかります。

[リスト8]リスト4に対応するReactでの記述(P002ReactSpreadJS/P002ReactSpreadJS/ClientApp/src/components/SpreadSample.js)
// SpreadSheets:スプレッドシート全体を表す
<SpreadSheets hostStyle={this.hostStyle}
  workbookInitialized={this.workbookInit}>
  {/*WorkSheet:ワークシートを表す*/}
  <Worksheet name='気温' dataSource={this.state.temperatures}
    autoGenerateColumns={false}>
    {/*Column:ワークシートの1列を表す*/}
    <Column headerText='日時' dataField='date' width={200}></Column>
    <Column headerText='最高気温' dataField='maxTemperature' width={100}
      formatter='#.0'></Column>
    <Column headerText='最低気温' dataField='minTemperature' width={100}
      formatter='#.0'></Column>
  </Worksheet>
</SpreadSheets>

 このようにSpreadJSは、幅広いフレームワーク・ライブラリへの対応により、開発者は自分の使い慣れた環境で利用でき、かつ、SpreadJSの利用法や実装は他の環境にも流用できるといえます。

まとめ

 本記事では、グレープシティのJavaScriptスプレッドシート部品SpreadJSを、クライアント側にVue.js、サーバー側にASP.NET Coreの環境で利用する方法を説明しました。SpreadJSが提供するスプレッドシート、ワークシート、列はVue.jsのコンポーネントとして提供され、Vue.jsで作成したWebページ内に自然に組み込めます。また、Vue.js以外にAngularやReactをWebページの作成で使用しても、考え方や実装の一部が共用できるため、少ない学習コストで幅広い環境に対応できます。

参考資料

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加

【AD】本記事の内容は記事掲載開始時点のものです 企画・制作 株式会社翔泳社

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/16799 2022/12/02 12:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング