WordPressのプラグイン flamingo は、メールフォームプラグイン Contact Form 7 の送信データをデータベース上に保存するプラグインです。
このデータをグラフ化する案件があったので覚書です。とある装置の日々の測定データの報告をメールフォームで送ってもらい、それをグラフ化するといった感じです。
グラフ化には Highcharts.js を使いました。つまり、flamingo に保存されたデータから Highcharts.js でグラフ化する方法です。

Contact Form 7 でフォームを作る

flamingo にデータを保存するので、Contact Form 7 でフォームを作ります。今回は下記のような感じです。
<dl class="report"> <dt>担当者</dt> <dd>[select* your-name first_as_label "選択してください" "佐藤" "鈴木" "高橋" "田中"]</dd> <dt>装置1</dt> <dd class="implement-ck"><span>測定:</span>[radio measuring-1 use_label_element default:2 "実施" "未実施"]</dd> </dl> <div class="measuring-1 hide"> <dl class="report"> <dd class="measuring-time"><span>測定時刻:</span>[select hour-1 include_blank "00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23"]:[select min-1 include_blank "00" "10" "20" "30" "40" "50"]</dd> <dd class="measuring-value"><span>測定値:</span>[number value-1 min:3000 max:20000 placeholder "99999"]mg/L</dd> </dl> </div> <dl class="report"> <dt>装置2</dt> <dd class="implement-ck"><span>測定:</span>[radio measuring-2 use_label_element default:2 "実施" "未実施"]</dd> </dl> <div class="measuring-2 hide"> <dl class="report"> <dd class="measuring-time"><span>測定時刻:</span>[select hour-2 include_blank "00" "01" "02" "03" "04" "05" "06" "07" "08" "09" "10" "11" "12" "13" "14" "15" "16" "17" "18" "19" "20" "21" "22" "23"]:[select min-2 include_blank "00" "10" "20" "30" "40" "50"]</dd> <dd class="measuring-value"><span>測定値:</span>[number value-2 min:0 max:20 placeholder "6.5"]pH</dd> </dl> </div> <dl class="report"> <dd class="cleaning"><span>清掃:</span>[radio cleaning use_label_element default:2 "実施" "未実施"]</dd> </dl> <p class="submit">[submit class:fas " 送 信"]</p>
ラジオボタンで関連箇所の表示/非表示(本題と関係ありません)
ラジオボタンの選択が“未実施”の場合に入力不要なinput要素を含む要素を非表示にしましたが、本題とは関係ありません。
(function($){
$('.implement-ck input[type="radio"]').change(function(){
var c = $(this).attr("name");
$('div.' + c).removeClass('hide');
if($('.implement-ck input[name="' + c + '"]:checked').val() == "未実施"){
$('div.' + c).addClass('hide');
}
});
})(jQuery);
グラフを入れる要素と日付を遡るためのform
id=”test-graph”のdiv要素にグラフが表示されます。
日付を遡るためのformは、Contact Form 7 とは別のformです。
<!-- ↓グラフの日付を遡るためのフォーム↓ --> <form action="" method="POST"> <span class="offset">最新より<input type="number" name="offset" class="offset" min="0" max="366" aria-invalid="false" placeholder="0" />日前</span><span><input type="submit" name="submit" value="送 信" /></span> </form> <!-- ↓グラフを表示するコンテナ↓ --> <div id="test-graph" style="height: 400px; margin: 0 auto;"></div>
フォームの外観を整えるCSS
/*### Contact Form 7 のフォーム用 ###*/
dl.report dt,
dl.report dd {
margin-left: 0;
}
dl.report dd {
margin-bottom: .5em;
}
.measuring-time span:nth-of-type(1),
.measuring-value span:nth-of-type(1) {
width: 8em;
display: inline-block;
}
.cleaning > span:nth-of-type(1) {
width: 7em;
display: inline-block;
}
.measuring-time span:nth-of-type(2) {
margin-right: .5em;
}
.measuring-time span:nth-of-type(3) {
margin-left: .5em;
}
.measuring-time input {
width: 3.5em;
}
.measuring-time select {
width: 4.0em;
}
.measuring-value input {
width: 6em;
}
.measuring-1.hide,
.measuring-2.hide { /*ラジオボタンによる非表示スクリプト用*/
display: none;
}
/*### グラフ上部フォーム用 ###*/
.entry-content form {
margin-bottom: 40px;
}
.entry-content form span {
display: inline-block;
}
.entry-content form span.offset {
width: 13em;
margin-left: 1em;
margin-bottom: 10px;
}
.entry-content form input.offset {
width: 5em;
}
.entry-content form input[name="submit"] {
width: 5em;
}
テンプレートファイルにコード追加
今回は固定ページ用のテンプレートファイル page.php をコピーしてグラフ用のテンプレートファイル page-graph.php を作成し、その最上部(header要素より上)に下記のコードを追加しました。
flamingo のデータは post_type が flamingo_inbound のカスタムフィールドなので、get_post_meta() で取得可能です。それをJSONエンコードしてJavaScriptで使用できる形式に変換します。
// フォームから送信されたinputの値を$offsetに格納
if(isset($_POST["offset"])) {
$offset = $_POST["offset"];
} else {
$offset = 0;
}
//投稿データ作成のためのパラメータ
$args = array(
'post_type' => 'flamingo_inbound', // flamingoのデータはpost_typeがflamingo_inbound
'posts_per_page' => 10, // 10件取得
'orderby' => array(
'date' => 'DESC' // 最新から取得したいので降順
),
'offset' => $offset // 取得開始位置(日付を遡るため)
);
$flamingo_posts = get_posts( $args ); // 投稿データの配列作成
// 空の配列をそれぞれ作成
$report_date_arr = array();
$report_time_arr = array();
$your_name_arr = array();
$measuring_1_arr = array();
$measuring_2_arr = array();
$hour_1_arr = array();
$min_1_arr = array();
$hour_2_arr = array();
$min_2_arr = array();
$value_1_arr = array();
$value_2_arr = array();
$cleaning_arr = array();
// 配列を繰り返し処理
foreach( $flamingo_posts as $value ) { // 要素の値を$valueに代入
$post_id = $value->ID; // $valueからIDを取得
$flamingo_post = get_post( $post_id ); // IDから投稿レコードを取得
$report_date = $flamingo_post->post_date; // 投稿レコードから送信日時を取得
$report_time = mysql2date('H:i:s', $flamingo_post->post_date); // tooltip表示用書式(時:分:秒)
// IDからカスタムフィールドの値を取得
$your_name = get_post_meta( $post_id, '_field_your-name', true ); // 担当者取得
$measuring_1 = get_post_meta( $post_id, '_field_measuring-1', true); // 装置1測定実施/未実施取得
$measuring_2 = get_post_meta( $post_id, '_field_measuring-2', true); // 装置2測定実施/未実施取得
$hour_1 = get_post_meta( $post_id, '_field_hour-1', true ); // 装置1測定時刻(時)取得
$min_1 = get_post_meta( $post_id, '_field_min-1', true ); // 装置1測定時刻(分)取得
$hour_2 = get_post_meta( $post_id, '_field_hour-2', true ); // 装置2測定時刻(時)取得
$min_2 = get_post_meta( $post_id, '_field_min-2', true ); // 装置2測定時刻(分)取得
$value_1 = get_post_meta( $post_id, '_field_value-1', true ); // 装置1測定値取得
$value_2 = get_post_meta( $post_id, '_field_value-2', true ); // 装置2測定値取得
$cleaning = get_post_meta( $post_id, '_field_cleaning', true ); // 清掃実施/未実施
// 取得したカスタムフィールドの値を空の配列に入れていく
$report_date_arr[] = $report_date;
$report_time_arr[] = $report_time;
$your_name_arr[] = $your_name;
$measuring_1_arr[] = $measuring_1;
$measuring_2_arr[] = $measuring_2;
$hour_1_arr[] = $hour_1;
$min_1_arr[] = $min_1;
$hour_2_arr[] = $hour_2;
$min_2_arr[] = $min_2;
$value_1_arr[] = (int)$value_1;
$value_2_arr[] = (float)$value_2;
$cleaning_arr[] = $cleaning;
}
// グラフのX軸は右方向に最新となるので配列を逆順にする
$report_date_arr_r = array_reverse($report_date_arr);
$report_time_arr_r = array_reverse($report_time_arr);
$your_name_arr_r = array_reverse($your_name_arr);
$measuring_1_arr_r = array_reverse($measuring_1_arr);
$measuring_2_arr_r = array_reverse($measuring_2_arr);
$hour_1_arr_r = array_reverse($hour_1_arr);
$min_1_arr_r = array_reverse($min_1_arr);
$hour_2_arr_r = array_reverse($hour_2_arr);
$min_2_arr_r = array_reverse($min_2_arr);
$value_1_arr_r = array_reverse($value_1_arr);
$value_2_arr_r = array_reverse($value_2_arr);
$cleaning_arr_r = array_reverse($cleaning_arr);
// JavaScriptにデータを渡すためにJSONエンコード
$report_date_j = json_encode($report_date_arr_r);
$report_time_j = json_encode($report_time_arr_r);
$your_name_j = json_encode($your_name_arr_r);
$measuring_1_j = json_encode($measuring_1_arr_r);
$measuring_2_j = json_encode($measuring_2_arr_r);
$hour_1_j = json_encode($hour_1_arr_r);
$min_1_j = json_encode($min_1_arr_r);
$hour_2_j = json_encode($hour_2_arr_r);
$min_2_j = json_encode($min_2_arr_r);
$value_1_j = json_encode($value_1_arr_r);
$value_2_j = json_encode($value_2_arr_r);
$cleaning_j = json_encode($cleaning_arr_r);
Highcharts.js のグラフ設定
テンプレートファイル page-graph.php の body要素最下部(タグ直前)に記述します。highcharts.js と exporting.js を読み込んでその下にスクリプトを記述します。
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/modules/exporting.js"></script>
<script type="text/javascript">
$(document).ready(function () {
// PHPから値を受ける
let offset = '<?php echo $offset; ?>';
// JSON形式の文字列をJavaScriptのJSONオブジェクトに変換
let report_date_j = JSON.parse('<?php echo $report_date_j; ?>');
let report_time_j = JSON.parse('<?php echo $report_time_j; ?>');
let your_name_j = JSON.parse('<?php echo $your_name_j; ?>');
let measuring_1_j = JSON.parse('<?php echo $measuring_1_j; ?>');
let measuring_2_j = JSON.parse('<?php echo $measuring_2_j; ?>');
let hour_1_j = JSON.parse('<?php echo $hour_1_j; ?>');
let min_1_j = JSON.parse('<?php echo $min_1_j; ?>');
let hour_2_j = JSON.parse('<?php echo $hour_2_j; ?>');
let min_2_j = JSON.parse('<?php echo $min_2_j; ?>');
let value_1_j = JSON.parse('<?php echo $value_1_j; ?>');
let value_2_j = JSON.parse('<?php echo $value_2_j; ?>');
let cleaning_j = JSON.parse('<?php echo $cleaning_j; ?>');
// POST後にinputのvalueを残す
$('input.offset').val(offset);
// highcharts.jsの設定
chart = new Highcharts.Chart({
chart: { // グラフの設定
renderTo: 'test-graph', // グラフを表示する要素のid
defaultSeriesType: 'line', // データ系列の既定タイプ
marginRight: 140, // 右マージン
marginBottom: 70 // 下マージン
},
title: {
text: 'テストグラフ' // グラフのタイトル
},
subtitle: {
},
xAxis: { // X軸
categories: report_date_j, // X軸の項目(送信日時)
labels: {
formatter: function(){
return this.value.toString().substring(0,10); // グラフX軸表示用書式(最初の文字から10文字分の日付のみ)
}
}
},
yAxis: [{ // 1番目のY軸(既定の左)
title: {
text: '(mg/L)' // 1番目のY軸のタイトル
}
}, { // 2番目のY軸
title: {
text: '(pH)' // 2番目のY軸のタイトル
},
opposite: true // 右側に設定
}],
plotOptions: { // データ系列のオプション
line: { // 線分タイプの設定
dataLabels: {
enabled: true,
formatter: function() { // 値により色を変える
if (this.y > 8.0 || (this.y < 6.0 && this.y > 0)){ // 0を非表示
var color = '<span style="color:#c00">' + this.y + '</span>';
} else if (this.y <= 8.0 && this.y >= 6.0){
var color = '<span style="color:#00c">' + this.y + '</span>';
}
return color;
}
},
},
area: { // エリアタイプの設定
fillOpacity: 0.2,
marker: {
enabled: false
},
lineWidth: 0,
dataLabels: {
enabled: true,
formatter: function() { // 値により色を変える
if (this.y > 6000 ){
var color = '<span style="color:#c00">' + this.y + '</span>';
} else if (this.y <= 6000 && this.y > 0){ // 0を非表示
var color = '<span style="color:#00c">' + this.y + '</span>';
}
return color;
}
},
},
},
tooltip: {
formatter: function(){
var index = report_date_j.indexOf(this.x); // 送信日時からX軸の項目を検索してその位置を返す
var man = your_name_j[index]; // index位置の担当者
var clean = cleaning_j[index]; // index位置の清掃実施/未実施
var report_time = report_time_j[index]; // index位置の送信時刻
if(this.series.name == '装置1'){ //装置1のデータ系列において
var hour = hour_1_j[index]; // index位置の測定時刻(時)
var min = min_1_j[index]; // index位置の測定時刻(分)
var implement = measuring_1_j[index]; // index位置の測定実施/未実施
} else if(this.series.name == '装置2'){ //装置2のデータ系列において
var hour = hour_2_j[index]; // index位置の測定時刻(時)
var min = min_2_j[index]; // index位置の測定時刻(分)
var implement = measuring_2_j[index]; // index位置の測定実施/未実施
}
if(this.series.name == '装置1' && implement == '実施'){ // 装置1が測定実施の場合
var meas = '<br />' + this.y + 'mg/L<br />' + hour + ':' + min + '測定<br />';
} else if(this.series.name == '装置2' && implement == '実施'){ // 装置2が測定実施の場合
var meas = '<br />pH' + this.y + '<br />' + hour + ':' + min + '測定<br />';
} else { // 装置1装置2ともに未実施の場合
var meas = '<br />';
}
var word = this.series.name + '<br />測定' + implement + meas + '清掃' + clean + '<br />' + '担当:' + man + 'さん' + '<br />' + report_time + '送信'; // tooltip表示内容
return word; // 値を返す
}
},
legend: { // 凡例の設定
layout: 'vertical', // 各凡例を垂直方向に配置
align: 'right', // 右に配置
verticalAlign: 'middle' // 垂直方向中央配置
},
series: [{ // データ系列1の設定
name: '装置1', // 名前
type: 'area', // エリアタイプ
data: value_1_j // データ系列
}, {
name: '装置2', // 名前
yAxis: 1, // 2番目のY軸を使う
data: value_2_j // データ系列
}]
});
});
</script>
以上、ご参考になれば幸いです。
ありがとうございます。



コメント