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