Web Performer で2軸グラフを表現してみる

こんにちは。エヌデーデーの関口です。
Web Performer で開発を行っていて、グラフ機能をもう少し表現豊かにしたいといった要望はないでしょうか。
この記事では2020年5月にリリースされた Web Performer V2.4 の「カスタム部品」に JavaScript のグラフライブラリである Chart.js を利用して、2軸グラフを実装する方法を紹介したいと思います。
前提知識として、以前の記事「Web Performer V2.4の新機能「カスタム部品」を使って地図を表示してみる」を先に読んでいただくと、比較的スムーズに理解出来るかと思います。

想定される読者

  • Web Performerは導入済
  • Web Performer標準のグラフ機能に課題を抱えている
  • JavaScript プログラム経験者

今回の実装例について

Web Performer の標準機能として、グラフ表示という機能があります。データベースの値を元に、棒グラフ(縦、横)、折れ線グラフ、円グラフ、散布図をHTML上に表現するというものです。(下図参照)

標準のグラフ表示機能は、一覧形式の入出力に特定の設定を行うだけで簡単にグラフを表現できるので便利なのですが、ユーザー要件によっては、売上金額と売上数量を同じグラフ上に表現したいというようなケースもあるでしょう。そのような要件に対応する方法として、V2.4から利用出来る「カスタム部品」が利用出来ます。
今回は気象庁が発表している気象データ(http://www.data.jma.go.jp/gmd/risk/obsdl/)を元に、下図の Excel のように東京の平均気温と降水量を一つのグラフで表現します。

なお、以下の説明では、Web Performer のプロジェクト、アプリケーション、およびデータベース接続の設定は既に作成されている前提で進めます。

グラフの対象となるデータモデルを作成する

まず、グラフの対象となるデータモデルを作成しましょう。先に示した Excel ファイルがあるので、それを元にデータモデルとテーブルを作成します。
Web Performer のプロジェクトを右クリックして、[新規]>[新規データモデル] を選びます。データモデルコードは TENKI としておきましょう。

次に、既に作成されている Excel ファイルを開いて、データモデルの対象となるデータ領域を選択してコピーします。そのまま Web Performer の TENKI 編集画面上で、右クリックして [Excelデータ行をDMとして貼り付け] を選択すると、項目の情報などが自動的に作成されます。この機能は、Excel で管理されているデータなどを Web Performer のアプリケーションとして作成したい場合などには便利な機能です。

Excel 上の項目名が日本語の場合、そこから推測してデータモデルの項目コードを英字で作成します。またデータタイプや、桁数なども推測して作成されます。これらは必要に応じて修正してください。

体裁を整えたデータモデルは以下の通りになりました。

項目コード名前NULL可キーグループ桁数小数桁データタイプ
NENGETSU年月不可100DATE
KION平均気温(℃)01210NUM
KOSUI降水量の合計(mm)01310NUM

データモデルからテーブルを作成する

データモデルができたので、テーブルを作成してみます。なお、データベースへの接続設定は行っている前提とします。
ツールバーから、[スキーマを作成します。(F7)] を押し、表示されたダイアログに、DDL(テーブル作成用のSQL)を保存するディレクトリや、データベースへの接続情報を入力し[DDL作成] を押します。
一度ダイアログが閉じるので、もう一度 [スキーマを作成します。(F7)] を押し、今度はダイアログの [スキーマ作成] ボタンを押します。これでテーブルの作成は終了です。

下図では Eclipse のプラグインである DBViewer を使って実際にテーブルが作成されたのかを確認していますが、DBViewer 以外でも結構ですので、ご自身が利用されているデータベースツールでご確認ください。

テーブル作成を終えたら、データを登録しておきましょう。

グラフを表示する入出力を作成する

データモデルができたので、データを表示するための入出力を作ります。
Web Performer のプロジェクトを右クリックして、[新規]>[新規入出力] を選びます。入出力コードは TENKI_IO 、名前は「天気グラフ」としておきましょう。

新規入出力のダイアログでは、コピー元データモデルは [TENKI] 、画面構成パターンは [一覧] を選択してください。項目タイプはそのままで結構です。下図のような定義が出来ると思います。

また、プレビューとしては次のようになります。

カスタム部品(グラフ)の設定を入出力項目に定義する

次にカスタム部品(グラフ)を表示させるために、グループ(G)の入出力項目にカスタム部品の定義をします。

今回のカスタム部品の名前は、tenkiGraph とします。以前の記事でも紹介しましたが、この名前はカスタム部品の実装である JavaScript を格納するフォルダの名称になります。

項目コード G 天気 を選択して、入出力項目プロパティに次の値を設定します。

キー
compName カスタム部品tenkiGraph
compParam カスタム部品パラメータ{width: 800, height: 500, label1: '平均気温(℃)’, label2: '降水量(mm)’}

カスタム部品を作成する

tenkiGraph の実装である JavaScript の作成を行います。
プロジェクトフォルダ以下に、次フォルダを作成してください。
/src/JavaWebApp/@COMMON/components/tenkiGraph/
その次にこのフォルダ以下に次のファイルを作成してください。それぞれのファイルの役割については、以前の記事をご覧ください。記述内容については後述します。

  • load.jsp
  • snippet.jsp
  • glue.js
  • script/module.js

ファイル構成は次のようになります。

/src/JavaWebApp/@COMMON/components/tenkiGraph/
 ├script
 │  └module.js
 ├load.jsp
 ├snippet.jsp
 └glue.js

load.jsp

load.jsp には、Chart.js を CDN から読み込む設定と、自分で作成する module.js を読み込む設定を入れておきます。

<%@ page pageEncoding="UTF-8" %>
<%@ page import="jp.co.canon_soft.wp.runtime.AppContext"%>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.3/Chart.min.js" type="text/javascript"></script>
<script src="<%= AppContext.getContextPath() %>/components/tenkiGraph/script/module.js" type="text/javascript"></script>

snippet.jsp

snippet.jsp では、グラフを表示する領域を canvas タグとして定義します。

<%@ page pageEncoding="UTF-8" %>
<canvas id="myChart"></canvas>

glue.js

glue.js には init_tenkiGraph という関数を定義する必要があります。

function init_tenkiGraph(itemElem, itemValue, itemCode, compParam, isGroupItem, index) {
    const records =  JSON.parse(disp.get(itemCode))[itemCode];

    const kion_array = [];
    const kosui_array = [];
    const nengetsu_array = [];
    // 平均気温、降水量のデータを配列にして、年月のデータもX軸として配列に格納する
    const red = records.forEach( (o) => {
        kion_array.push(Number(o.KION.normalizedvalue));
        kosui_array.push(Number(o.KOSUI.normalizedvalue));
        nengetsu_array.push(o.NENGETSU.normalizedvalue.replace(/(\d+)\-(\d+)\-\d+/, `$1年$2月`));
    });

    genChart(kion_array, kosui_array, nengetsu_array, compParam);
}

コードの解説です。
2行目の const records = JSON.parse(disp.get(itemCode))[itemCode]; で一覧表示されたデータモデルのレコードをJSON形式の配列に格納しています。

8行目~12行目でその配列から値を取り出し、新たな配列に詰め込み直しています。

14行目で module.js に定義する genChart という関数を呼び出しています。

module.js

module.js で Chart.js のオブジェクトを生成し、画面に表示する処理を書いています。

const genChart = (kion, kosui, nengetsu, param) => {
    // canvas タグで定義したグラフ表示領域の大きさをパラメータから取得して変更
    document.getElementById("myChart").style.cssText = `width: ${param.width}px; height: ${param.height}px;`;

    // Chart.js の表示領域の初期化
    const ctx = document.getElementById("myChart").getContext('2d');

    // グラフの表示オプション
    const options = {
        hover: {
            mode: 'dataset',
        },
        scales: {
            // Y軸の表示設定
            yAxes: [{
                id: "y-axis-1",
                type: "linear",
                position: "left",
                ticks: {
                    max: 30,
                    min: 0,
                    stepSize: 5
                },
            }, {
                id: "y-axis-2",
                type: "linear", 
                position: "right",
                ticks: {
                    max: 600,
                    min: 0,
                    stepSize: 100
                },
            }],
        }
    };

    // Char.js に表示させるデータと、Y軸の設定をパラメータとして与えて表示
    const mixedChart = new Chart(ctx, {
            type: 'bar',
            data: {
                datasets: [{
                    label: param.label1,
                    data: kion,
                    type: 'line',
                    borderColor: "rgba(235,125,49,0.8)",
                    pointBackgroundColor: "rgba(235,125,49,0.8)",
                    fill: false, 
                    yAxisID: "y-axis-1",
                }, {
                    label: param.label2,
                    data: kosui,
                    type: 'bar',
                    borderColor: "rgba(68,114,196,0.8)",
                    backgroundColor: "rgba(68,114,196,0.5)",
                    yAxisID: "y-axis-2", 
                }],
                labels: nengetsu
            },
            options: options
        });
}

コードの解説です。
9行目~35行目は Chart.js を用いて、2軸グラフを表示するときの設定として、左右それぞれの軸の目盛りの表現方法を定義しています。

38行目~60行目で Chart.js を生成してグラフを表現するのですが、data の箇所に実際に表現するデータの配列( datasets )と、X軸の表現 labels をパラメータとして与えています。
43行目の data に平均気温、51行目の data に降水量の配列を設定しているのがわかるかと思います。
また、凡例のタイトルを入出力で定義していた compParam から取得するようにしており、それぞれ42行目、50行目でタイトルを設定しています。

アプリケーションを自動生成する

以上を設定し終えたら、アプリケーションの自動生成です。
ツールバーから、自動生成のボタンをクリックし、表示されたダイアログでは、HTML を HTML5 として自動生成します。

アプリケーションを実行する

自動生成が完了したら、アプリケーションサーバー(Tomcat)を起動して、http://localhost:8080/TENKI_GRAPH/ にアクセスしてみます。
ログインして、テストページから TENKI_IO(天気グラフ)をクリックしてみてください。Excel で作成したものと同じようなグラフの表現が出来ているのがおわかりでしょう。

まとめ

前回は「カスタム部品」を利用して、地図を表現するという方法をご紹介しましたが、今回ご紹介したようにグラフの表現についても「カスタム部品」を用いて表現することが可能です。

グラフ表現に用いた Chart.js は JavaScript のプログラムを書くという手間はありますが、多様なグラフ表現に対応しているので、データの投入や抽出は、Web Performer でスピーディに作ってしまって、グラフによる様々な形で表現の部分は「カスタム部品」に時間をかけるというやり方が良いかもしれません。

Web Performer のグラフ機能も手軽に利用出来て便利ですが、もう少し表現力を上げたいという方は検討してみてはいかがでしょうか。

また、当社は Web Performer の開発部隊とは別に BI システムを構築する部隊も居ます。データの収集、蓄積から、当記事のデータの可視化といったところまでワンストップでご相談に乗れます。もし BI システム構築にご興味があれば是非お問い合わせ頂ければ幸いです。