前回、ビーコン方式でログを取得して、テーブルレポートを表示したが、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 " >
<?php
new AREA_CHART();
class AREA_CHART{
function __construct(){
if($_REQUEST['mode']=="load_chart"){
$test = array(array("Day","PV","UU"));
$datas = $this->getData();
for($i=0;$i<count($datas);$i++){
$test[] = $datas[$i];
}
echo json_encode($test);
exit();
}
}
function getData(){
$lists = scanDir("data");
$datas= array();
for($i=0;$i<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「ログを取得する」
0 件のコメント:
コメントを投稿