Ignite UIのigDataChartで時折見られるご要望に、図形やテキストなどの視覚要素を追加したいというものがあります。そこで、今回はチャートエリアにカスタムのHTML Canvasを追加する方法をご紹介します。
サンプルに使用するチャートは折れ線グラフです。シリーズの最大値と最小値となる地点に横線を引いてラベルを付けてみたいと思います。
最終的に目指すチャートはこちらです。

赤線の Max ラインと青線の Min ライン、およびそのラベルがカスタムで追加した Canvas 要素です。

それでは、コーディングです。

まず、 Canvas を追加するためのヘルパークラス「MyCanvas」を定義します。
コンストラクタはターゲットとする igDataChartのID、X軸とY軸をインプットとします。

function MyCanvas(chart, x, y) {
	this.attached = false;
	this.chartId = chart;
	this.xAxis = x;
	this.yAxis = y;
}

MyCanvas  クラスの attachCanvas() ファンクションは、 html に <canvas> タグを追加します。igDataChart は <canvas> のレイヤー構造になっていますので、ブランクの canvas を新たに追加する形です。

MyCanvas.prototype.attachCanvas = function (chartElement) {
	this.element = chartElement;
	var canvases = chartElement.find("canvas");
	this.renderCanvas = $("<canvas class='myCanvas' style='position: absolute; top: 0; left: 0;'></canvas>");
	if (canvases.length > 0) {
		this.overlay = $(canvases[canvases.length - 1]);
		this.overlay.before(this.renderCanvas);
		this.attached = true;
	}
};

続きまして、 draw() メソッドでは、先ほど追加した <canvas> から2Dコンテキストを取得し、図を描いていきます。まずは igDataChart のチャート領域でクリップします。実際の図の描画は最後のaddMinAndMaxLines() ファンクションで行います。

MyCanvas.prototype.draw = function () {
	if (!this.attached) {
		this.attachCanvas($("#" + this.chartId));
	}

	this.renderCanvas.attr("width", this.overlay.attr("width"));
	this.renderCanvas.attr("height", this.overlay.attr("height"));

	if (this.context == null) {
		this.context = this.renderCanvas[0].getContext("2d");
	}
	this.context.clearRect(0, 0, this.renderCanvas.attr("width"), this.renderCanvas.attr("height"));

	var viewport = this.element.igDataChart("option", "gridAreaRect");

	this.context.save();
	this.context.beginPath();
	this.context.moveTo(viewport.left, viewport.top);
	this.context.lineTo(viewport.left + viewport.width, viewport.top);
	this.context.lineTo(viewport.left + viewport.width, viewport.top + viewport.height);
	this.context.lineTo(viewport.left, viewport.top + viewport.height);
	this.context.lineTo(viewport.left, viewport.top);
	this.context.clip();
				
	this.addMinAndMaxLines(viewport);
};

そして、次が addMinAndMaxLines() の中身です。

MyCanvas.prototype.addMinAndMaxLines = function (viewport) {
	//y=925の位置にMaxライン、y=100の位置にMinラインを表示させる
	var maxYValue = 925;
	var minYValue = 100;
	var maxPos = this.element.igDataChart("scaleValue", this.yAxis, maxYValue);
	var minPos = this.element.igDataChart("scaleValue", this.yAxis, minYValue);

	//Max値のlineとtextを描画する
	this.context.strokeStyle = "red";
	this.context.fillStyle = "red";
	this.context.lineWidth = 1.0;
	this.context.beginPath();
	this.context.moveTo(viewport.left, maxPos);
	this.context.lineTo(viewport.left + viewport.width, maxPos);
	this.context.stroke();
	this.context.textBaseline = "bottom";
	this.context.fillText("Max:" + maxYValue, viewport.left, maxPos);
				
	//Min値のlineとtextを描画する
	this.context.strokeStyle = "blue";
	this.context.fillStyle = "blue";
	this.context.beginPath();
	this.context.moveTo(viewport.left, minPos);
	this.context.lineTo(viewport.left + viewport.width, minPos);
	this.context.stroke();
	this.context.textBaseline = "bottom";
	this.context.fillText("Min:" + minYValue, viewport.left, minPos);
	
	this.context.restore();
};

ヘルパークラスの定義は以上です。

後は、クラスをインスタンス化し、 igDataChartのrefreshCompleted() イベントで draw() メソッドを実行するだけです。 refreshCompleted() イベントを使用するのは 、igDataChart がズームされた際にそのズームレベルによって Canvas 要素を書き換える必要があるからです。

では、 igDataChart の定義です。

//チャートデータ
var data = [
	{ "Country": "Canada", "Coal": 400, "Oil": 100, "Gas": 175, "Nuclear": 225 },
	{ "Country": "China", "Coal": 925, "Oil": 200, "Gas": 350, "Nuclear": 400 },
	{ "Country": "Russia", "Coal": 550, "Oil": 100, "Gas": 250, "Nuclear": 475 },
	{ "Country": "Australia", "Coal": 450, "Oil": 100, "Gas": 150, "Nuclear": 175 },
	{ "Country": "United States", "Coal": 800, "Oil": 250, "Gas": 475, "Nuclear": 575 },
	{ "Country": "France", "Coal": 375, "Oil": 150, "Gas": 350, "Nuclear": 275 }
];

//チャートの定義			
$("#chart").igDataChart({
	width: "100%",
	height: "400px",
	dataSource: data,
	verticalZoomable: true,
	horizontalZoomable: true,
	axes: [
		{
			name: "xAxis",
			type: "categoryX",
			label: "Country"
		},
		{
			name: "yAxis",
			type: "numericY",
			minimumValue: 0,
			maximumValue: 1000
		}
	],
	series: [
		{
			name: "Coal",
			type: "line",
			xAxis: "xAxis",
			yAxis: "yAxis",
			valueMemberPath: "Coal"
		},
		{
                        name: "Oil",
                        type: "line",
                        xAxis: "xAxis",
                        yAxis: "yAxis",
                        valueMemberPath: "Oil"
		},
		{
                        name: "Gas",
                        type: "line",
                        xAxis: "xAxis",
                        yAxis: "yAxis",
                        valueMemberPath: "Gas"
		}
	],
	refreshCompleted: function (e, ui) {
		myCanvas.draw();
	}
});

上記の igDataChart で使用するためには、 MyCanvas は次のようにインスタンス化します。

var myCanvas = new MyCanvas("chart", "xAxis", "yAxis");

必要な実装は以上です。

今回の MyCanvas  クラスのファンクションを応用すれば、チャートのX軸やY軸の位置を指定して様々な線や図形を描くことができ、また注釈のようなテキストも表示することが可能です。

例えば、特定のデータポイントを強調してみたり、

特定の領域に背景色をつけたりすることができます。

チャートに自由に視覚要素を追加してみてください。

Tagged:

製品について

Ignite UI for jQuery