前回はカテゴリーやクレジットカードの種類やスマホ決済の種類の割合を月別で円グラフにする実装を行いました。
今回は前回実装した円グラフの横に表示している、表からそのアイテムの月別金額推移グラフのページに遷移する実装を行います。
月別金額推移グラフ
・円グラフ横表の項目<td>にリンクを追加(不明以外)
・検索フォーム実装
・棒グラフを表示
・グラフ下に詳細データを表示
以上の4ステップで進めていきます。
円グラフ横表の項目<td>にリンクを追加(不明以外)
まずは前回実装した円グラフ横の表から、月別金額推移グラフのページに飛ばすためのリンクを追加します。
ただこのリンクは「不明」となっている行には出力しないようにします。
<!--既存の表タイトル行 全4項目共通-->
<tr>
<th>項目名</th>
<th>金額</th>
</tr>
<!--既存のtdタグ 全4項目共通-->
<td><?php echo $item_list[$i]; ?></td>
<td><?php echo '¥' . number_format($amount_sum[$i]); ?></td>
<!--表タイトル行 全4項目共通-->
<tr class="head">
<th>項目名</th>
<th>金額</th>
</tr>
<!--不明以外tdリンク追加 全4項目共通-->
<?php if ($item_list[$i] !== '不明') : ?>
<td>
<a href="">
<?php echo $item_list[$i]; ?>
</a>
</td>
<?php else : ?>
<td class="unknown">
<?php echo $item_list[$i]; ?>
</td>
<?php endif; ?>
<?php if ($item_list[$i] !== '不明') : ?>
<td>
<a href="">
<?php echo '¥' . number_format($amount_sum[$i]); ?>
</a>
</td>
<?php else : ?>
<td class="unknown">
<?php echo '¥' . number_format($amount_sum[$i]); ?>
</td>
<?php endif; ?>
上記の修正を、「支出カテゴリー」「収入カテゴリー」「クレジットカード」「スマホ決済」の4箇所に行います。
修正後の画面は特に大きく変わりません。円グラフ横の表の項目名や金額にカーソルを近づけると、カーソルがポインターに変わりクリックできるようになります。
このクリックできる範囲を広く、そしてクリックできることがわかりやすく表示するようにレイアウトを調整します。
&--graph {
width: 45%;
border-collapse: collapse;
@include m.mq(tab) {
width: 100%;
}
th,
td {
font-size: 1.8rem;
line-height: 2;
border-bottom: solid 0.2rem #ddd;
&:first-of-type {
padding-left: 1rem;
}
}
//↓ここから追記
tr:not(.head) {
position: relative;
&::after {
content: "\f105";
position: absolute;
top: 50%;
right: 2rem;
transform: translateY(-50%);
color: #ccc;
font-size: 1.4rem;
font-weight: bold;
transition: all 0.3s;
}
&:hover {
&::after {
right: 1rem;
}
td:not(.unknown) {
background-color: #def;
}
}
a {
display: block;
}
}
//↑ここまで
}
続いてhref属性を設定します。
月別金額推移グラフのページに飛ばすのに加えて、表示されている円グラフの「年」と遷移しようとしている項目の「id」「テーブル名」が必要になります。
この3点の情報はパラメータにして遷移先のページに渡します。
href='./item-report.php?year=[年]&item=[項目id]&num=[テーブル番号]'
上記の形で渡します。テーブル情報はそのまま文字列を渡すのではなく、一度数値で渡してから遷移先のページでテーブル文字列に変換する処理にします。
現在のプログラムでは「年」を入れている変数とテーブル番号の用意はありますが、項目のid情報を抽出していないので、項目idを抽出するプログラムを追加します。
//支出カテゴリーの場合
$amount_sum = array();
$item_id = array(); //追加(共通)
$item_list = array();
//SELECT文でspending_category.idを追加(その他項目はテーブル名に合わせて修正)
$sql = 'SELECT SUM(records.amount) as sum, spending_category.id, spending_category.name
FROM records
LEFT JOIN spending_category ON records.spending_category = spending_category.id
WHERE records.type=0 AND records.user_id=? AND records.date LIKE ?
GROUP BY records.spending_category
ORDER BY sum DESC';
:
省略
:
$stmt->bind_result($amount, &id, $item); //$idを追加(共通)
while ($stmt->fetch()) :
$amount_sum[] = $amount;
if (is_null($item)) :
$item_list[] = '不明';
$item_id[] = ''; //追加(共通)
else :
$item_list[] = $item;
$item_id[] = $id; //追加
endif;
endwhile;
SQLで項目名だけでなく、id値も抽出し配列に入れるプログラムに修正しました。
以上でパラメータの値が揃ったので、href属性にリンク先を設定します。
<a href="./item-report.php?year=<?php echo mb_substr($graph_month, 0, 4); ?>&item=<?php echo $item_id[$i]; ?>&num=0">
yearパラメータの値は、mb_substr($graph_month, 0, 4)と、mb_substr関数で「YYYY-mm」の形式になっている$graph_monthの値の頭4文字分「YYYY」を取り出して出力しています。
itemパラメータは先程追加した項目のidを抽出し配列に入れたなかから、[$i]番目の値を取り出し出力しています。
numパラメータは、「支出カテゴリー→0」「収入カテゴリー→1」「クレジットカード→2」「スマホ決済→3」を入れます。
それぞれのhref属性に適当なリンク先を設定できたら完了です。
検索フォーム実装
ここからは月別金額推移グラフのページの実装に入ります。
まずは新しく「item-report.php」ファイルを追記し以下を記述します。
<?php
include_once('./session.php');
require_once('./dbconnect.php');
include_once('./functions.php');
$page_title = '選択項目月別推移レポート';
include_once('./header.php');
?>
<main class="l-main">
<section class="p-section p-section__bar-graph">
<form class="p-form--bar-graph u-flex-box" action="" method="POST" name="graphSearch">
<input type="hidden" id="itemTable" name="item_table" value="">
<select name="year">
<?php for ($i = 2020; $i <= date('Y'); $i++) : ?>
<option value="<?php echo $i; ?>" <?php echo $year == $i ? 'selected' : ''; ?>><?php echo $i; ?>年</option>
<?php endfor; ?>
</select>
<select name="item" onchange="">
<optgroup id="defaultGroup" label="支出カテゴリー">
<?php
$stmt = $db->prepare('SELECT id, name FROM spending_category WHERE user_id=?');
$stmt->bind_param('i', $user_id);
$stmt->execute();
$stmt->bind_result($id, $name);
while ($stmt->fetch()) : ?>
<option value="<?php echo $id; ?>" <?php echo ($item_table === 'spending_category' && $item == $id) ? 'selected' : ''; ?>><?php echo $name; ?></option>
<?php endwhile; ?>
</optgroup>
<optgroup label="収入カテゴリー">
<?php
$stmt = $db->prepare('SELECT id, name FROM income_category WHERE user_id=?');
$stmt->bind_param('i', $user_id);
$stmt->execute();
$stmt->bind_result($id, $name);
while ($stmt->fetch()) : ?>
<option value="<?php echo $id; ?>" <?php echo ($item_table === 'income_category' && $item == $id) ? 'selected' : ''; ?>><?php echo $name; ?></option>
<?php endwhile; ?>
</optgroup>
<optgroup label="クレジットカード">
<?php
$stmt = $db->prepare('SELECT id, name FROM creditcard WHERE user_id=?');
$stmt->bind_param('i', $user_id);
$stmt->execute();
$stmt->bind_result($id, $name);
while ($stmt->fetch()) : ?>
<option value="<?php echo $id; ?>" <?php echo ($item_table === 'creditcard' && $item == $id) ? 'selected' : ''; ?>><?php echo $name; ?></option>
<?php endwhile; ?>
</optgroup>
<optgroup label="スマホ決済">
<?php
$stmt = $db->prepare('SELECT id, name FROM qr WHERE user_id=?');
$stmt->bind_param('i', $user_id);
$stmt->execute();
$stmt->bind_result($id, $name);
while ($stmt->fetch()) : ?>
<option value="<?php echo $id; ?>" <?php echo ($item_table === 'qr' && $item == $id) ? 'selected' : ''; ?>><?php echo $name; ?></option>
<?php endwhile; ?>
</optgroup>
</select>
<input type="submit" class="c-button c-button--bg-blue" value="検索" onclick="">
</form>
</section>
<section class="p-section p-section__back-home">
<a href="./index.php" class="c-button c-button--bg-gray">ホームに戻る</a>
</section>
</main>
<footer id="footer" class="l-footer">
<p>家計簿アプリ|2022</p>
</footer>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="./js/import.js"></script>
<script src="./js/functions.js"></script>
</body>
</html>
以上を記述すると以下のようになります。
select内の値はすでにSQLで抽出したものを出力しています。
続いて検索ボタンが押下されPOST送信がされた場合や、パラメータで伝わってきた場合は値を処理し、selectの値に反映します。
以下を共通ファイル読み込みプログラムの下に追記します。
if (isset($_POST['year']) && isset($_POST['item']) && isset($_POST['item_table'])) :
//検索ボタンが押下されたとき
$item_table = filter_input(INPUT_POST, 'item_table', FILTER_SANITIZE_SPECIAL_CHARS);
$year = filter_input(INPUT_POST, 'year', FILTER_SANITIZE_NUMBER_INT);
$item = filter_input(INPUT_POST, 'item', FILTER_SANITIZE_NUMBER_INT);
elseif (isset($_GET['year']) && isset($_GET['item']) && $_GET['item'] !== '' && isset($_GET['num']) && $_GET['num'] < 4) :
//円グラフ横の表から遷移されたとき
$table_list = ['spending_category', 'income_category', 'creditcard', 'qr'];
$num = $_GET['num'];
$item_table = $table_list[$num];
$year = $_GET['year'];
$item = $_GET['item'];
else :
//どちらにも当てはまらない場合はエラー付きパラメータを付けて返す
header('Location: ./index.php?dataOperation=error');
exit();
endif;
echo $item_table . '<br>' . $year . '<br>' . $item;
echoを入れたのでパラメータ遷移の際は、画面左上に値が出力されています。
しかし検索を押すと、テーブル情報が渡ってきません。これはまだ検索フォームに設定しているテーブル情報を入れるinputに値を設定する処理をつけていないためです。
それではテーブル情報を設定する処理を追加します。
<!--value値を設定-->
<input type="hidden" id="itemTable" name="item_table" value="<?php echo isset($item_table) ? $item_table : 'spending_category'; ?>">
変数がある場合にはその値を出力し、ない場合は「spending_category」を出力するようにしています。
そして、selectが変更されたときにテーブル情報をセットしている上記inputのvalueを変更する必要があります。
この処理をJavaScriptで関数を作成し、onchange属性にセットする方法で実装します。
まずはJavaScriptで関数を作成します。以下をファイル下部に記述しているJSファイル読み込みプログラムの下に追記します。
<script>
const itemTable = document.getElementById('itemTable'); //テーブル情報格納 hidden input要素を取得
const selectForm = document.graphSearch.item; //項目select要素取得
const tableList = { //key:テーブル名、値:optgroupのlabelの連想配列
'spending_category': '支出カテゴリー',
'income_category': '収入カテゴリー',
'creditcard': 'クレジットカード',
'qr': 'スマホ決済'
};
//selectボックスで項目が変更されたときのイベント
const onChangeItem = () => {
//選択されたoptionが何番目の要素か
const num = document.graphSearch.item.selectedIndex;
//選択されたoptionの親要素optgroupのラベル取得
const optGroupLabel = selectForm.options[num].parentNode.label;
//取得したoptgroupラベルと一致する連想配列の値を検索し、そのkey名を返す
const key = Object.keys(tableList).find((key) => tableList[key] === optGroupLabel);
//テーブル名を入れるinputのvalueを書き換え
itemTable.value = key;
console.log(num);
console.log(optGroupLabel);
console.log(key);
}
</script>
実際に書き換わっているかはデベロッパーツールで確認できます。
※上記動画はコンソール画面で各変数の値を出力しています。
そして作成した関数をselect要素に設定します。
<select name="item" onchange="onChangeItem();">
以上で検索フォームの実装は完了しました。
最後に
今回は月別金額推移グラフのページ実装に向けて、検索フォームを実装するまで行いました。
次回は続きの実装を行い、月別金額推移グラフのページを完成させます。
最後までお読みいただきありがとうございました。
コメント