サイトの計測を手動で行ってみる PHP #2「GoogleCharts」

2015年4月4日

PHP プログラミング 特集

前回、ビーコン方式でログを取得して、テーブルレポートを表示したが、GoogleAnalyticsのメインビジュアルがそうであるように、ビジュアルグラフでないと、数字ばっかり見ても何も面白くない。 ということで、ビジュアルグラフを設置してみます。 Canvasで作っていこうと思ったんですが、初回は「GoogleCharts」を使って簡単にやってみます。

GoogleChartsについて

https://google-developers.appspot.com/chart/ URLやAJAXでパラメータを来ると、グラフイメージが自動生成される便利なツールです。 サイトを見てみるとたくさんの種類のグラフがあり、かなりの多様性が有ることがわかります。 今回は「AreaChart」という機能で構築します。

サンプルコード

<html> <head> <script type="text/javascript" src="https://www.google.com/jsapi"></script> <script type="text/javascript"> google.load("visualization", "1", {packages:["corechart"]}); google.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Year', 'Sales', 'Expenses'], ['2013', 1000, 400], ['2014', 1170, 460], ['2015', 660, 1120], ['2016', 1030, 540] ]); var options = { title: 'Company Performance', hAxis: {title: 'Year', titleTextStyle: {color: '#333'}}, vAxis: {minValue: 0} }; var chart = new google.visualization.AreaChart(document.getElementById('chart_div')); chart.draw(data, options); } </script> </head> <body> <div id="chart_div" style="width: 900px; height: 500px;"></div> </body> </html> サイトに乗っているサンプルコードですが、このコードでHTMLファイルを作るだけで、簡単にグラフが作れてしまいます。

改良ポイント

HEADタグ内にある、 <script type="text/javascript"> google.load("visualization", "1", {packages:["corechart"]}); google.setOnLoadCallback(drawChart); function drawChart() { var data = google.visualization.arrayToDataTable([ ['Year', 'Sales', 'Expenses'], ['2013', 1000, 400], ['2014', 1170, 460], ['2015', 660, 1120], ['2016', 1030, 540] ]); var options = { title: 'Company Performance', hAxis: {title: 'Year', titleTextStyle: {color: '#333'}}, vAxis: {minValue: 0} }; var chart = new google.visualization.AreaChart(document.getElementById('chart_div')); chart.draw(data, options); } </script> この部分をAjaxに変換して、レポート表示したいサーバーにリクエストを投げて、「google.visualization.arrayToDataTable」を実行している箇所のjsonフォーマットで返してもらうようにすることで、動的なグラフ作成ができるようになります。 ちなみに、このscriptタグは、headタグ内で行っていますが、bodyタグ内で実行しても、ちゃんとグラフが表示されることは確認済みです。

ページ内JSの改良

HTMLコードはシンプルにしたかったので、JSは全て外出しにしました。 <script type="text/javascript" src="https://www.google.com/jsapi"></script> <script type="text/javascript" src="prg/js/area_chart.js"></script> <div id="chart_div"></div> 1行目のスクリプトはgoogleサイトに有るライブラリの読み込み 2行目のスクリプトは新規に作成するJSファイル 3行目のdivは、グラフを表示するエリア(ページ内のどこに設置してもOKです) (function(){ var $$={}; $$.event = { add:function(t, m, f){ //other Browser if (t.addEventListener){ t.addEventListener(m, f, false); } //IE else{ if(m=='load'){ var d = document.body; if(typeof(d)!='undefined'){d = window;} if((typeof(onload)!='undefined' && typeof(d.onload)!='undefined' && onload == d.onload) || typeof(eval(onload))=='object'){ t.attachEvent('on' + m, function() { f.call(t , window.event); }); } else{ f.call(t, window.event); } } else{ t.attachEvent('on' + m, function() { f.call(t , window.event); }); } } } }; /** * Ajax */ $$.ajax = { xmlObj:function(f){ var r=null; try{ r=new XMLHttpRequest(); } catch(e){ try{ r=new ActiveXObject("Msxml2.XMLHTTP"); } catch(e){ try{ r=new ActiveXObject("Microsoft.XMLHTTP"); } catch(e){ return null; } } } return r; }, /** * XMLHttpRequestオブジェクト生成 */ set:function( option ){ if(!option){return} $$.ajax.httpoj = $$.ajax.createHttpRequest(); if(!$$.ajax.httpoj){return;} //open メソッド; $$.ajax.httpoj.open( option.method , option.url , option.async ); $$.ajax.httpoj.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); //受信時に起動するイベント; $$.ajax.httpoj.onreadystatechange = function(){ //readyState値は4で受信完了; if ($$.ajax.httpoj.readyState==4){ //コールバック option.onSuccess($$.ajax.httpoj.responseText); } }; //query整形 var data = []; if(typeof(option.query)!="undefined"){ for(var i in option.query){ data.push(i+"="+encodeURIComponent(option.query[i])); } } if(typeof(option.querys)!="undefined"){ for(var i=0;i<option .querys.length;i++){ data.push(option.querys[i][0]+"="+encodeURIComponent(option.querys[i][1])); } } //send メソッド if(data.length){//console.log(data.join("&")); $$.ajax.httpoj.send( data.join("&") ); } }, createHttpRequest:function(){ //Win ie用 if(window.ActiveXObject){ try { //MSXML2以降用; return new ActiveXObject("Msxml2.XMLHTTP") } catch(e){ try { //旧MSXML用; return new ActiveXObject("Microsoft.XMLHTTP") } catch(e2){ return null } } } //Win ie以外のXMLHttpRequestオブジェクト実装ブラウザ用; else if(window.XMLHttpRequest){ return new XMLHttpRequest() } else{ return null } }, //コールバック関数 ( 受信時に実行されます ); onSuccess:function(oj){ //レスポンスを取得; var res = oj.responseText;console.log(res); //ダイアログで表示; if(res && res.match(/^[a-z|$]/)){ eval(res); } } }; window.$$LIB = $$; return $$; })(); google.load("visualization", "1", {packages:["corechart"]}); google.setOnLoadCallback(drawChart); function drawChart() { $$LIB.ajax.set({ query:{ "php":"area_chart", "mode":"load_chart" }, method:"post", url:"index.php", async:true, onSuccess:function(res){ if(!res){return} var json = JSON.parse(res); var data = google.visualization.arrayToDataTable(json); var options = { title: 'Access Report', hAxis: {title: 'Day', titleTextStyle: {color: '#333'}}, vAxis: {minValue: 0} }; var chart = new google.visualization.AreaChart(document.getElementById('chart_div')); chart.draw(data, options); } }); } </pre> 前半、ajax用のライブラリを直書きしてます。気になる方は、ここを外出ししてもらっても問題ありません。 ajax内容は「index.php」に対していくつかクエリをつけてますが、ここは、サーバー側での仕様で変更してください。 <h3>PHP処理</h3> <pre class="lang:default decode:true " > &lt;?php new AREA_CHART(); class AREA_CHART{ function __construct(){ if($_REQUEST['mode']=="load_chart"){ $test = array(array("Day","PV","UU")); $datas = $this-&gt;getData(); for($i=0;$i&lt;count($datas);$i++){ $test[] = $datas[$i]; } echo json_encode($test); exit(); } } function getData(){ $lists = scanDir("data"); $datas= array(); for($i=0;$i&lt;count($lists);$i++){ if($lists[$i]=="." || $lists[$i]==".."){continue;} unset($data); exec("awk -F, '{print $4}' "."data/".$lists[$i]."|wc -l" , $data); $num1 = (int)trim($data[0]); //array_push($pvs,$num1); unset($data); exec("awk -F, '{print $4}' "."data/".$lists[$i]."|sort|uniq|wc -l" , $data); $num2 = (int)trim($data[0]); //array_push($uus,$num2); $date = str_replace(".log","",$lists[$i]); $datas[] = array($date,$num1,$num2); } return $datas; } } AREA_CHARTクラスをnew宣言するだけで、実行されるように「__construct」してますので、ここは適宜変更してください。 また、getData関数では、dataフォルダに入っている「YYYYMMDD(日付).log」というファイルをawk言語で値を取得して日別の値を作成してます。 フォーマットとしては、 配列の1番目が、グラフに表示するサブスクリプションになり、 ["グラフ下部の目盛り部分","グラフ値1","グラフ値2"]※以降はグラフ値を3,4,5...と増やしていけます。 配列の2番目以降に、対象の値を入れるとグラフに反映されます。

ハマったポイント

1. PHPの配列内のデータ部分は、数値型で作らないといけない。  ※型をあまり考えない言語同士なのですが、ここだけは厳密にしましょう。 2. PHPでのjson_encode、javascriptでのJSON.parse()というJSONの受け渡し方式 ※googleからのレスポンスで怒られることがあるので、上記型も合わせてデバッグ検証しながらやってください。

完成

無事に完成して、グラフも表示されました。 計測して使うものなので、簡単に見ることができないんですが、サンプルをGitHUBにアップしておきました。 https://github.com/yugeta/sitemate

Issue

まだ、簡易表示機能しかないんですが、今後使い続けると、日別のデータが膨大になり横が広くなっていくので、期間による絞込みを付けて、デフォルト表示は、直近1ヶ月という風にしたいんですね。 あと、GoogleAnalyticsに機能としてない、時間別計測機能は付けたいと思います。これは、1日の時間帯でのアクセス頻度を計測することで、wordpressなどの更新時間タイミングを調整できるという機能なので、ブロガーの人は必須ではないでしょうか?

過去記事

サイトの計測を手動で行ってみる PHP #1「ログを取得する」

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。