note011:円グラフを描く

2013年1月14日


 円や円弧を描く「arc」コマンドで開始角度と終了角度を指定すると、簡単に扇形の範囲を塗りつぶすことができる。単純な爺は、これを使って、円グラフを描くことに挑戦した^^;


Canvasに未対応です。

グラフの題名: 総数(単位):
グラフの色データ項目データ値


 はじめは、円グラフのデータをスクリプト内の配列要素として直接指定していた。そのほうが手っ取り早いし、いたずらにスクリプトが長くなることもない。でも、それでは、このページを見た人が面白くないだろうとゆーことで、HTMLのFORMでデータを変更、作成できるようにした。円グラフの塗りつぶし色を指定する部分は、カラーピッカー「JSColor」を使用している。クリックすると色を選ぶことができる。データ数は9個まで。それに満たない場合は、データ値に「0」を入力すると、凡例に表示されない。ただし、途中にデータ値を「0」にすると、その部分が歯抜けになってしまう><; 必ず、最後のデータ値から順に「0」にしてね。まあ、頭で考えるより、手を動かし、力技で書いたスクリプトなので、スマートではないし、いろいろな制約や改善の余地がたくさんあると思うけど、円グラフを描く際の参考になれば幸いだ。


JavaScript

<script type="text/javascript">
window.onload = function(){
	var canvas = document.getElementById('myGraph');
	if (! canvas || ! canvas.getContext){return false;};
	ctx = canvas.getContext('2d');
	w = canvas.width;
	h = canvas.height;
	pieChart();
};
// 円グラフ関数
function pieChart(){
	ctx.fillStyle = "#ffffff";
	ctx.fillRect(0, 0, w, h);
	ctx.fill();
	ctx.lineWidth = 1;
	ctx.strokeStyle = "#cccccc";
	ctx.strokeRect(0, 0, w, h);
	/* スクリプト内で配列要素としてデータを列挙すればカンタン!
	var myTitle = "2012年衆議院選挙結果";
	var myUnit = "議席数";
	var myColor = ["#ff3300","#ffcc00","#3333ff","#99cc00","#9933ff","#66ccff","#ff9933","#66ff99","#999999"];
	var myLabel = ["自民","公明","民主","維新","みんな","未来","共産","社民","その他・無所属"];
	var myData = [294,31,57,54,18,9,8,2,7];
	*/
	// HTMLのFORMからデータを配列に読み込む
	var myTitle = document.myFORM.title_label.value;
	var myUnit = document.myFORM.sum_label.value;
	var myColor = new Array();	// JSColorの数値を読み込むときは頭に「#」をつける
		myColor[0] = "#"+ document.myFORM.c0.value;
		myColor[1] = "#"+ document.myFORM.c1.value;
		myColor[2] = "#"+ document.myFORM.c2.value;
		myColor[3] = "#"+ document.myFORM.c3.value;
		myColor[4] = "#"+ document.myFORM.c4.value;
		myColor[5] = "#"+ document.myFORM.c5.value;
		myColor[6] = "#"+ document.myFORM.c6.value;
		myColor[7] = "#"+ document.myFORM.c7.value;
		myColor[8] = "#"+ document.myFORM.c8.value;
	var myLabel = new Array();
		myLabel[0] = document.myFORM.i0.value;
		myLabel[1] = document.myFORM.i1.value;
		myLabel[2] = document.myFORM.i2.value;
		myLabel[3] = document.myFORM.i3.value;
		myLabel[4] = document.myFORM.i4.value;
		myLabel[5] = document.myFORM.i5.value;
		myLabel[6] = document.myFORM.i6.value;
		myLabel[7] = document.myFORM.i7.value;
		myLabel[8] = document.myFORM.i8.value;
	var myData = new Array();	// parseFloat(浮動小数点)の数値に変換して読み込む
		myData[0] = parseFloat(document.myFORM.d0.value);
		myData[1] = parseFloat(document.myFORM.d1.value);
		myData[2] = parseFloat(document.myFORM.d2.value);
		myData[3] = parseFloat(document.myFORM.d3.value);
		myData[4] = parseFloat(document.myFORM.d4.value);
		myData[5] = parseFloat(document.myFORM.d5.value);
		myData[6] = parseFloat(document.myFORM.d6.value);
		myData[7] = parseFloat(document.myFORM.d7.value);
		myData[8] = parseFloat(document.myFORM.d8.value);
	var p1 = 0;	// 円弧の開始角度(ラジアン)
	var p2 = 0;	// 円弧の終了角度(ラジアン)
	var offsetP = Math.PI/2*-1;	// 開始点を真上(90度)にする
	var mySum = 0;	// データの合計値
	var y = h/2;	// 円グラフの中心Y座標
	var r = h/2*0.8;	// 円グラフの半径
	var x = r + h*0.05;	// 円グラフの中心X座標
	for(i=0; i<myData.length; i++){
		mySum += myData[i];	// データ値を足し算して合計を求める
	};
	mySum = Math.round(mySum*10)/10;
	// 円グラフの描画
	for(i=0; i<myData.length; i++){
		p2 = myData[i] * (Math.PI*2 / mySum);
		ctx.fillStyle = myColor[i];
		ctx.beginPath();
		ctx.moveTo(x, y);
		ctx.arc(x, y, r, p1+offsetP, p1+p2+offsetP, false);
		ctx.lineTo(x, y);
		ctx.closePath();
		ctx.fill();
		p1 = p1 + p2;	// 終了角度を次の開始角度にする
	};
	p1 = 0;
	p2 = 0;
	for(i=0; i<myData.length; i++){
		p2 = myData[i] * (Math.PI*2 / mySum);
		if((myData[i]/mySum)>0.06){	// データが全体の6%より大ならラベルを表示
			ctx.font = "12px Meiryo";
			ctx.textAlign = "center";
			ctx.textBaseline = "alphabetic";
			ctx.fillStyle = "black";
			var txt = myLabel[i];
			var xx = Math.cos(p1+p2/2+offsetP)*(r*0.6)+x;	// ラベルのX座標
			var yy = Math.sin(p1+p2/2+offsetP)*(r*0.6)+y;	// ラベルのY座標
			ctx.fillText(txt, xx, yy);
			p1 = p1 + p2;
		};
	};
	// グラフのタイトルと凡例
	var myRow = h * 0.2;
	var stepRow = (h * 0.8)/ myLabel.length;
	ctx.font = "14px Meiryo";
	ctx.textAlign = "center";
	ctx.textBaseline = "alpabetic";
	ctx.fillStyle = "black";
	ctx.fillText(myTitle, 2*x, h*0.1);
	for(i=0; i<myLabel.length; i++){
		if(! myData[i]==0){	// データが「0」じゃなかったら凡例を表示する
			ctx.font = "12px Meiryo";
			ctx.textAlign = "left";
			ctx.textBaseline = "alphabetic";
			ctx.fillStyle = myColor[i];
			ctx.fillText("■", 2*x, myRow + stepRow * i);
		};
	};
	for(i=0; i<myLabel.length; i++){
		if(! myData[i]==0){	// データが「0」じゃなかったら凡例を表示する
			ctx.font = "12px Meiryo";
			ctx.textAlign = "left";
			ctx.textBaseline = "alphabetic";
			ctx.fillStyle = "black";
			var txt = myLabel[i] + ":" + myData[i];
			ctx.fillText(txt, 2*x + 14, myRow + stepRow * i);
		};
	};
	// グラフ中央にデータ合計数を表示
	ctx.fillStyle = "#000000";
	ctx.beginPath();
	ctx.arc(x, y, 0.3*r, 0, Math.PI*2, false);
	ctx.closePath();
	ctx.fill();
	ctx.font = "12px Meiryo";
	ctx.textAlign = "center";
	ctx.textBaseline = "middle";
	ctx.fillStyle = "white";
	ctx.fillText(myUnit, x, y-8);
	ctx.fillText(mySum, x, y+8);
};
</script>