C#アプリのローカルReporting ToolとしてChart.jsを使う
TL;DR
C#アプリからブラウザーを起動させ、http/httpsのWebサーバーが不要で、Chart.jsを使ってチャートを表示することができる。
1.チャート表示用html + 2.データロード用js + 3.データ定義js
1と2は一回作っておけばOKで、3はチャート表示する度にC#アプリから書き出す。
webpackは必須ではないが、TypeScriptでChart.jsを使うためにはimportが必要なため、通常はWebサーバーが必要だが、webpackで2.データロード用js
とChart.jsをバンドルにすればWebサーバーなしでfile:///
プロトコルでも動作。
目次
背景
.Net Coreになってからすぐに使える内蔵のレポーティングツールがなく、.Net 5もそうみたい。
いろいろ調べたら第三者の有料のものが多くて何か面倒そう。
そこで目にしたのはChart.js である。ビジュアルがキレイでチャートの種類も豊富。無料で使えてドキュメントを読む限りシンプルに使えそうだから、これを使うことにした。
JavaScriptのライブラリだから、C#からはそのまま使えないが、少し工夫すれば普通に使えて重宝している。
全体像
使用ツール
- Visual Studio Code(vscode)
HTML/JavaScript/TypeScript編集 - Node.js
npmを使うため - webpack
npmよりインストール
TypeScriptの恩恵を受けるのにChart.js
をimport
することが必要。import
はfile:///
プロトコルの場合がブラウザーサポートされていない。そのためwebpackでindex.js
とChart.js
のコードをバンドル(main.js
)にして、HTMLの<Script>
タグで指定すれば解決。 - Chart.js
npmよりインストール
チャートを描画するjsライブラリ。 - Visual Studio 2019 Community
C# デモプロジェクト用、これに限らない。 - ブラウザー
HTMLを表示用、今回はMicrosoft Edge(chromium)を使用。
開発環境の準備
- プロジェクトフォルダー作成
CsChartjsDemo
というフォルダーを作成し、その中にsrc
とdist
のフォルダーをそれぞれ作成する。CsChartjsDemo │ ├─dist #webpackの出力、htmlファイル、入力データjsファイル格納 └─src #ts,jsソースファイル格納 package.json
作成npm init -y- TypeScript初期化tsc -init
- webpackをインストールnpm install webpack webpack-cli --save-dev
- Chart.jsをインストールnpm install chart.js
これでpackage.json
はこんな感じになる:
{
"name": "cschartjsdemo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.58.0",
"webpack-cli": "^4.9.0"
},
"dependencies": {
"chart.js": "^3.5.1"
}
}
まずJavaScript + Chart.jsで動くようにする
※ここの説明をシンプルにするために、各ファイル名はwebpackがデフォルトで認識できるものにしている。
- チャート表示用HTMLファイル作成
./dist
フォルダーにindex.html
を作成する。チャートを表示するためだけなので、Scriptタグ以外はほぼ空っぽ。
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" charset="UTF-8">
</head>
<body>
<script src="./main.js"></script>
</body>
</html>
index.ts
でチャート表示機能を実装
./src/index.ts
import Chart from "chart.js/auto";
//参照:https://www.chartjs.org/docs/latest/getting-started/integration.html
//bodyを取得してcanvasを作成して挿入
let body: HTMLBodyElement = document.querySelector("body")!;
let canvas: HTMLCanvasElement = document.createElement("canvas");
body.appendChild(canvas);
//テスト用の入力データを作成、次のステップはこのデータをC#から書き出す
let dataInput={
labels: ["1月","2月","3月"],
datasets: [
{
label: "売上",
data: [100, 300, 500],
backgroundColor:"LightBlue"
},
{
label: "仕入",
data: [30, 100, 150],
backgroundColor:"LightGreen"
}
]
};
//ここで問題なく表示できたら,dataInputをC#で生成させればOK
let chartConfig= {
type: "bar",
data: dataInput
};
let ctx = canvas.getContext("2d");
let chart: Chart = new Chart(ctx, chartConfig);
- tscで
index.ts
をindex.js
に出力tsc - webpackで
main.js
を出力npx webpack
ファイルエクスプローラーで./dist/index.html
をEdgeで開いてみる:
C#アプリからChart.js用入力データを生成してチャートを表示させる
順調にチャート表示できたので、ここからは上記手動でindex.ts
の中で定義したdataInput
をC#から書き出せばいい。
-
C#でサンプルデータを作成する
以下のようなDataTable
を元データのサンプルとして作るstring int int 月 売上 仕入 1月 100 30 2月 300 100 3月 500 150 private DataTable CreateSampleTable() {//元データサンプルを作る DataTable dt = new DataTable(); dt.Columns.Add("月", typeof(string)); dt.Columns.Add("売上", typeof(int)); dt.Columns.Add("仕入", typeof(int)); dt.Rows.Add(new object[] { "1月", 100, 30 }); dt.Rows.Add(new object[] { "2月", 300, 100 }); dt.Rows.Add(new object[] { "3月", 500, 150 }); return dt; } -
C#でChart.jsの入力データモデルを定義する
data
とdataset
の2種類:public class ChartJsDataSet {//Chart.js入力データのdatasetモデルを定義する public string label { get; set; } public List<int> data { get; set; } public string backgroundColor { get; set; } } public class ChartJsInputData {//Chart.js入力データのdataモデルを定義する public List<string> labels { get; set; } public List<ChartJsDataSet> datasets { get; set; } } -
C#でデータを定義したモデル形式に抽出し、
inputData.js
に書き出す//まず元データのサンプルを作る var dt = CreateSampleTable(); //売上と仕入のdatasetをそれぞれ作る ChartJsDataSet cdsSales = new ChartJsDataSet() { label = "売上", data = dt.AsEnumerable().Select(r => r.Field<int>("売上")).ToList(), backgroundColor = "Gold" }; ChartJsDataSet cdsPurchase = new ChartJsDataSet() { label = "仕入", data = dt.AsEnumerable().Select(r => r.Field<int>("仕入")).ToList(), backgroundColor = "Pink" }; //datasetをListにする List<ChartJsDataSet> chartDatasets = new List<ChartJsDataSet>(); chartDatasets.Add(cdsSales); chartDatasets.Add(cdsPurchase); //datasetのListをinputDataモデルに入れる ChartJsInputData chartInput = new ChartJsInputData() { labels = dt.AsEnumerable().Select(r => r.Field<string>("月")).ToList(), datasets=chartDatasets }; //inputDataをjsonのstringに出力する string strChartInput = JsonSerializer.Serialize(chartInput, new JsonSerializerOptions() { Encoder = System.Text.Encodings.Web.JavaScriptEncoder.Create(System.Text.Unicode.UnicodeRanges.All) }); //inputDataをjsファイルに書き出す string output = $"var dataInput={strChartInput};"; System.IO.File.WriteAllText($"{PROJ_PATH}\\dist\\dataInput.js",output);書き出された
dataInput.js
はこんな感じ:var dataInput={"labels":["1月","2月","3月"],"datasets":[{"label":"売上","data":[100,300,500],"backgroundColor":"Gold"},{"label":"仕入","data":[30,100,150],"backgroundColor":"Pink"}]}; -
index.ts
のなかのdataInput
の定義を削除する -
index.html
にdataInput.js
を追加する<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" charset="UTF-8"> </head> <body> <!-- main.jsの前にC#から書き出されたdataInput.jsを追加する --> <script src="./dataInput.js"></script> <script src="./main.js"></script> </body> </html> -
再度
tsc
を実行して、npx webpack
を実行する
ここからはindex.html
,index.ts
を編集する必要がなくなる。 -
最後にC#より以下のコードを実行すればデフォルトのブラウザーで
index.html
を開くSystem.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo() { FileName = $"{PROJ_PATH}\\dist\\index.html", UseShellExecute = true }) ;
後書き
以上はC#からChart.jsのチャートを生成する一番基本的なステップでした。
より高度なチャート機能を使うにはC#でのモデル定義追加や、index.tsでチャートをクリックしたときのイベントハンドル等、いろいろいじれて楽しそうです。
デスクトップのアプリでもJavascriptのライブラリが使えて便利な時代と実感しています。
上記のDemoでは、tscの際のエラー等、完璧ではありませんが、やり方のメモとしては支障がないと、また別件として今後対応していきたいと思います。
コメント
コメントを投稿
個人情報を記入しないようご注意ください