WebFOCUSのHTML5拡張グラフを開発する(chart.jsで作る場合)

2025/03/05に公開

chart.jsを使って拡張グラフを開発する方法

D3.jsは学習コストも高くてそんなにビジュアライゼーションとか言わなくていい場合は、chart.jsで簡単に拡張グラフを作れます。

Chart.jsとD3.js

Chart.js

  • 使いやすさ: Chart.jsはシンプルで使いやすく、簡単に美しいグラフを作成できる
  • 基本的なグラフタイプ: 棒グラフ、折れ線グラフ、円グラフなど、一般的なグラフタイプをサポート
  • カスタマイズ性: カスタマイズは可能だが、D3.jsほど自由度は高くない
  • パフォーマンス: 軽量で、パフォーマンスも良好

D3.js

  • 自由度の高さ: D3.jsは非常に柔軟で、複雑なデザインやインタラクティブな要素を追加することができる
  • カスタマイズ性: グラフの細部までカスタマイズ可能で、独自のデザインを実現できる
  • 学習曲線: D3.jsは学習曲線が急で、使いこなすには時間がかかる
  • 大規模データの処理: 大量のデータを扱うのに適している
  • 複雑なデータ表現: データの関係性を視覚化する多彩な表現が可能

選び方

  • 簡単に使いたい場合: Chart.jsが適しています。短時間で基本的なグラフを作成したい場合に便利です。
  • 高度なカスタマイズが必要な場合: D3.jsが適しています。複雑なデータを視覚化したり、独自のデザインを追求したい場合に最適です。

chart.jsでも作成できる棒グラフや折れ線グラフや円グラフならchart.jsの方が開発コストは低くなります。

オプションを設定しなくても、軸の大きさやラベルの大きさ、文字の角度など全部良い感じにしてくれるのがchart.jsの良いところです。

D3.jsは、デフォルトの配置では良い感じにならないので文字サイズや角度や表示位置を細かく指定しします。

時には、ラベルの文字数や棒グラフの本数や縦横比によって計算した数字で設定することになります。(chart.jsより自由)

chart.jsを使って拡張グラフを開発する方法

libフォルダにchart.jsを置いて、chart.jsな記法でcanvasに書けば良い。

と簡単にいうとこれだけです。

フォルダ構成

  • com.shimokado.chartjs_sample
    • lib
      • chart.js (ダウンロードして気になる方はミニマイズ)
    • icons
      • icon.png (適当な画像を作りましょう)
    • com.shimokado.chartjs_sample.js
    • properties.json

設定ファイル

特になにもないですが、external_libraryに chart.js を指定しています。

properties.json
{
    "info": {
        "version": "1.0.0",
        "implements_api_version": 1.0,
        "author": "Shimokado Masataka",
        "copyright": "Shimokado Masataka",
        "url": "https://github.com/shimokado/webfocus-extensions/tree/main/com.shimokado.chartjs_sample",
        "icons": {
            "medium": "icons/icon.png"
        }
    },
    "properties": {
        "external_library": "lib/chart.js"
    },
    "propertyAnnotations": {
        "external_library": "str"
    },
    "dataBuckets": {
        "tooltip": false,
        "matrix": false,
        "data_page": false,
        "series_break": false,
        "buckets": [
            {
                "id": "value",
                "type": "measure",
                "count": {
                    "min": 1,
                    "max": 1
                }
            },
            {
                "id": "labels",
                "type": "dimension",
                "count": {
                    "min": 1,
                    "max": 1
                }
            }
        ]
    },
    "translations": {
        "en": {
            "name": "Simple Bar Chart with Chart.js",
            "description": "A simple bar chart written with Chart.js",
            "icon_tooltip": "Simple Bar Chart with Chart.js",
            "value_name": "Value",
            "value_tooltip": "Drop a measure here",
            "labels_name": "Labels",
            "labels_tooltip": "Drop a dimension here"
        },
        "ja": {
            "name": "Chart.jsで書いた簡単な棒グラフ",
            "description": "Chart.jsで書いてみただけのグラフ",
            "icon_tooltip": "chart.jsで書いた簡単な棒グラフ",
            "value_name": "値",
            "value_tooltip": "ここにメジャーをドロップ",
            "labels_name": "ラベル",
            "labels_tooltip": "ここにディメンションをドロップ"
        }
    }
}

モジュール

com.shimokado.chartjs_sample.js
(function() {
	function initCallback(successCallback, initConfig) {
		successCallback(true);
	}

	function noDataPreRenderCallback(preRenderConfig) {
	}
	
	function noDataRenderCallback(renderConfig) {
		renderConfig.data= [[['A',10],['B',20]]];
		renderConfig.dataBuckets = {labels: {title: 'Lavel'},value: {title: 'Value'}};
		renderCallback(renderConfig);
	}

	function preRenderCallback(preRenderConfig) {
	}

	function renderCallback(renderConfig) {
		const container = renderConfig.container; // 出力先のコンテナ
		const data = renderConfig.data; // WebFOCUSが出力したデータ
		const dataBuckets = renderConfig.dataBuckets; // データバケット
		const buckets = dataBuckets.buckets; // バケットの配列

		container.innerHTML = ''; // コンテナをクリア

		// chart.jsの場合はcanvas要素を作成して、それをコンテナに追加する
		const canvas = document.createElement('canvas');

		// data配列のオブジェクトからlabelsプロパティの値を取り出して配列に格納
		const labels = data.map(function(d) {return d.labels});

		// data配列のオブジェクトからvalueプロパティの値を取り出して配列に格納
		const values = data.map(function(d) {return d.value});

		// chart.jsの棒グラフを描画
		new Chart(canvas, {
		  type: 'bar',
		  data: {
			labels: labels,
			datasets: [{
			  label: buckets.value.title,
			  data: values
			}]
		  }
		});

		container.appendChild(canvas);

		renderConfig.renderComplete();
	}

	var config = {
		id: 'com.shimokado.chartjs_sample',	// エクステンションID
		containerType: 'html',	// // 'html'または'svg'(デフォルト)
		initCallback: initCallback,	// 拡張機能の初期化直前に呼び出される関数への参照。必要に応じてMonbeamインスタンスを設定するために使用
		preRenderCallback: preRenderCallback,  // 拡張機能のレンダリング直前に呼び出される関数への参照。preRenderConfigオブジェクトが渡されます
		renderCallback: renderCallback,  // 実際のチャートを描画する関数への参照。renderConfigオブジェクトが渡されます
		noDataPreRenderCallback: noDataPreRenderCallback, // データがない場合のレンダリング直前に呼び出される関数への参照
		noDataRenderCallback: noDataRenderCallback, // データがない場合のチャート描画関数への参照
		resources: {
			script: ['lib/chart.js'],
			css: ['css/style.css']
		},
		modules: {
			dataSelection: {
				supported: false,  // 拡張機能でデータ選択を有効にする場合はtrueに設定
				needSVGEventPanel: false, // HTMLコンテナを使用するか、SVGコンテナを変更する場合は、これをtrueに設定すると、チャートエンジンがユーザー操作を捕捉するために必要なSVG要素を挿入します
				svgNode: function() {}  // HTMLコンテナを使用するか、SVGコンテナを変更する場合は、ルートSVGノードへの参照をここで返します
			},
			eventHandler: {
				supported: true // イベントハンドラを有効にする場合はtrueに設定
			},
			tooltip: {
				supported: true  // 拡張機能でHTMLツールチップを有効にする場合はtrueに設定
			}
		}
	};

	// 必須: この呼び出しにより拡張機能がチャートエンジンに登録されます
	tdgchart.extensionManager.register(config);
}());

実行結果

alt text

まとめ

グラフのオプションを何も指定しなくても良い感じ

  • Y軸が良い感じの幅でキリの良い数字のグリッドが付いている
  • X軸のラベルが長いので良い感じに傾けている
  • グラフ領域が良い感じに設定されてラベル表示場所が確保できている
  • グラフの幅と凡例表示位置も良い感じ
  • 位置もデザインも良い感じのツールチップが表示される

このような簡単なグラフを配置したダッシュボード風の拡張グラフを作るならchart.jsで良いですね。

Discussion